UNPKG

4.49 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.parseParameterList = void 0;
4const function_tokenizer_1 = require("./function-tokenizer");
5/*
6 * Parses the parameter list of a function string, including ES6 class constructors.
7 *
8 * @param {string} source
9 * The source of a function to extract the parameter list from
10 *
11 * @return {Array<Parameter> | null}
12 * Returns an array of parameters, or `null` if no
13 * constructor was found for a class.
14 */
15function parseParameterList(source) {
16 const { next: _next, done } = (0, function_tokenizer_1.createTokenizer)(source);
17 const params = [];
18 let t = null;
19 nextToken();
20 while (!done()) {
21 switch (t.type) {
22 case 'class':
23 skipUntilConstructor();
24 // If we didn't find a constructor token, then we know that there
25 // are no dependencies in the defined class.
26 if (!isConstructorToken()) {
27 return null;
28 }
29 // Next token is the constructor identifier.
30 nextToken();
31 break;
32 case 'function':
33 const next = nextToken();
34 if (next.type === 'ident' || next.type === '*') {
35 // This is the function name or a generator star. Skip it.
36 nextToken();
37 }
38 break;
39 case '(':
40 // Start parsing parameter names.
41 parseParams();
42 break;
43 case ')':
44 // We're now out of the parameter list.
45 return params;
46 case 'ident':
47 // Likely a paren-less arrow function
48 // which can have no default args.
49 const param = { name: t.value, optional: false };
50 if (t.value === 'async') {
51 // Given it's the very first token, we can assume it's an async function,
52 // so skip the async keyword if the next token is not an equals sign, in which
53 // case it is a single-arg arrow func.
54 const next = nextToken();
55 if (next && next.type !== '=') {
56 break;
57 }
58 }
59 params.push(param);
60 return params;
61 /* istanbul ignore next */
62 default:
63 throw unexpected();
64 }
65 }
66 return params;
67 /**
68 * After having been placed within the parameter list of
69 * a function, parses the parameters.
70 */
71 function parseParams() {
72 // Current token is a left-paren
73 let param = { name: '', optional: false };
74 while (!done()) {
75 nextToken();
76 switch (t.type) {
77 case 'ident':
78 param.name = t.value;
79 break;
80 case '=':
81 param.optional = true;
82 break;
83 case ',':
84 params.push(param);
85 param = { name: '', optional: false };
86 break;
87 case ')':
88 if (param.name) {
89 params.push(param);
90 }
91 return;
92 /* istanbul ignore next */
93 default:
94 throw unexpected();
95 }
96 }
97 }
98 /**
99 * Skips until we reach the constructor identifier.
100 */
101 function skipUntilConstructor() {
102 while (!isConstructorToken() && !done()) {
103 nextToken(1 /* Dumb */);
104 }
105 }
106 /**
107 * Determines if the current token represents a constructor, and the next token after it is a paren
108 * @return {boolean}
109 */
110 function isConstructorToken() {
111 return t.type === 'ident' && t.value === 'constructor';
112 }
113 /**
114 * Advances the tokenizer and stores the previous token in history
115 */
116 function nextToken(flags = 0 /* None */) {
117 t = _next(flags);
118 return t;
119 }
120 /**
121 * Returns an error describing an unexpected token.
122 */
123 /* istanbul ignore next */
124 function unexpected() {
125 return new SyntaxError(`Parsing parameter list, did not expect ${t.type} token${t.value ? ` (${t.value})` : ''}`);
126 }
127}
128exports.parseParameterList = parseParameterList;
129//# sourceMappingURL=param-parser.js.map
\No newline at end of file