Giter Site home page Giter Site logo

jonschlinkert / parse-comments Goto Github PK

View Code? Open in Web Editor NEW
67.0 5.0 23.0 614 KB

Parse JavaScript code comments. Works with block and line comments, and should work with CSS, LESS, SASS, or any language with the same comment formats.

Home Page: https://github.com/jonschlinkert

License: MIT License

JavaScript 100.00%
parse comments javascript nodejs esprima catharsis babel espree doctrine code

parse-comments's Introduction

parse-comments NPM version NPM monthly downloads NPM total downloads Linux Build Status

Parse code comments from JavaScript or any language that uses the same format.

Please consider following this project's author, Jon Schlinkert, and consider starring the project to show your ❤️ and support.

Install

Install with npm:

$ npm install --save parse-comments

Usage

const Comments = require('parse-comments');
const comments = new Comments();
const ast = comments.parse(str);
console.log(ast);

Parses a comment like this:

/**
 * Create an instance of `CustomClass` with the given `options`.
 *
 * @param {String} options
 * @api public
 */

class CustomClass {
  constructor(options) {
    this.options = options;
  }
  set(type, fn) {
    // do stuff
  }
}

Into an array of comment objects, like this:

[
  {
    type: 'BlockComment',
    value: '\nCreate an instance of `CustomClass` with the given `options`.\n\n@param {String} options\n@api public',
    range: [0, 117],
    loc: { start: { line: 1, column: 0 }, end: { line: 6, column: 3 } },
    codeStart: 119,
    raw:
      '*\n * Create an instance of `CustomClass` with the given `options`.\n *\n * @param {String} options\n * @api public\n ',
    code: {
      context: {
        type: 'class',
        ctor: 'CustomClass',
        name: 'CustomClass',
        extends: undefined,
        string: 'new CustomClass()'
      },
      value: 'class CustomClass {',
      range: [119, 138],
      loc: { start: { line: 8, column: 0 }, end: { line: 8, column: 19 } }
    },
    description: 'Create an instance of `CustomClass` with the given `options`.',
    footer: '',
    examples: [],
    tags: [
      {
        title: 'param',
        name: 'options',
        description: '',
        type: { type: 'NameExpression', name: 'String' }
      },
      { title: 'api', name: 'public', description: '' }
    ],
    inlineTags: []
  }
]

API

Create an instance of Comments with the given options.

Params

  • {Object}: options

Example

const Comments = require('parse-comments');
const comments = new Comments();

Register a parser function of the given type

Params

  • type {string|object}
  • fn {Function}
  • returns {Object}

Params

  • fn {Function}: plugin function
  • returns {Object}: Returns the comments instance for chaining.

Example

// plugin example
function yourPlugin(options) {
  return function(comments) {
    // do stuff
  };
}
// usage
comments.use(yourPlugin());

Params

  • type {String}: The node.type to call the handler on. You can override built-in middleware by registering a handler of the same name, or register a handler for rendering a new type.
  • fn {Function}: The handler function
  • returns {Object}: Returns the instance for chaining.

Example

comments.set('param', function(node) {
  // do stuff to node
});

Params

  • type {String|Object|Array}: Handler name(s), or an object of middleware
  • fn {Function}: Handler function, if type is a string or array. Otherwise this argument is ignored.
  • returns {Object}: Returns the instance for chaining.

Example

comments.before('param', function(node) {
  // do stuff to node
});

// or
comments.before(['param', 'returns'], function(node) {
  // do stuff to node
});

// or
comments.before({
  param: function(node) {
    // do stuff to node
  },
  returns: function(node) {
    // do stuff to node
  }
});

Params

  • type {String|Object|Array}: Handler name(s), or an object of middleware
  • fn {Function}: Handler function, if type is a string or array. Otherwise this argument is ignored.
  • returns {Object}: Returns the instance for chaining.

Example

comments.after('param', function(node) {
  // do stuff to node
});

// or
comments.after(['param', 'returns'], function(node) {
  // do stuff to node
});

// or
comments.after({
  param: function(node) {
    // do stuff to node
  },
  returns: function(node) {
    // do stuff to node
  }
});

Params

  • javascript {String}: String of javascript
  • options {Object}
  • returns {Object}: Returns an object with description string, array of examples, array of tags (strings), and a footer if descriptions are defined both before and after tags.

Example

const parser = new ParseComments();
const tokens = parser.tokenize([string]);

