UNPKG

13.1 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _debug = _interopRequireDefault(require("debug"));
9
10function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
12const debug = (0, _debug.default)('requireExportJsdoc');
13
14const createNode = function createNode() {
15 return {
16 props: {}
17 };
18};
19
20const getSymbolValue = function getSymbolValue(symbol) {
21 /* istanbul ignore next */
22 if (!symbol) {
23 /* istanbul ignore next */
24 return null;
25 }
26 /* istanbul ignore next */
27
28
29 if (symbol.type === 'literal') {
30 return symbol.value.value;
31 }
32 /* istanbul ignore next */
33
34
35 return null;
36};
37
38const getIdentifier = function getIdentifier(node, globals, scope, opts) {
39 if (opts.simpleIdentifier) {
40 // Type is Identier for noncomputed properties
41 const identifierLiteral = createNode();
42 identifierLiteral.type = 'literal';
43 identifierLiteral.value = {
44 value: node.name
45 };
46 return identifierLiteral;
47 }
48 /* istanbul ignore next */
49
50
51 const block = scope || globals; // As scopes are not currently supported, they are not traversed upwards recursively
52
53 if (block.props[node.name]) {
54 return block.props[node.name];
55 } // Seems this will only be entered once scopes added and entered
56
57 /* istanbul ignore next */
58
59
60 if (globals.props[node.name]) {
61 return globals.props[node.name];
62 }
63
64 return null;
65};
66
67let _createSymbol = null;
68
69const getSymbol = function getSymbol(node, globals, scope, opt) {
70 const opts = opt || {};
71
72 switch (node.type) {
73 case 'Identifier':
74 {
75 return getIdentifier(node, globals, scope, opts);
76 }
77
78 case 'MemberExpression':
79 {
80 const obj = getSymbol(node.object, globals, scope, opts);
81 const propertySymbol = getSymbol(node.property, globals, scope, {
82 simpleIdentifier: !node.computed
83 });
84 const propertyValue = getSymbolValue(propertySymbol);
85 /* istanbul ignore next */
86
87 if (obj && propertyValue && obj.props[propertyValue]) {
88 const block = obj.props[propertyValue];
89 return block;
90 }
91 /*
92 if (opts.createMissingProps && propertyValue) {
93 obj.props[propertyValue] = createNode();
94 return obj.props[propertyValue];
95 }
96 */
97
98 /* istanbul ignore next */
99
100
101 debug(`MemberExpression: Missing property ${node.property.name}`);
102 /* istanbul ignore next */
103
104 return null;
105 }
106
107 case 'ClassDeclaration':
108 case 'ClassExpression':
109 case 'FunctionExpression':
110 case 'FunctionDeclaration':
111 case 'ArrowFunctionExpression':
112 {
113 const val = createNode();
114 val.props.prototype = createNode();
115 val.props.prototype.type = 'object';
116 val.type = 'object';
117 val.value = node;
118 return val;
119 }
120
121 case 'AssignmentExpression':
122 {
123 return _createSymbol(node.left, globals, node.right, scope, opts);
124 }
125
126 case 'ClassBody':
127 {
128 const val = createNode();
129 node.body.forEach(method => {
130 val.props[method.key.name] = createNode();
131 val.props[method.key.name].type = 'object';
132 val.props[method.key.name].value = method.value;
133 });
134 val.type = 'object';
135 val.value = node;
136 return val;
137 }
138
139 case 'ObjectExpression':
140 {
141 const val = createNode();
142 val.type = 'object';
143 node.properties.forEach(prop => {
144 if (prop.type === 'ExperimentalSpreadProperty') {
145 return;
146 }
147
148 const propVal = getSymbol(prop.value, globals, scope, opts);
149 /* istanbul ignore next */
150
151 if (propVal) {
152 val.props[prop.key.name] = propVal;
153 }
154 });
155 return val;
156 }
157
158 case 'Literal':
159 {
160 const val = createNode();
161 val.type = 'literal';
162 val.value = node;
163 return val;
164 }
165 }
166 /* istanbul ignore next */
167
168
169 return null;
170};
171
172const createBlockSymbol = function createBlockSymbol(block, name, value, globals, isGlobal) {
173 block.props[name] = value;
174
175 if (isGlobal && globals.props.window && globals.props.window.special) {
176 globals.props.window.props[name] = value;
177 }
178};
179
180_createSymbol = function createSymbol(node, globals, value, scope, isGlobal) {
181 const block = scope || globals;
182 let symbol;
183
184 switch (node.type) {
185 case 'ClassDeclaration':
186 {
187 if (node.id && node.id.type === 'Identifier') {
188 return _createSymbol(node.id, globals, node, globals);
189 }
190
191 break;
192 }
193
194 case 'Identifier':
195 {
196 if (value) {
197 const valueSymbol = getSymbol(value, globals, block);
198 /* istanbul ignore next */
199
200 if (valueSymbol) {
201 createBlockSymbol(block, node.name, valueSymbol, globals, isGlobal);
202 return block.props[node.name];
203 }
204 /* istanbul ignore next */
205
206
207 debug('Identifier: Missing value symbol for %s', node.name);
208 } else {
209 createBlockSymbol(block, node.name, createNode(), globals, isGlobal);
210 return block.props[node.name];
211 }
212 /* istanbul ignore next */
213
214
215 break;
216 }
217
218 case 'MemberExpression':
219 {
220 symbol = getSymbol(node.object, globals, block);
221 const propertySymbol = getSymbol(node.property, globals, block, {
222 simpleIdentifier: !node.computed
223 });
224 const propertyValue = getSymbolValue(propertySymbol);
225
226 if (symbol && propertyValue) {
227 createBlockSymbol(symbol, propertyValue, getSymbol(value, globals, block), globals, isGlobal);
228 return symbol.props[propertyValue];
229 }
230 /* istanbul ignore next */
231
232
233 debug('MemberExpression: Missing symbol: %s', node.property.name);
234 break;
235 }
236
237 case 'FunctionDeclaration':
238 {
239 if (node.id && node.id.type === 'Identifier') {
240 return _createSymbol(node.id, globals, node, globals);
241 }
242
243 break;
244 }
245 }
246
247 return null;
248}; // Creates variables from variable definitions
249
250
251const initVariables = function initVariables(node, globals, opts) {
252 switch (node.type) {
253 case 'Program':
254 {
255 node.body.forEach(childNode => {
256 initVariables(childNode, globals, opts);
257 });
258 break;
259 }
260
261 case 'ExpressionStatement':
262 {
263 initVariables(node.expression, globals, opts);
264 break;
265 }
266
267 case 'VariableDeclaration':
268 {
269 node.declarations.forEach(declaration => {
270 // let and const
271 const symbol = _createSymbol(declaration.id, globals, null, globals);
272
273 if (opts.initWindow && node.kind === 'var' && globals.props.window) {
274 // If var, also add to window
275 globals.props.window.props[declaration.id.name] = symbol;
276 }
277 });
278 break;
279 }
280
281 case 'ExportNamedDeclaration':
282 {
283 if (node.declaration) {
284 initVariables(node.declaration, globals, opts);
285 }
286
287 break;
288 }
289 }
290}; // Populates variable maps using AST
291
292
293const mapVariables = function mapVariables(node, globals, opt, isExport) {
294 /* istanbul ignore next */
295 const opts = opt || {};
296 /* istanbul ignore next */
297
298 switch (node.type) {
299 case 'Program':
300 {
301 if (opts.ancestorsOnly) {
302 return false;
303 } else {
304 node.body.forEach(childNode => {
305 mapVariables(childNode, globals, opts);
306 });
307 }
308
309 break;
310 }
311
312 case 'ExpressionStatement':
313 {
314 mapVariables(node.expression, globals, opts);
315 break;
316 }
317
318 case 'AssignmentExpression':
319 {
320 _createSymbol(node.left, globals, node.right);
321
322 break;
323 }
324
325 case 'VariableDeclaration':
326 {
327 node.declarations.forEach(declaration => {
328 const isGlobal = opts.initWindow && node.kind === 'var' && globals.props.window;
329
330 const symbol = _createSymbol(declaration.id, globals, declaration.init, globals, isGlobal);
331
332 if (symbol && isExport) {
333 symbol.exported = true;
334 }
335 });
336 break;
337 }
338
339 case 'FunctionDeclaration':
340 {
341 /* istanbul ignore next */
342 if (node.id.type === 'Identifier') {
343 _createSymbol(node.id, globals, node, globals, true);
344 }
345
346 break;
347 }
348
349 case 'ExportDefaultDeclaration':
350 {
351 const symbol = _createSymbol(node.declaration, globals, node.declaration);
352
353 if (symbol) {
354 symbol.exported = true;
355 } else if (!node.id) {
356 globals.ANONYMOUS_DEFAULT = node.declaration;
357 }
358
359 break;
360 }
361
362 case 'ExportNamedDeclaration':
363 {
364 if (node.declaration) {
365 if (node.declaration.type === 'VariableDeclaration') {
366 mapVariables(node.declaration, globals, opts, true);
367 } else {
368 const symbol = _createSymbol(node.declaration, globals, node.declaration);
369 /* istanbul ignore next */
370
371
372 if (symbol) {
373 symbol.exported = true;
374 }
375 }
376 }
377
378 node.specifiers.forEach(specifier => {
379 mapVariables(specifier, globals, opts);
380 });
381 break;
382 }
383
384 case 'ExportSpecifier':
385 {
386 const symbol = getSymbol(node.local, globals, globals);
387 /* istanbul ignore next */
388
389 if (symbol) {
390 symbol.exported = true;
391 }
392
393 break;
394 }
395
396 case 'ClassDeclaration':
397 {
398 _createSymbol(node.id, globals, node.body, globals);
399
400 break;
401 }
402
403 default:
404 {
405 /* istanbul ignore next */
406 return false;
407 }
408 }
409
410 return true;
411};
412
413const findNode = function findNode(node, block, cache) {
414 let blockCache = cache || [];
415 /* istanbul ignore next */
416
417 if (!block || blockCache.includes(block)) {
418 return false;
419 }
420
421 blockCache = blockCache.slice();
422 blockCache.push(block);
423
424 if (block.type === 'object') {
425 if (block.value === node) {
426 return true;
427 }
428 }
429
430 const props = block.props;
431
432 for (const prop in props) {
433 /* istanbul ignore next */
434 if (Object.prototype.hasOwnProperty.call(props, prop)) {
435 const propval = props[prop]; // Only check node if it had resolvable value
436
437 if (propval && findNode(node, propval, blockCache)) {
438 return true;
439 }
440 }
441 }
442
443 return false;
444};
445
446const findExportedNode = function findExportedNode(block, node, cache) {
447 if (block.ANONYMOUS_DEFAULT === node) {
448 return true;
449 }
450 /* istanbul ignore next */
451
452
453 if (block === null) {
454 return false;
455 }
456
457 const blockCache = cache || [];
458 const props = block.props;
459
460 for (const key in props) {
461 /* istanbul ignore next */
462 if (Object.prototype.hasOwnProperty.call(props, key)) {
463 blockCache.push(props[key]);
464
465 if (props[key].exported) {
466 if (node === props[key].value || findNode(node, props[key].value)) {
467 return true;
468 }
469 } // No need to check `props[key]` for exported nodes as ESM
470 // exports are only global
471
472 }
473 }
474
475 return false;
476};
477
478const isNodeExported = function isNodeExported(node, globals, opt) {
479 if (opt.initModuleExports && globals.props.module && globals.props.module.props.exports) {
480 if (findNode(node, globals.props.module.props.exports)) {
481 return true;
482 }
483 }
484
485 if (opt.initWindow && globals.props.window) {
486 if (findNode(node, globals.props.window)) {
487 return true;
488 }
489 }
490
491 if (opt.esm && findExportedNode(globals, node)) {
492 return true;
493 }
494
495 return false;
496};
497
498const parseRecursive = function parseRecursive(node, globalVars, opts) {
499 // Iterate from top using recursion - stop at first processed node from top
500 if (node.parent) {
501 if (parseRecursive(node.parent, globalVars, opts)) {
502 return true;
503 }
504 }
505
506 return mapVariables(node, globalVars, opts);
507};
508
509const parse = function parse(ast, node, opt) {
510 /* istanbul ignore next */
511 const opts = opt || {
512 ancestorsOnly: false,
513 esm: true,
514 initModuleExports: true,
515 initWindow: true
516 };
517 const globalVars = createNode();
518
519 if (opts.initModuleExports) {
520 globalVars.props.module = createNode();
521 globalVars.props.module.props.exports = createNode();
522 globalVars.props.exports = globalVars.props.module.props.exports;
523 }
524
525 if (opts.initWindow) {
526 globalVars.props.window = createNode();
527 globalVars.props.window.special = true;
528 }
529
530 if (opts.ancestorsOnly) {
531 parseRecursive(node, globalVars, opts);
532 } else {
533 initVariables(ast, globalVars, opts);
534 mapVariables(ast, globalVars, opts);
535 }
536
537 return {
538 globalVars
539 };
540};
541
542const isExported = function isExported(node, parseResult, opt) {
543 return isNodeExported(node, parseResult.globalVars, opt);
544};
545
546var _default = {
547 isExported,
548 parse
549};
550exports.default = _default;
551module.exports = exports.default;
552//# sourceMappingURL=exportParser.js.map
\No newline at end of file