├── .gitattributes ├── .npmrc ├── example.js ├── .travis.yml ├── .editorconfig ├── .gitignore ├── LICENSE ├── package.json ├── test ├── fixtures │ └── class.js └── test.js ├── .eslintrc.json ├── .verb.md ├── index.js └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.* text eol=lf -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | const parse = require('./'); 2 | const context = parse('function app(a, b, c) {\n\n}'); 3 | console.log(context) 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | os: 3 | - linux 4 | - osx 5 | - windows 6 | language: node_js 7 | node_js: 8 | - node 9 | - '11' 10 | - '10' 11 | - '9' 12 | - '8' 13 | - '7' 14 | - '6' 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # always ignore files 2 | *.DS_Store 3 | *.sublime-* 4 | 5 | # test related, or directories generated by tests 6 | test/actual 7 | actual 8 | coverage 9 | .nyc* 10 | 11 | # npm 12 | node_modules 13 | npm-debug.log 14 | 15 | # yarn 16 | yarn.lock 17 | yarn-error.log 18 | 19 | # misc 20 | _gh_pages 21 | _draft 22 | _drafts 23 | bower_components 24 | vendor 25 | temp 26 | tmp 27 | TODO.md 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-present, Jon Schlinkert. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parse-code-context", 3 | "description": "Fast and simple way to parse code context for use with documentation from code comments. Parses context from a single line of JavaScript, for functions, variable declarations, methods, prototype properties, prototype methods etc.", 4 | "version": "1.0.0", 5 | "homepage": "https://github.com/jonschlinkert/parse-code-context", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "jonschlinkert/parse-code-context", 8 | "bugs": { 9 | "url": "https://github.com/jonschlinkert/parse-code-context/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js" 14 | ], 15 | "main": "index.js", 16 | "engines": { 17 | "node": ">=6" 18 | }, 19 | "scripts": { 20 | "test": "mocha" 21 | }, 22 | "devDependencies": { 23 | "gulp-format-md": "^2.0.0", 24 | "mocha": "^5.2.0" 25 | }, 26 | "keywords": [ 27 | "args", 28 | "arguments", 29 | "code", 30 | "code-context", 31 | "context", 32 | "declaration", 33 | "function", 34 | "method", 35 | "parse", 36 | "property", 37 | "prototype", 38 | "statement" 39 | ], 40 | "verb": { 41 | "toc": false, 42 | "layout": "default", 43 | "tasks": [ 44 | "readme" 45 | ], 46 | "plugins": [ 47 | "gulp-format-md" 48 | ], 49 | "related": { 50 | "list": [ 51 | "code-context", 52 | "snapdragon", 53 | "strip-comments" 54 | ] 55 | }, 56 | "lint": { 57 | "reflinks": true 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/fixtures/class.js: -------------------------------------------------------------------------------- 1 | /* fixture from https://github.com/tj/dox */ 2 | 3 | /* 4 | * A Foo. 5 | * @class FooBar 6 | * @extends Foo.Baz 7 | */ 8 | export default class FooBar extends Foo.Baz { 9 | 10 | /* 11 | * construct a FooBar 12 | * @constructor 13 | * @param {Object} options constructor options 14 | */ 15 | 16 | constructor(options) { 17 | this.options = options 18 | } 19 | 20 | /* 21 | * Method of the FooBar class. 22 | * @return {Overflow} 23 | */ 24 | bar() { 25 | return 99999999999999999999999999999999999999999999999999999999999999999 26 | } 27 | 28 | /** 29 | * Static method of the FooBar class. 30 | * @return {String} 31 | */ 32 | static staticMethod() { 33 | return 'static method' 34 | } 35 | 36 | /** 37 | * Static generator method of the FooBar class. 38 | * @return {String} 39 | */ 40 | static * staticGeneratorMethod() { 41 | return 'static method' 42 | } 43 | 44 | /** 45 | * Generator method with computed name. 46 | * @return {String} 47 | */ 48 | *[Symbol.iterator]() { 49 | for (let arg of this.args) yield arg 50 | } 51 | 52 | /* 53 | * Getter for the blah property. 54 | */ 55 | get blah() { 56 | this._blah = "blah" 57 | return this._blah; 58 | } 59 | 60 | /* 61 | * Getter for the whatever property. 62 | * @return {String} 63 | */ 64 | get whatever() { 65 | return this.whatever; 66 | } 67 | } 68 | 69 | /* 70 | * @class Baz 71 | */ 72 | export class Baz extends FooBar { 73 | 74 | /* 75 | * @param {Object} options constructor options 76 | */ 77 | constructor(options) { 78 | this.options = options 79 | } 80 | } 81 | 82 | /* 83 | * @class Lorem 84 | */ 85 | class Lorem { 86 | constructor(options) { 87 | this.options = options 88 | } 89 | } 90 | 91 | /* 92 | * @class Lorem 93 | */ 94 | class Ipsum extends mixin(Foo.Bar, Baz) { 95 | constructor(options) { 96 | this.options = options 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended" 4 | ], 5 | 6 | "env": { 7 | "browser": false, 8 | "es6": true, 9 | "node": true, 10 | "mocha": true 11 | }, 12 | 13 | "parserOptions":{ 14 | "ecmaVersion": 9, 15 | "sourceType": "module", 16 | "ecmaFeatures": { 17 | "modules": true, 18 | "experimentalObjectRestSpread": true 19 | } 20 | }, 21 | 22 | "globals": { 23 | "document": false, 24 | "navigator": false, 25 | "window": false 26 | }, 27 | 28 | "rules": { 29 | "accessor-pairs": 2, 30 | "arrow-spacing": [2, { "before": true, "after": true }], 31 | "block-spacing": [2, "always"], 32 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 33 | "comma-dangle": [2, "never"], 34 | "comma-spacing": [2, { "before": false, "after": true }], 35 | "comma-style": [2, "last"], 36 | "constructor-super": 2, 37 | "curly": [2, "multi-line"], 38 | "dot-location": [2, "property"], 39 | "eol-last": 2, 40 | "eqeqeq": [2, "allow-null"], 41 | "generator-star-spacing": [2, { "before": true, "after": true }], 42 | "handle-callback-err": [2, "^(err|error)$" ], 43 | "indent": [2, 2, { "SwitchCase": 1 }], 44 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 45 | "keyword-spacing": [2, { "before": true, "after": true }], 46 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 47 | "new-parens": 2, 48 | "no-array-constructor": 2, 49 | "no-caller": 2, 50 | "no-class-assign": 2, 51 | "no-cond-assign": 2, 52 | "no-const-assign": 2, 53 | "no-control-regex": 2, 54 | "no-debugger": 2, 55 | "no-delete-var": 2, 56 | "no-dupe-args": 2, 57 | "no-dupe-class-members": 2, 58 | "no-dupe-keys": 2, 59 | "no-duplicate-case": 2, 60 | "no-empty-character-class": 2, 61 | "no-eval": 2, 62 | "no-ex-assign": 2, 63 | "no-extend-native": 2, 64 | "no-extra-bind": 2, 65 | "no-extra-boolean-cast": 2, 66 | "no-extra-parens": [2, "functions"], 67 | "no-fallthrough": 2, 68 | "no-floating-decimal": 2, 69 | "no-func-assign": 2, 70 | "no-implied-eval": 2, 71 | "no-inner-declarations": [2, "functions"], 72 | "no-invalid-regexp": 2, 73 | "no-irregular-whitespace": 2, 74 | "no-iterator": 2, 75 | "no-label-var": 2, 76 | "no-labels": 2, 77 | "no-lone-blocks": 2, 78 | "no-mixed-spaces-and-tabs": 2, 79 | "no-multi-spaces": 2, 80 | "no-multi-str": 2, 81 | "no-multiple-empty-lines": [2, { "max": 1 }], 82 | "no-native-reassign": 0, 83 | "no-negated-in-lhs": 2, 84 | "no-new": 2, 85 | "no-new-func": 2, 86 | "no-new-object": 2, 87 | "no-new-require": 2, 88 | "no-new-wrappers": 2, 89 | "no-obj-calls": 2, 90 | "no-octal": 2, 91 | "no-octal-escape": 2, 92 | "no-proto": 0, 93 | "no-redeclare": 2, 94 | "no-regex-spaces": 2, 95 | "no-return-assign": 2, 96 | "no-self-compare": 2, 97 | "no-sequences": 2, 98 | "no-shadow-restricted-names": 2, 99 | "no-spaced-func": 2, 100 | "no-sparse-arrays": 2, 101 | "no-this-before-super": 2, 102 | "no-throw-literal": 2, 103 | "no-trailing-spaces": 0, 104 | "no-undef": 2, 105 | "no-undef-init": 2, 106 | "no-unexpected-multiline": 2, 107 | "no-unneeded-ternary": [2, { "defaultAssignment": false }], 108 | "no-unreachable": 2, 109 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 110 | "no-useless-call": 0, 111 | "no-with": 2, 112 | "one-var": [0, { "initialized": "never" }], 113 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }], 114 | "padded-blocks": [0, "never"], 115 | "quotes": [2, "single", "avoid-escape"], 116 | "radix": 2, 117 | "semi": [2, "always"], 118 | "semi-spacing": [2, { "before": false, "after": true }], 119 | "space-before-blocks": [2, "always"], 120 | "space-before-function-paren": [2, "never"], 121 | "space-in-parens": [2, "never"], 122 | "space-infix-ops": 2, 123 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 124 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], 125 | "use-isnan": 2, 126 | "valid-typeof": 2, 127 | "wrap-iife": [2, "any"], 128 | "yoda": [2, "never"] 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | ## Getting started 2 | 3 | - [Usage](#usage) 4 | - [API](#api) 5 | - [Examples](#examples) 6 | - [Custom parsers](#custom-parsers) 7 | 8 | ## Usage 9 | 10 | ```js 11 | const parse = require('{%= name %}'); 12 | console.log(parse('function app(a, b, c) {\n\n}')); 13 | ``` 14 | 15 | ## API 16 | {%= apidocs('index.js') %} 17 | 18 | ## Examples 19 | 20 | ### function statement 21 | 22 | ```js 23 | const context = parse('function app(a, b, c) {\n\n}'); 24 | console.log(context); 25 | ``` 26 | 27 | Results in: 28 | 29 | ```js 30 | { type: 'function statement', 31 | name: 'app', 32 | params: [ 'a', 'b', 'c' ], 33 | string: 'app()', 34 | original: 'function app() {\n\n}' } 35 | ``` 36 | 37 | ### function expression 38 | 39 | ```js 40 | parse("var app = function(a, b, c) {\n\n}"); 41 | ``` 42 | 43 | Results in: 44 | 45 | ```js 46 | { type: 'function expression', 47 | name: 'app', 48 | params: [ 'a', 'b', 'c' ], 49 | string: 'app()', 50 | original: 'var app = function() {\n\n}' } 51 | ``` 52 | 53 | ### `module.exports` function expression 54 | 55 | ```js 56 | parse("module.exports = function foo(a, b, c) {\n\n}"); 57 | ``` 58 | 59 | Results in: 60 | 61 | ```js 62 | { type: 'function expression', 63 | receiver: 'module.exports', 64 | name: 'foo', 65 | params: [ 'a', 'b', 'c' ], 66 | string: 'module.exports()', 67 | original: 'module.exports = function foo(a, b, c) {\n\n}' } 68 | ``` 69 | 70 | ### `module.exports` method 71 | 72 | ```js 73 | parse("module.exports = function() {\n\n}"); 74 | ``` 75 | 76 | Results in: 77 | 78 | ```js 79 | { type: 'method', 80 | receiver: 'module.exports', 81 | name: '', 82 | params: [], 83 | string: 'module.exports.() {\n\n}()', 84 | original: 'module.exports = function() {\n\n}' } 85 | ``` 86 | 87 | ### prototype method 88 | 89 | ```js 90 | parse("Template.prototype.get = function() {}"); 91 | ``` 92 | 93 | Results in: 94 | 95 | ```js 96 | { type: 'prototype method', 97 | class: 'Template', 98 | name: 'get', 99 | params: [], 100 | string: 'Template.prototype.get()', 101 | original: 'Template.prototype.get = function() {}' } 102 | ``` 103 | 104 | ### prototype property 105 | 106 | ```js 107 | parse("Template.prototype.enabled = true;\nasdf"); 108 | ``` 109 | 110 | Results in: 111 | 112 | ```js 113 | { type: 'prototype property', 114 | class: 'Template', 115 | name: 'enabled', 116 | value: 'true', 117 | string: 'Template.prototype.enabled', 118 | original: 'Template.prototype.enabled = true;\nasdf' } 119 | ``` 120 | 121 | ### method 122 | 123 | ```js 124 | parse("option.get = function() {}"); 125 | ``` 126 | 127 | Results in: 128 | 129 | ```js 130 | { type: 'method', 131 | receiver: 'option', 132 | name: 'get', 133 | params: [], 134 | string: 'option.get()', 135 | original: 'option.get = function() {}' } 136 | ``` 137 | 138 | ### property 139 | 140 | ```js 141 | parse("option.name = \"delims\";\nasdf"); 142 | ``` 143 | 144 | Results in: 145 | 146 | ```js 147 | { type: 'property', 148 | receiver: 'option', 149 | name: 'name', 150 | value: '"delims"', 151 | string: 'option.name', 152 | original: 'option.name = "delims";\nasdf' } 153 | ``` 154 | 155 | ### declaration 156 | 157 | ```js 158 | parse("var name = \"delims\";\nasdf"); 159 | ``` 160 | 161 | Results in: 162 | 163 | ```js 164 | { type: 'declaration', 165 | name: 'name', 166 | value: '"delims"', 167 | string: 'name', 168 | original: 'var name = "delims";\nasdf' } 169 | 170 | ``` 171 | 172 | ### function statement params 173 | 174 | ```js 175 | parse("function app(a, b) {\n\n}"); 176 | ``` 177 | 178 | Results in: 179 | 180 | ```js 181 | { type: 'function statement', 182 | name: 'app', 183 | params: [ 'a', 'b' ], 184 | string: 'app()', 185 | original: 'function app(a, b) {\n\n}' } 186 | ``` 187 | 188 | ### function expression params 189 | 190 | ```js 191 | parse("var app = function(foo, bar) {\n\n}"); 192 | ``` 193 | 194 | Results in: 195 | 196 | ```js 197 | { type: 'function expression', 198 | name: 'app', 199 | params: [ 'foo', 'bar' ], 200 | string: 'app()', 201 | original: 'var app = function(foo, bar) {\n\n}' } 202 | ``` 203 | 204 | ### function expression params 205 | 206 | ```js 207 | parse("var app=function(foo,bar) {\n\n}"); 208 | ``` 209 | 210 | Results in: 211 | 212 | ```js 213 | { type: 'function expression', 214 | name: 'app', 215 | params: [ 'foo', 'bar' ], 216 | string: 'app()', 217 | original: 'var app=function(foo,bar) {\n\n}' } 218 | ``` 219 | 220 | ### prototype method params 221 | 222 | ```js 223 | parse("Template.prototype.get = function(key, value, options) {}"); 224 | ``` 225 | 226 | Results in: 227 | 228 | ```js 229 | { type: 'prototype method', 230 | class: 'Template', 231 | name: 'get', 232 | params: [ 'key', 'value', 'options' ], 233 | string: 'Template.prototype.get()', 234 | original: 'Template.prototype.get = function(key, value, options) {}' } 235 | ``` 236 | 237 | ## Custom parsers 238 | 239 | Instantiate the `Parser` class to register custom parsers. 240 | 241 | 242 | ```js 243 | const { Parser} = require('{%= name %}'); 244 | const parser = new Parser(); 245 | 246 | parser.capture(/foo\(([^)]+)\)/, match => { 247 | return { 248 | params: match[1].split(/[,\s]+/) 249 | }; 250 | }); 251 | 252 | console.log(parser.parse('foo(a, b, c)')); 253 | ``` 254 | 255 | 256 | ## Credit 257 | 258 | Regex was originally sourced and modified from . 259 | 260 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Create an instance of `Parser` with 5 | * the given `string`, optionally passing 6 | * a `parent` name for namespacing methods 7 | * 8 | * ```js 9 | * const { Parser } = require('parse-code-context'); 10 | * const parser = new Parser('function foo(a, b, c) {}'); 11 | * ``` 12 | * @name Parser 13 | * @param {String} `str` 14 | * @param {String} `parent` 15 | * @api public 16 | */ 17 | 18 | class Parser { 19 | constructor(parent) { 20 | this.parent = parent; 21 | this.fns = []; 22 | this.init(); 23 | } 24 | 25 | /** 26 | * Convenience method for creating a property name 27 | * that is prefixed with the parent namespace, if defined. 28 | * 29 | * @name .name 30 | * @param {String} `name` 31 | * @return {String} 32 | * @api public 33 | */ 34 | 35 | name(name) { 36 | return this.parent ? this.parent + (name || '') : ''; 37 | } 38 | 39 | /** 40 | * Register a parser to use (in addition to those already 41 | * registered as default parsers) with the given `regex` and 42 | * function. 43 | * 44 | * ```js 45 | * const parser = new Parser('function foo(a, b, c){}'); 46 | * .capture(/function\s*([\w$]+)\s*\(([^)]+)/, (match) => { 47 | * return { 48 | * name: match[1], 49 | * params: matc(h[2] || '').split(/[,\s]/) 50 | * }; 51 | * }); 52 | * ``` 53 | * @name .capture 54 | * @param {RegExp} `regex` 55 | * @param {Function} `fn` 56 | * @return {Object} The instance for chaining 57 | * @api public 58 | */ 59 | 60 | capture(regex, fn) { 61 | this.fns.push({ regex, fn }); 62 | return this; 63 | } 64 | 65 | /** 66 | * Parse the string passed to the constructor with all registered parsers. 67 | * 68 | * @name .parse 69 | * @return {Object|Null} 70 | * @api public 71 | */ 72 | 73 | parse(str, parent) { 74 | this.parent = parent || this.parent; 75 | for (let parser of this.fns) { 76 | let re = parser.regex; 77 | let fn = parser.fn; 78 | let match = re.exec(str); 79 | if (match) { 80 | let ctx = fn.call(this, match, this.parent); 81 | if (ctx) { 82 | ctx.match = match; 83 | this.value = ctx; 84 | return ctx; 85 | } 86 | } 87 | } 88 | } 89 | 90 | init() { 91 | // module.exports method 92 | this.capture(/^(module\.exports)\s*=\s*function\s*\(([^)]+)/, (m, parent) => { 93 | return { 94 | type: 'method', 95 | receiver: m[1], 96 | name: '', 97 | params: params(m[2]), 98 | string: m[1] + '.' + m[2] + '()' 99 | }; 100 | }); 101 | 102 | this.capture(/^(module\.exports)\s*=\s*function\s([\w$]+)\s*\(([^)]+)/, (m, parent) => { 103 | return { 104 | type: 'function', 105 | subtype: 'expression', 106 | receiver: m[1], 107 | name: m[2], 108 | params: params(m[3]), 109 | string: m[2] + '()' 110 | }; 111 | }); 112 | 113 | // class, possibly exported by name or as a default 114 | this.capture(/^\s*(export(\s+default)?\s+)?class\s+([\w$]+)(\s+extends\s+([\w$.]+(?:\(.*\))?))?\s*{/, (m, parent) => { 115 | return { 116 | type: 'class', 117 | ctor: m[3], 118 | name: m[3], 119 | extends: m[5], 120 | string: 'new ' + m[3] + '()' 121 | }; 122 | }); 123 | 124 | // class constructor 125 | this.capture(/^\s*constructor\s*\(([^)]+)/, (m, parent) => { 126 | return { 127 | type: 'constructor', 128 | ctor: this.parent, 129 | name: 'constructor', 130 | params: params(m[4]), 131 | string: this.name('.prototype.') + 'constructor()' 132 | }; 133 | }); 134 | 135 | // class method 136 | this.capture(/^\s*(static)?\s*(\*?)\s*(\[Symbol\.[^\]]+\]|[\w$]+|\[.*\])\s*\(([^)]*)/, (m, parent) => { 137 | return { 138 | type: 'method', 139 | ctor: this.parent, 140 | name: m[2] + m[3], 141 | params: params(m[4]), 142 | static: m[1] === 'static', 143 | generator: m[2] === '*', 144 | string: this.name(m[1] ? '.' : '.prototype.') + m[2] + m[3] + '()' 145 | }; 146 | }); 147 | 148 | // named function statement, possibly exported by name or as a default 149 | this.capture(/^\s*(export(\s+default)?\s+)?function\s+([\w$]+)\s*\(([^)]+)/, (m, parent) => { 150 | return { 151 | type: 'function', 152 | subtype: 'statement', 153 | name: m[3], 154 | params: params(m[4]), 155 | string: m[3] + '()' 156 | }; 157 | }); 158 | 159 | // anonymous function expression exported as a default 160 | this.capture(/^\s*export\s+default\s+function\s*\(([^)]+)/, (m, parent) => { 161 | return { 162 | type: 'function', 163 | name: m[1], // undefined 164 | params: params(m[4]), 165 | string: m[1] + '()' 166 | }; 167 | }); 168 | 169 | // function expression 170 | this.capture(/^return\s+function(?:\s+([\w$]+))?\s*\(([^)]+)/, (m, parent) => { 171 | return { 172 | type: 'function', 173 | subtype: 'expression', 174 | name: m[1], 175 | params: params(m[4]), 176 | string: m[1] + '()' 177 | }; 178 | }); 179 | 180 | // function expression 181 | this.capture(/^\s*(?:const|let|var)\s+([\w$]+)\s*=\s*function\s*\(([^)]+)/, (m, parent) => { 182 | return { 183 | type: 'function', 184 | subtype: 'expression', 185 | name: m[1], 186 | params: params(m[2]), 187 | string: (m[1] || '') + '()' 188 | }; 189 | }); 190 | 191 | // prototype method 192 | this.capture(/^\s*([\w$.]+)\s*\.\s*prototype\s*\.\s*([\w$]+)\s*=\s*function\s*\(([^)]+)/, (m, parent) => { 193 | return { 194 | type: 'prototype method', 195 | category: 'method', 196 | ctor: m[1], 197 | name: m[2], 198 | params: params(m[3]), 199 | string: m[1] + '.prototype.' + m[2] + '()' 200 | }; 201 | }); 202 | 203 | // prototype property 204 | this.capture(/^\s*([\w$.]+)\s*\.\s*prototype\s*\.\s*([\w$]+)\s*=\s*([^\n;]+)/, (m, parent) => { 205 | return { 206 | type: 'prototype property', 207 | ctor: m[1], 208 | name: m[2], 209 | value: trim(m[3]), 210 | string: m[1] + '.prototype.' + m[2] 211 | }; 212 | }); 213 | 214 | // prototype property without assignment 215 | this.capture(/^\s*([\w$]+)\s*\.\s*prototype\s*\.\s*([\w$]+)\s*/, (m, parent) => { 216 | return { 217 | type: 'prototype property', 218 | ctor: m[1], 219 | name: m[2], 220 | string: m[1] + '.prototype.' + m[2] 221 | }; 222 | }); 223 | 224 | // inline prototype 225 | this.capture(/^\s*([\w$.]+)\s*\.\s*prototype\s*=\s*{/, (m, parent) => { 226 | return { 227 | type: 'prototype', 228 | ctor: m[1], 229 | name: m[1], 230 | string: m[1] + '.prototype' 231 | }; 232 | }); 233 | 234 | // Fat arrow function 235 | this.capture(/^\s*\(*\s*([\w$.]+)\s*\)*\s*=>/, (m, parent) => { 236 | return { 237 | type: 'function', 238 | ctor: this.parent, 239 | name: m[1], 240 | string: this.name('.prototype.') + m[1] + '()' 241 | }; 242 | }); 243 | 244 | // inline method 245 | this.capture(/^\s*([\w$.]+)\s*:\s*function\s*\(([^)]+)/, (m, parent) => { 246 | return { 247 | type: 'method', 248 | ctor: this.parent, 249 | name: m[1], 250 | string: this.name('.prototype.') + m[1] + '()' 251 | }; 252 | }); 253 | 254 | // inline property 255 | this.capture(/^\s*([\w$.]+)\s*:\s*([^\n;]+)/, (m, parent) => { 256 | return { 257 | type: 'property', 258 | ctor: this.parent, 259 | name: m[1], 260 | value: trim(m[2]), 261 | string: this.name('.') + m[1] 262 | }; 263 | }); 264 | 265 | // inline getter/setter 266 | this.capture(/^\s*(get|set)\s*([\w$.]+)\s*\(([^)]+)/, (m, parent) => { 267 | return { 268 | type: 'property', 269 | ctor: this.parent, 270 | name: m[2], 271 | string: this.name('.prototype.') + m[2] 272 | }; 273 | }); 274 | 275 | // method 276 | this.capture(/^\s*([\w$.]+)\s*\.\s*([\w$]+)\s*=\s*function\s*\(([^)]+)/, (m, parent) => { 277 | return { 278 | type: 'method', 279 | receiver: m[1], 280 | name: m[2], 281 | params: params(m[3]), 282 | string: m[1] + '.' + m[2] + '()' 283 | }; 284 | }); 285 | 286 | // property 287 | this.capture(/^\s*([\w$.]+)\s*\.\s*([\w$]+)\s*=\s*([^\n;]+)/, (m, parent) => { 288 | return { 289 | type: 'property', 290 | receiver: m[1], 291 | name: m[2], 292 | value: trim(m[3]), 293 | string: m[1] + '.' + m[2] 294 | }; 295 | }); 296 | 297 | // declaration 298 | this.capture(/^\s*(?:const|let|var)\s+([\w$]+)\s*=\s*([^\n;]+)/, (m, parent) => { 299 | return { 300 | type: 'declaration', 301 | name: m[1], 302 | value: trim(m[2]), 303 | string: m[1] 304 | }; 305 | }); 306 | } 307 | } 308 | 309 | function params(val) { 310 | return trim(val).split(/[\s,]+/); 311 | } 312 | 313 | function trim(str) { 314 | return toString(str).trim(); 315 | } 316 | 317 | function toString(str) { 318 | return str ? str.toString() : ''; 319 | } 320 | 321 | /** 322 | * Expose `parse` 323 | */ 324 | 325 | const parse = (str, options) => { 326 | let parser = new Parser(options); 327 | return parser.parse(str); 328 | }; 329 | 330 | parse.Parser = Parser; 331 | module.exports = parse; 332 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # parse-code-context [![NPM version](https://img.shields.io/npm/v/parse-code-context.svg?style=flat)](https://www.npmjs.com/package/parse-code-context) [![NPM monthly downloads](https://img.shields.io/npm/dm/parse-code-context.svg?style=flat)](https://npmjs.org/package/parse-code-context) [![NPM total downloads](https://img.shields.io/npm/dt/parse-code-context.svg?style=flat)](https://npmjs.org/package/parse-code-context) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/parse-code-context.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/parse-code-context) 2 | 3 | > Fast and simple way to parse code context for use with documentation from code comments. Parses context from a single line of JavaScript, for functions, variable declarations, methods, prototype properties, prototype methods etc. 4 | 5 | Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support. 6 | 7 | ## Install 8 | 9 | Install with [npm](https://www.npmjs.com/): 10 | 11 | ```sh 12 | $ npm install --save parse-code-context 13 | ``` 14 | 15 | ## Getting started 16 | 17 | * [Usage](#usage) 18 | * [API](#api) 19 | * [Examples](#examples) 20 | * [Custom parsers](#custom-parsers) 21 | 22 | ## Usage 23 | 24 | ```js 25 | const parse = require('parse-code-context'); 26 | console.log(parse('function app(a, b, c) {\n\n}')); 27 | ``` 28 | 29 | ## API 30 | 31 | ### [Parser](index.js#L18) 32 | 33 | Create an instance of `Parser` with the given `string`, optionally passing a `parent` name for namespacing methods 34 | 35 | **Params** 36 | 37 | * `str` **{String}** 38 | * `parent` **{String}** 39 | 40 | **Example** 41 | 42 | ```js 43 | const { Parser } = require('parse-code-context'); 44 | const parser = new Parser('function foo(a, b, c) {}'); 45 | ``` 46 | 47 | ### [.name](index.js#L35) 48 | 49 | Convenience method for creating a property name 50 | that is prefixed with the parent namespace, if defined. 51 | 52 | **Params** 53 | 54 | * `name` **{String}** 55 | * `returns` **{String}** 56 | 57 | ### [.capture](index.js#L60) 58 | 59 | Register a parser to use (in addition to those already registered as default parsers) with the given `regex` and function. 60 | 61 | **Params** 62 | 63 | * `regex` **{RegExp}** 64 | * `fn` **{Function}** 65 | * `returns` **{Object}**: The instance for chaining 66 | 67 | **Example** 68 | 69 | ```js 70 | const parser = new Parser('function foo(a, b, c){}'); 71 | .capture(/function\s*([\w$]+)\s*\(([^)]+)/, (match) => { 72 | return { 73 | name: match[1], 74 | params: matc(h[2] || '').split(/[,\s]/) 75 | }; 76 | }); 77 | ``` 78 | 79 | ### [.parse](index.js#L73) 80 | 81 | Parse the string passed to the constructor with all registered parsers. 82 | 83 | * `returns` **{Object|Null}** 84 | 85 | ## Examples 86 | 87 | ### function statement 88 | 89 | ```js 90 | const context = parse('function app(a, b, c) {\n\n}'); 91 | console.log(context); 92 | ``` 93 | 94 | Results in: 95 | 96 | ```js 97 | { type: 'function statement', 98 | name: 'app', 99 | params: [ 'a', 'b', 'c' ], 100 | string: 'app()', 101 | original: 'function app() {\n\n}' } 102 | ``` 103 | 104 | ### function expression 105 | 106 | ```js 107 | parse("var app = function(a, b, c) {\n\n}"); 108 | ``` 109 | 110 | Results in: 111 | 112 | ```js 113 | { type: 'function expression', 114 | name: 'app', 115 | params: [ 'a', 'b', 'c' ], 116 | string: 'app()', 117 | original: 'var app = function() {\n\n}' } 118 | ``` 119 | 120 | ### `module.exports` function expression 121 | 122 | ```js 123 | parse("module.exports = function foo(a, b, c) {\n\n}"); 124 | ``` 125 | 126 | Results in: 127 | 128 | ```js 129 | { type: 'function expression', 130 | receiver: 'module.exports', 131 | name: 'foo', 132 | params: [ 'a', 'b', 'c' ], 133 | string: 'module.exports()', 134 | original: 'module.exports = function foo(a, b, c) {\n\n}' } 135 | ``` 136 | 137 | ### `module.exports` method 138 | 139 | ```js 140 | parse("module.exports = function() {\n\n}"); 141 | ``` 142 | 143 | Results in: 144 | 145 | ```js 146 | { type: 'method', 147 | receiver: 'module.exports', 148 | name: '', 149 | params: [], 150 | string: 'module.exports.() {\n\n}()', 151 | original: 'module.exports = function() {\n\n}' } 152 | ``` 153 | 154 | ### prototype method 155 | 156 | ```js 157 | parse("Template.prototype.get = function() {}"); 158 | ``` 159 | 160 | Results in: 161 | 162 | ```js 163 | { type: 'prototype method', 164 | class: 'Template', 165 | name: 'get', 166 | params: [], 167 | string: 'Template.prototype.get()', 168 | original: 'Template.prototype.get = function() {}' } 169 | ``` 170 | 171 | ### prototype property 172 | 173 | ```js 174 | parse("Template.prototype.enabled = true;\nasdf"); 175 | ``` 176 | 177 | Results in: 178 | 179 | ```js 180 | { type: 'prototype property', 181 | class: 'Template', 182 | name: 'enabled', 183 | value: 'true', 184 | string: 'Template.prototype.enabled', 185 | original: 'Template.prototype.enabled = true;\nasdf' } 186 | ``` 187 | 188 | ### method 189 | 190 | ```js 191 | parse("option.get = function() {}"); 192 | ``` 193 | 194 | Results in: 195 | 196 | ```js 197 | { type: 'method', 198 | receiver: 'option', 199 | name: 'get', 200 | params: [], 201 | string: 'option.get()', 202 | original: 'option.get = function() {}' } 203 | ``` 204 | 205 | ### property 206 | 207 | ```js 208 | parse("option.name = \"delims\";\nasdf"); 209 | ``` 210 | 211 | Results in: 212 | 213 | ```js 214 | { type: 'property', 215 | receiver: 'option', 216 | name: 'name', 217 | value: '"delims"', 218 | string: 'option.name', 219 | original: 'option.name = "delims";\nasdf' } 220 | ``` 221 | 222 | ### declaration 223 | 224 | ```js 225 | parse("var name = \"delims\";\nasdf"); 226 | ``` 227 | 228 | Results in: 229 | 230 | ```js 231 | { type: 'declaration', 232 | name: 'name', 233 | value: '"delims"', 234 | string: 'name', 235 | original: 'var name = "delims";\nasdf' } 236 | 237 | ``` 238 | 239 | ### function statement params 240 | 241 | ```js 242 | parse("function app(a, b) {\n\n}"); 243 | ``` 244 | 245 | Results in: 246 | 247 | ```js 248 | { type: 'function statement', 249 | name: 'app', 250 | params: [ 'a', 'b' ], 251 | string: 'app()', 252 | original: 'function app(a, b) {\n\n}' } 253 | ``` 254 | 255 | ### function expression params 256 | 257 | ```js 258 | parse("var app = function(foo, bar) {\n\n}"); 259 | ``` 260 | 261 | Results in: 262 | 263 | ```js 264 | { type: 'function expression', 265 | name: 'app', 266 | params: [ 'foo', 'bar' ], 267 | string: 'app()', 268 | original: 'var app = function(foo, bar) {\n\n}' } 269 | ``` 270 | 271 | ### function expression params 272 | 273 | ```js 274 | parse("var app=function(foo,bar) {\n\n}"); 275 | ``` 276 | 277 | Results in: 278 | 279 | ```js 280 | { type: 'function expression', 281 | name: 'app', 282 | params: [ 'foo', 'bar' ], 283 | string: 'app()', 284 | original: 'var app=function(foo,bar) {\n\n}' } 285 | ``` 286 | 287 | ### prototype method params 288 | 289 | ```js 290 | parse("Template.prototype.get = function(key, value, options) {}"); 291 | ``` 292 | 293 | Results in: 294 | 295 | ```js 296 | { type: 'prototype method', 297 | class: 'Template', 298 | name: 'get', 299 | params: [ 'key', 'value', 'options' ], 300 | string: 'Template.prototype.get()', 301 | original: 'Template.prototype.get = function(key, value, options) {}' } 302 | ``` 303 | 304 | ## Custom parsers 305 | 306 | Instantiate the `Parser` class to register custom parsers. 307 | 308 | ```js 309 | const { Parser} = require('parse-code-context'); 310 | const parser = new Parser(); 311 | 312 | parser.capture(/foo\(([^)]+)\)/, match => { 313 | return { 314 | params: match[1].split(/[,\s]+/) 315 | }; 316 | }); 317 | 318 | console.log(parser.parse('foo(a, b, c)')); 319 | ``` 320 | 321 | ## Credit 322 | 323 | Regex was originally sourced and modified from [https://github.com/visionmedia/dox](https://github.com/visionmedia/dox). 324 | 325 | ## About 326 | 327 |
328 | Contributing 329 | 330 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). 331 | 332 |
333 | 334 |
335 | Running Tests 336 | 337 | 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: 338 | 339 | ```sh 340 | $ npm install && npm test 341 | ``` 342 | 343 |
344 | 345 |
346 | Building docs 347 | 348 | _(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_ 349 | 350 | To generate the readme, run the following command: 351 | 352 | ```sh 353 | $ npm install -g verbose/verb#dev verb-generate-readme && verb 354 | ``` 355 | 356 |
357 | 358 | ### Related projects 359 | 360 | You might also be interested in these projects: 361 | 362 | * [code-context](https://www.npmjs.com/package/code-context): Parse a string of javascript to determine the context for functions, variables and comments based… [more](https://github.com/jonschlinkert/code-context) | [homepage](https://github.com/jonschlinkert/code-context "Parse a string of javascript to determine the context for functions, variables and comments based on the code that follows.") 363 | * [snapdragon](https://www.npmjs.com/package/snapdragon): Easy-to-use plugin system for creating powerful, fast and versatile parsers and compilers, with built-in source-map… [more](https://github.com/here-be/snapdragon) | [homepage](https://github.com/here-be/snapdragon "Easy-to-use plugin system for creating powerful, fast and versatile parsers and compilers, with built-in source-map support.") 364 | * [strip-comments](https://www.npmjs.com/package/strip-comments): Strip comments from code. Removes line comments, block comments, the first comment only, or all… [more](https://github.com/jonschlinkert/strip-comments) | [homepage](https://github.com/jonschlinkert/strip-comments "Strip comments from code. Removes line comments, block comments, the first comment only, or all comments. Optionally leave protected comments unharmed.") 365 | 366 | ### Author 367 | 368 | **Jon Schlinkert** 369 | 370 | * [GitHub Profile](https://github.com/jonschlinkert) 371 | * [Twitter Profile](https://twitter.com/jonschlinkert) 372 | * [LinkedIn Profile](https://linkedin.com/in/jonschlinkert) 373 | 374 | ### License 375 | 376 | Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert). 377 | Released under the [MIT License](LICENSE). 378 | 379 | *** 380 | 381 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on November 24, 2018._ -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * parse-code-context 3 | * 4 | * Copyright (c) 2014-present Jon Schlinkert. 5 | * Some of the regex was originally sourced from https://github.com/visionmedia/dox 6 | * Licensed under the MIT License 7 | */ 8 | 9 | 'use strict'; 10 | 11 | require('mocha'); 12 | const fs = require('fs'); 13 | const path = require('path'); 14 | const assert = require('assert'); 15 | const { Parser } = require('..'); 16 | let parser; 17 | 18 | function fixtures(fp, cb) { 19 | return fs.readFile(path.join('test/fixtures', fp), 'utf8', cb); 20 | } 21 | 22 | describe('parse-code-context', () => { 23 | beforeEach(() => (parser = new Parser())); 24 | 25 | describe('constructor:', () => { 26 | it('should create an instance of Parser', () => { 27 | assert(parser instanceof Parser); 28 | }); 29 | 30 | it('should register parsers for matching', () => { 31 | parser.capture(/foo\(([^)]+)\)/, m => { 32 | return { 33 | params: m[1].split(/[,\s]+/) 34 | }; 35 | }); 36 | 37 | const ctx = parser.parse('foo(a, b, c)'); 38 | assert.deepEqual(ctx.params, ['a', 'b', 'c']); 39 | }); 40 | 41 | it('should support passing the parent name on the constructor', () => { 42 | const ctx = parser.parse('enabled: true;\nasdf', 'Foo'); 43 | assert.equal(ctx.ctor, 'Foo'); 44 | assert.equal(ctx.type, 'property'); 45 | assert.equal(ctx.name, 'enabled'); 46 | assert.equal(ctx.string, 'Foo.enabled'); 47 | }); 48 | }); 49 | 50 | describe('parse context:', () => { 51 | it('should return null when no matches are found', () => { 52 | let ctx = parser.parse('foo'); 53 | assert.equal(ctx, null); 54 | }); 55 | 56 | it('should extract function statements', () => { 57 | let ctx = parser.parse('function app(a, b, c) {\n\n}'); 58 | assert.equal(ctx.type, 'function'); 59 | assert.equal(ctx.subtype, 'statement'); 60 | assert.equal(ctx.name, 'app'); 61 | assert.deepEqual(ctx.params, [ 'a', 'b', 'c' ]); 62 | }); 63 | 64 | it('should extract function statements', () => { 65 | let ctx = parser.parse('function app(a, b, c) {\n\n}'); 66 | assert.equal(ctx.type, 'function'); 67 | assert.equal(ctx.subtype, 'statement'); 68 | assert.equal(ctx.name, 'app'); 69 | assert.deepEqual(ctx.params, [ 'a', 'b', 'c' ]); 70 | }); 71 | 72 | it('should extract function expressions', () => { 73 | let ctx = parser.parse('let app = function(a, b, c) {\n\n}'); 74 | assert.equal(ctx.type, 'function'); 75 | assert.equal(ctx.subtype, 'expression'); 76 | assert.equal(ctx.name, 'app'); 77 | assert.deepEqual(ctx.params, [ 'a', 'b', 'c' ]); 78 | }); 79 | 80 | it('should extract `module.exports` function expressions', () => { 81 | let ctx = parser.parse('module.exports = function foo(a, b, c) {\n\n}'); 82 | assert.equal(ctx.type, 'function'); 83 | assert.equal(ctx.subtype, 'expression'); 84 | assert.equal(ctx.name, 'foo'); 85 | assert.deepEqual(ctx.params, [ 'a', 'b', 'c' ]); 86 | }); 87 | 88 | it('should support class, extends and is exported as default', () => { 89 | let ctx = parser.parse('export default class FooBar extends Foo.Baz {'); 90 | assert.equal(ctx.type, 'class'); 91 | assert.equal(ctx.name, 'FooBar'); 92 | assert.equal(ctx.ctor, 'FooBar'); 93 | assert.equal(ctx.extends, 'Foo.Baz'); 94 | assert.equal(ctx.string, 'new FooBar()'); 95 | }); 96 | 97 | it('should parse inline prototype properties', () => { 98 | let ctx = parser.parse('App.prototype = {'); 99 | assert.equal(ctx.type, 'prototype'); 100 | assert.equal(ctx.ctor, 'App'); 101 | assert.equal(ctx.name, 'App'); 102 | assert.equal(ctx.string, 'App.prototype'); 103 | }); 104 | 105 | it('should extract prototype methods', () => { 106 | let ctx = parser.parse('App.prototype.get = function(a, b, c) {}'); 107 | assert.equal(ctx.type, 'prototype method'); 108 | assert.equal(ctx.ctor, 'App'); 109 | assert.equal(ctx.name, 'get'); 110 | assert.deepEqual(ctx.params, [ 'a', 'b', 'c' ]); 111 | }); 112 | 113 | it('should support passing a parent name to properties', () => { 114 | let ctx = parser.parse('enabled: true;\nasdf', 'Foo'); 115 | assert.equal(ctx.ctor, 'Foo'); 116 | assert.equal(ctx.type, 'property'); 117 | assert.equal(ctx.name, 'enabled'); 118 | assert.equal(ctx.string, 'Foo.enabled'); 119 | }); 120 | 121 | it('should extract prototype properties', () => { 122 | let ctx = parser.parse('App.prototype.enabled = true;\nasdf'); 123 | assert.equal(ctx.type, 'prototype property'); 124 | assert.equal(ctx.ctor, 'App'); 125 | assert.equal(ctx.name, 'enabled'); 126 | assert.equal(ctx.value, 'true'); 127 | }); 128 | 129 | it('should extract methods', () => { 130 | let ctx = parser.parse('option.get = function(a, b, c) {}'); 131 | assert.equal(ctx.type, 'method'); 132 | assert.equal(ctx.receiver, 'option'); 133 | assert.equal(ctx.name, 'get'); 134 | assert.deepEqual(ctx.params, [ 'a', 'b', 'c' ]); 135 | }); 136 | 137 | it('should extract properties', () => { 138 | let ctx = parser.parse('option.name = "delims";\nasdf'); 139 | assert.equal(ctx.type, 'property'); 140 | assert.equal(ctx.receiver, 'option'); 141 | assert.equal(ctx.name, 'name'); 142 | assert.equal(ctx.value, '"delims"'); 143 | }); 144 | 145 | it('should extract declarations', () => { 146 | let ctx = parser.parse('let name = "delims";\nasdf'); 147 | assert.equal(ctx.type, 'declaration'); 148 | assert.equal(ctx.name, 'name'); 149 | assert.equal(ctx.value, '"delims"'); 150 | }); 151 | }); 152 | 153 | describe('context params:', () => { 154 | it('should extract function statement params', () => { 155 | let ctx = parser.parse('function app(a, b) {\n\n}'); 156 | assert.equal(ctx.type, 'function'); 157 | assert.equal(ctx.subtype, 'statement'); 158 | assert.deepEqual(ctx.params, ['a', 'b']); 159 | }); 160 | 161 | it('should extract function statement params with newlines', () => { 162 | let ctx = parser.parse('function app(\n a,\n b) {\n\n}'); 163 | assert.equal(ctx.type, 'function'); 164 | assert.equal(ctx.subtype, 'statement'); 165 | assert.deepEqual(ctx.params, ['a', 'b']); 166 | }); 167 | 168 | it('should extract function expression params', () => { 169 | let ctx = parser.parse('let app = function(foo, bar) {\n\n}'); 170 | assert.equal(ctx.type, 'function'); 171 | assert.equal(ctx.subtype, 'expression'); 172 | assert.deepEqual(ctx.params, ['foo', 'bar']); 173 | }); 174 | 175 | it('should extract function expression params with newlines', () => { 176 | let ctx = parser.parse('let app = function(foo,\n bar) {\n\n}'); 177 | assert.equal(ctx.type, 'function'); 178 | assert.equal(ctx.subtype, 'expression'); 179 | assert.deepEqual(ctx.params, ['foo', 'bar']); 180 | }); 181 | 182 | it('should extract function expression params', () => { 183 | let ctx = parser.parse('let app=function(foo,bar) {\n\n}'); 184 | assert.equal(ctx.type, 'function'); 185 | assert.equal(ctx.subtype, 'expression'); 186 | assert.deepEqual(ctx.params, ['foo', 'bar']); 187 | }); 188 | 189 | it('should extract prototype method params', () => { 190 | let ctx = parser.parse('App.prototype.get = function(key, value, options) {}'); 191 | assert.equal(ctx.type, 'prototype method'); 192 | assert.equal(ctx.ctor, 'App'); 193 | assert.deepEqual(ctx.params, ['key', 'value', 'options']); 194 | }); 195 | 196 | it('should extract class', (cb) => { 197 | fixtures('class.js', (err, str) => { 198 | if (err) return cb(err); 199 | 200 | let matches = []; 201 | let i = 0; 202 | str.split('\n').forEach(function(line) { 203 | line = line.replace(/^\s+/, ''); 204 | let ctx = parser.parse(line); 205 | if (ctx) { 206 | matches.push(ctx); 207 | } 208 | }); 209 | 210 | assert.equal(matches[i].type, 'class'); 211 | assert.equal(matches[i].ctor, 'FooBar'); 212 | assert.equal(matches[i].name, 'FooBar'); 213 | assert.equal(matches[i].extends, 'Foo.Baz'); 214 | assert.equal(matches[i].string, 'new FooBar()'); 215 | 216 | i++; 217 | assert.equal(matches[i].type, 'constructor'); 218 | assert.equal(matches[i].ctor, undefined); 219 | assert.equal(matches[i].name, 'constructor'); 220 | assert.equal(matches[i].params[0], ''); 221 | assert.equal(matches[i].string, 'constructor()'); 222 | 223 | i++; 224 | assert.equal(matches[i].type, 'property'); 225 | assert.equal(matches[i].receiver, 'this'); 226 | assert.equal(matches[i].name, 'options'); 227 | assert.equal(matches[i].value, 'options'); 228 | assert.equal(matches[i].string, 'this.options'); 229 | 230 | i++; 231 | assert.equal(matches[i].type, 'method'); 232 | assert.equal(matches[i].ctor, undefined); 233 | assert.equal(matches[i].name, 'bar'); 234 | assert.deepEqual(matches[i].params, ['']); 235 | assert.equal(matches[i].string, 'bar()'); 236 | 237 | i++; 238 | assert.equal(matches[i].type, 'method'); 239 | assert.equal(matches[i].ctor, undefined); 240 | assert.equal(matches[i].name, 'staticMethod'); 241 | assert.deepEqual(matches[i].params, ['']); 242 | assert.equal(matches[i].string, 'staticMethod()'); 243 | 244 | i++; 245 | assert.equal(matches[i].type, 'method'); 246 | assert.equal(matches[i].ctor, undefined); 247 | assert.equal(matches[i].name, '*staticGeneratorMethod'); 248 | assert.deepEqual(matches[i].params, ['']); 249 | assert.equal(matches[i].string, '*staticGeneratorMethod()'); 250 | 251 | i++; 252 | assert.equal(matches[i].type, 'method'); 253 | assert.equal(matches[i].ctor, undefined); 254 | assert.equal(matches[i].name, '*[Symbol.iterator]'); 255 | assert.deepEqual(matches[i].params, ['']); 256 | assert.equal(matches[i].string, '*[Symbol.iterator]()'); 257 | 258 | i++; 259 | assert.equal(matches[i].type, 'method'); 260 | assert.equal(matches[i].ctor, undefined); 261 | assert.equal(matches[i].name, 'for'); 262 | assert.deepEqual(matches[i].params, ['let', 'arg', 'of', 'this.args']); 263 | assert.equal(matches[i].string, 'for()'); 264 | 265 | i++; 266 | assert.equal(matches[i].type, 'property'); 267 | assert.equal(matches[i].receiver, 'this'); 268 | assert.equal(matches[i].name, '_blah'); 269 | assert.equal(matches[i].value, '"blah"'); 270 | assert.equal(matches[i].string, 'this._blah'); 271 | 272 | i++; 273 | assert.equal(matches[i].type, 'class'); 274 | assert.equal(matches[i].ctor, 'Baz'); 275 | assert.equal(matches[i].name, 'Baz'); 276 | assert.equal(matches[i].extends, 'FooBar'); 277 | assert.equal(matches[i].string, 'new Baz()'); 278 | 279 | i++; 280 | assert.equal(matches[i].type, 'constructor'); 281 | assert.equal(matches[i].ctor, undefined); 282 | assert.equal(matches[i].name, 'constructor'); 283 | assert.deepEqual(matches[6].params, ['']); 284 | assert.equal(matches[i].string, 'constructor()'); 285 | 286 | i++; 287 | assert.equal(matches[i].type, 'property'); 288 | assert.equal(matches[i].receiver, 'this'); 289 | assert.equal(matches[i].name, 'options'); 290 | assert.equal(matches[i].value, 'options'); 291 | assert.equal(matches[i].string, 'this.options'); 292 | 293 | i++; 294 | assert.equal(matches[i].type, 'class'); 295 | assert.equal(matches[i].ctor, 'Lorem'); 296 | assert.equal(matches[i].name, 'Lorem'); 297 | assert.equal(matches[i].extends, undefined); 298 | assert.equal(matches[i].string, 'new Lorem()'); 299 | 300 | i++; 301 | assert.equal(matches[i].type, 'constructor'); 302 | assert.equal(matches[i].ctor, undefined); 303 | assert.equal(matches[i].name, 'constructor'); 304 | assert.deepEqual(matches[i].params, ['']); 305 | assert.equal(matches[i].string, 'constructor()'); 306 | 307 | i++; 308 | assert.equal(matches[i].type, 'property'); 309 | assert.equal(matches[i].receiver, 'this'); 310 | assert.equal(matches[i].name, 'options'); 311 | assert.equal(matches[i].value, 'options'); 312 | assert.equal(matches[i].string, 'this.options'); 313 | 314 | i++; 315 | assert.equal(matches[i].type, 'class'); 316 | assert.equal(matches[i].ctor, 'Ipsum'); 317 | assert.equal(matches[i].name, 'Ipsum'); 318 | assert.equal(matches[i].extends, 'mixin(Foo.Bar, Baz)'); 319 | assert.equal(matches[i].string, 'new Ipsum()'); 320 | 321 | i++; 322 | assert.equal(matches[i].type, 'constructor'); 323 | assert.equal(matches[i].ctor, undefined); 324 | assert.equal(matches[i].name, 'constructor'); 325 | assert.deepEqual(matches[i].params, ['']); 326 | assert.equal(matches[i].string, 'constructor()'); 327 | 328 | i++; 329 | assert.equal(matches[i].type, 'property'); 330 | assert.equal(matches[i].receiver, 'this'); 331 | assert.equal(matches[i].name, 'options'); 332 | assert.equal(matches[i].value, 'options'); 333 | assert.equal(matches[i].string, 'this.options'); 334 | cb(); 335 | }); 336 | }); 337 | }); 338 | }); 339 | --------------------------------------------------------------------------------