Params

  • str {String}: String of javascript
  • options {Object}
  • returns {Array}: Array of objects.

Example

const parser = new ParseComments();
const comments = parser.parse(string);

Params

  • str {String}: JavaScript comment
  • options {Object}
  • returns {Object}: Parsed comment object

Example

let parser = new ParseComments();
let comments = parser.parseComment(string);
**Params**

* **{}**: {String}    
* **{String}**: name    
* **{String}**: name The name to use for foo ```    
* **{Object}**: tok Takes a token from    
* `returns` **{Object}**  

```js

**Params**

* **{}**: {String}
* **{String}**: name
* **{String}**: name The name to use for foo ```
* **{Object}**: tok
* `returns` **{Object}**

```js

**Params**

* **{}**: {String}    
* **{}**: {...string}    
* **{}**: {function(...a)}    
* **{}**: {function(...a:b)}    
* **{}**: {String|Array}    
* **{}**: {(String|Array)}    
* **{}**: {{foo: bar}}    
* **{}**: {String[]}    
* ``` **{Array<String|Function|Array>=}**    
* **{String}**: value The    
* `returns` **{Object}**  

```js

**Params**

* **{}**: {String}
* **{}**: {String|Array}
* **{}**: {(String|Array)}
* **{}**: {{foo: bar}} ```
* **{string}**: str The string to parse
* `returns` **{object}**

Returns true if the given `comment` is valid. By default, comments
are considered valid when they begin with `/**`, and do not contain
`jslint`, `jshint`, `eshint`, or `eslint`. A custom `isValid` function may be
passed on the constructor options.

**Params**

* `comment` **{Object}**
* `options` **{Object}**
* `returns` **{Boolean}**

## About

<details>
<summary><strong>Contributing</strong></summary>

Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).

Please read the [contributing guide](.github/contributing.md) for advice on opening issues, pull requests, and coding standards.

</details>

<details>
<summary><strong>Running Tests</strong></summary>

Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:

```sh
$ npm install && npm test
Building docs

(This project's readme.md is generated by verb, please don't edit the readme directly. Any changes to the readme must be made in the .verb.md readme template.)

To generate the readme, run the following command:

$ npm install -g verbose/verb#dev verb-generate-readme && verb

Contributors

Commits Contributor
35 jonschlinkert
4 doowb

Author

Jon Schlinkert

License

Copyright © 2018, Jon Schlinkert. Released under the MIT License.


This file was generated by verb-generate-readme, v0.8.0, on November 24, 2018.

parse-comments's People

Contributors

doowb avatar jonschlinkert avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

parse-comments's Issues

should detect `@example`, `@public` and `@private`

Currently it won't work if you just give @public, instead of @api public.
Same applies for examples which works if it find **Example** in codeblock, but not works if find @example

this works as expected

/**
 * Will try to promisify `fn` with native Promise,
 * otherwise will use `Bluebird` or you can give
 * different promise module as `Prome`, for example `q` or `promise` or `pinkie`.
 *
 * **Example**
 *
 * ```js
 * const fs = require('fs')
 * const request = require('request')
 * const redolent = require('redolent')
 *
 * redolent(fs.readFile)('package.json', 'utf-8').then(data => {
 *   console.log(JSON.parse(data).name)
 * })
 *
 * // handles multiple arguments by default
 * redolent(request)('http://www.tunnckocore.tk/').then(result => {
 *   const [httpResponse, body] = result
 * })
 * ```
 *
 * @name   redolent
 * @param  {Function} `<fn>` callback-style function to promisify
 * @param  {Function} `[Prome]` custom Promise module to use, e.g. `Q`
 * @return {Function} promisified function
 * @api public
 */
module.exports = function redolent (fn, Prome) {
  if (typeof fn !== 'function') {
    throw new TypeError('redolent expect a function')
  }

I'm not sure if the issue is exactly for here, I can't remember but I think this module is behind verb-ish things and behind my apidocs-cli which use helper-apidocs.

Another ugly thing is that it adds one line from where codeblock ends, means that tools on top of this module will show and create link to line where is the if statement and not where the module.exports is which requires you to add empty line above the module.exports which in some cases aren't good. For example, recently I've just tried https://inch-ci.org/, which seems to read jsdoc comments to create "documentation analytics". So it assumes that the code comment starts right before the function or in case module.exports. It also assumes using @example.

respect `@throw(s)` tags

I know it's too old and it need some bumps soon, but just to point it. :)

I believe I will come to @docksjs soon (in week or two), which would be great for such things using plugins. :)

for example that's the code for get source code of a comment - test.js#L63-L74, and above that is the doctrine plugin.

suggestion for `@option` and `@property` and indenting

consider following example

/**
 * > Strip all code comments, but not these that are
 * marked as "ignored" like (`//!` and `/*!`).
 * Pass `opts.preserve: false` to remove even them.
 *
 * **Example**
 *
 * ```js
 * const fs = require('fs')
 * const strip = require('acorn-strip-comments')
 *
 * const str = fs.readFileSync('./index.js', 'utf8')
 * const output = strip(str, {})
 * // => modified and cleaned string
 * ```
 *
 * @name  acornStripComments
 * @param  {String} `<input>` string from which to get comments
 * @param  {Object} `opts` optional options, passed to `acorn-extract-comments` and `acorn`
 * @param {Boolean} `opts.ast` if `true` the ast is added to the resulting array
 * @param {Boolean} `opts.line` if `false` get only block comments, default `true`
 * @param {Boolean} `opts.block` if `false` get line comments, default `true`
 * @param {Function} `opts.ignore` check function, default check comment starts with `!`
 * @param {Boolean} `opts.preserve` if `true` keep comments that are ignored (that pass the `opts.ignore` check)
 * @param {Boolean} `opts.locations` if `true` result will include `acorn/esprima` format comment location object
 * @param {Number} `opts.ecmaVersion` defaults to `6`, acorn parsing version
 * @return {String} modified string
 * @api public
 */
exports = module.exports = function stripAllComments (input, opts) {
  opts = extend({line: true, block: true, preserve: true}, opts)
  return acornStripComments(input, opts)
}

I think this should work as do it currently by using @option or @property, which btw both of them do some strange things with identation.

For example, doing it currently and correctly like that

/**
 * > Strip all code comments, but not these that are
 * marked as "ignored" like (`//!` and `/*!`).
 * Pass `opts.preserve: false` to remove even them.
 *
 * **Example**
 *
 * ```js
 * const fs = require('fs')
 * const strip = require('acorn-strip-comments')
 *
 * const str = fs.readFileSync('./index.js', 'utf8')
 * const output = strip(str, {})
 * // => modified and cleaned string
 * ```
 *
 * @name  acornStripComments
 * @param  {String} `<input>` string from which to get comments
 * @param  {Object} `opts` optional options, passed to `acorn-extract-comments` and `acorn`
 *   @option {Boolean} [opts] `ast` if `true` the ast is added to the resulting array
 *   @option {Boolean} [opts] `line` if `false` get only block comments, default `true`
 *   @option {Boolean} [opts] `block` if `false` get line comments, default `true`
 *   @option {Function} [opts] `ignore` check function, default check comment starts with `!`
 *   @option {Boolean} [opts] `preserve` if `true` keep comments that are ignored (that pass the `opts.ignore` check)
 *   @option {Boolean} [opts] `locations` if `true` result will include `acorn/esprima` format comment location object
 *   @option {Number} [opts] `ecmaVersion` defaults to `6`, acorn parsing version
 * @return {String} modified string
 * @api public
 */
exports = module.exports = function stripAllComments (input, opts) {
  opts = extend({line: true, block: true, preserve: true}, opts)
  return acornStripComments(input, opts)
}

adds options as sublist but with huge indent and adds one line more above the returns which is with same indent as options sublist

### [acornStripComments](index.js#L43)
> Strip all code comments, but not these that are marked as "ignored" like (`//!` and `/*!`). Pass `opts.preserve: false` to remove even them.

**Params**

* `<input>` **{String}**: string from which to get comments    
* `opts` **{Object}**: optional options, passed to `acorn-extract-comments` and `acorn`  
        - `ast` **{Boolean}**: if `true` the ast is added to the resulting array
        - `line` **{Boolean}**: if `false` get only block comments, default `true`
        - `block` **{Boolean}**: if `false` get line comments, default `true`
        - `ignore` **{Function}**: check function, default check comment starts with `!`
        - `preserve` **{Boolean}**: if `true` keep comments that are ignored (that pass the `opts.ignore` check)
        - `locations` **{Boolean}**: if `true` result will include `acorn/esprima` format comment location object
        - `ecmaVersion` **{Number}**: defaults to `6`, acorn parsing version

* `returns` **{String}**: modified string  

Suggest to enable use other comment strings except `/*`

Hello, this project is really helpful for me.
I suppose that it could be better to support any custom comment strings instead of fixed string /* because parse-comments aims to support any languages, I believe.

I'm working on source code based API doc generation. My project uses an in-house language which uses (* for comment blocks. I forked this and modified to handle it. It worked for me, but the reason why I didn't do PR is I ignored an original option allowSingleStar.

I'd appreciate if you officially support it.

tag.type problems

First, it would be cool if in the tag object there is also the whole non-parsed string of the types.

Second, the example case

/**
 * @param {Array<string>|string} options.include - glob patterns
 * @param {string|boolean} options.exclude - ignore patterns
 * @param {Function} options.hook - a hook function passed with [Context](#context)
 * @param {boolean} options.always - a boolean that makes `options.hook` to always be called
 * @param {Function} options.glob - a globbing library like [glob][], [fast-glob][], [tiny-glob][], defaults to `fast-glob`
 * @param {object} options.globOptions
 * @param {string[]} options.cacheLocation
 */

I always felt there's something wrong. Finally dug down and found it.

{ type: 'NameExpression', name: 'string' }
{
  type: 'UnionType',
  elements: [
    { type: 'NameExpression', name: 'string' },
    { type: 'NameExpression', name: 'boolean' }
  ]
}
{ type: 'NameExpression', name: 'Function' }
{ type: 'NameExpression', name: 'boolean' }
{ type: 'NameExpression', name: 'Function' }
{ type: 'NameExpression', name: 'object' }
{
  type: 'TypeApplication',
  expression: { type: 'NameExpression', name: 'Array' },
  applications: [ { type: 'NameExpression', name: 'string' } ]
}
{ type: 'NameExpression', name: 'Promise' }

as you can see, the first one is just NameExpression, which means it only gets the last of the type definition. If you reverse it from {Array<string>|string} to {string|Array<string>} the first result will be TypeApplication.

{
  type: 'TypeApplication',
  expression: { type: 'NameExpression', name: 'Array' },
  applications: [ { type: 'NameExpression', name: 'string' } ]
}

In short, the problem only when there is a TypeApplication type in a UnionType, because this works {string|boolean} okay.

I believe that the expected result should be

{
  type: 'UnionType',
  elements: [
    { type: 'NameExpression', name: 'string' },
    {
      type: 'TypeApplication',
      expression: { type: 'NameExpression', name: 'Array' },
      applications: [ { type: 'NameExpression', name: 'string' } ]
    }
  ]
}

@jonschlinkert seems like I continue to stack up more and more issues 😆 🙉 ❤️

`@option` gets ignored

The result markdown doesn't seem to mention the included @option:

'use strict'

var _ = require('lodash')
var clone = require('udc')
var xtend = require('xtend')

/**
 * Gives birth to instances
 *
 * ```js
 * var History = require('object-history')
 * var initial = {foo: 'bar', name: 'victoria'}
 * var history = new History(initial)
 * ```
 *
 * @param {Object} `initial` The initial history point
 * @param {Object} `options`
 *   @option `limit` [options] Optional. Remember this many backward points
 * @constructor
 * @api public
 */

var History = function (initial, options) {
  var self = this
  self.options = xtend({
    limit: null
  }, options)

  self.notObjError = new Error('requires a plain object')
  if (!initial || !_.isPlainObject(initial)) {
    throw self.notObjError
  }

  self.current = clone(initial)
  self.changesets = {
    backward: [],
    forward: []
  }
}

History.prototype.add = require('./prototype/add')
History.prototype.get = require('./prototype/get')
History.prototype.lengthBackward = require('./prototype/length-backward')
History.prototype.lengthForward = require('./prototype/length-forward')
History.prototype.backward = require('./prototype/backward')
History.prototype.forward = require('./prototype/forward')
History.prototype.move = require('./prototype/move')
History.prototype.forgetAllInDirection = require('./prototype/forget-all-in-direction')
History.prototype.forgetAllBackward = require('./prototype/forget-all-backward')
History.prototype.forgetAllForward = require('./prototype/forget-all-forward')

module.exports = History

Get error when install

Overview

lodash version in dependencies is out of date.
Should raise the version.

Details

$ npm i
audited 2974 packages in 3.724s
found 1 low severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details

See also :
image

Class misidentified as a method

This class gets wrongly misidentified as a method in o.context.type, thus ending up with a prefix . in the heading.

'use strict'

var _ = require('lodash')
var clone = require('udc')
var xtend = require('xtend')

/**
 * Gives birth to instances
 *
 * ```js
 * var History = require('object-history')
 * var initial = {foo: 'bar', name: 'victoria'}
 * var history = new History(initial)
 * ```
 *
 * @class History
 * @param {Object} `initial` The initial history point
 * @param {Object} `options` `limit`: `{Number}` Remember this many backward points
 * @constructor
 * @api public
 */

module.exports = function (initial, options) {
  var self = this
  self.options = xtend({
    limit: null
  }, options)

  self.notObjError = new Error('requires a plain object')
  if (!initial || !_.isPlainObject(initial)) {
    throw self.notObjError
  }

  self.current = clone(initial)
  self.changesets = {
    backward: [],
    forward: []
  }
}

var proto = module.exports.prototype

proto.add = require('./prototype/add')
proto.get = require('./prototype/get')
proto.lengthBackward = require('./prototype/length-backward')
proto.lengthForward = require('./prototype/length-forward')
proto.backward = require('./prototype/backward')
proto.forward = require('./prototype/forward')
proto.move = require('./prototype/move')
proto.forgetAllInDirection = require('./prototype/forget-all-in-direction')
proto.forgetAllBackward = require('./prototype/forget-all-backward')
proto.forgetAllForward = require('./prototype/forget-all-forward')

code.context is an empty object

Hey @jonschlinkert :)

The comment's code.context is an empty object when using export default, arrow function.

/**
 * Foobar 1 with default export arrow function and typescript
 * and empty code.context
 *
 * @param  {string} `commit` a commit message
 * @api public
 */

export default (commit: string): Commit => {};

/**
 * Foobar 2 with default export arrow function JS
 * and empty code.context
 *
 * @param  {string} `commit` a commit message
 * @api public
 */

export default (commit) => {};

/**
 * Foobar 3 with default export named function and typescript
 *
 * @param  {string} `commit` a commit message
 * @api public
 */

export default function foobar(commit: string): Commit {}

/**
 * Foobar 4 with default export named function javascript
 *
 * @param  {string} `commit` a commit message
 * @api public
 */

export default function foobar(commit) {}

/**
 * Foobar 5 with default export arrow function and typescript
 *
 * @param  {string} `commit` a commit message
 * @api public
 */

module.exports = (commit: string): Commit => {};

/**
 * Foobar 6 with default export arrow function JS
 *
 * @param  {string} `commit` a commit message
 * @api public
 */

module.exports = (commit) => {};

/**
 * Foobar 7 with default export named function and typescript
 *
 * @param  {string} `commit` a commit message
 * @api public
 */

module.exports = function foobar(commit: string): Commit {};

/**
 * Foobar 8 with default export named function javascript
 *
 * @param  {string} `commit` a commit message
 * @api public
 */

module.exports = function foobar(commit) {};

Remove the carrot (`) from the parseParams regex?

It can be found at https://github.com/jonschlinkert/parse-comments/blob/master/index.js#L126. And the intention of that is because it is not standard jsdoc, so syntax highlighting is different.

source code

/**
 * > Make an array from any value.
 *
 * @param  {Any} `val` some long description
 * @return {Array}
 * @api private
 */

let arrayify = (val) => {
  if (!val) return []
  if (Array.isArray(val)) return val
  return [val]
}

without carrot

2017-01-18-19 36 58_445x309_scrot

with carrot

2017-01-18-19 37 35_481x296_scrot

notice the val

More better would be to wrap with ` later, instead of relay on that

module.exports and `@name`

I'm not sure if the issue is for here, but yea... maybe you know better, i dont have time to investigate deeper and just want to mention it

Currently, using some tools like helper-apidocs or the cli apidocs-cli and the following example

/**
 * > Lorem ipsum thingish thing
 *
 * @param  {Number} `one` you should pass `1`
 * @param  {Number} `two` you should pass `2`
 * @return {Number} the `one + two` result
 * @api public
 */
module.exports = function foobar (one, two) {
  return one + two
}

will output

### [.exports](./index.js#L10)

* `one` **{Number}**: you should pass `1`    
* `two` **{Number}**: you should pass `2`    
* `returns` **{Number}**: the `one + two` result  

> Lorem ipsum thingish thing

notice the [.exports], so we need to be [foobar] without adding the @name foobar.
And notice the #L10 for which i'm talking in #6.

I can guarantee that these things isn't from my side (from my packages and etc)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.