1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | Object.defineProperty(exports, "__esModule", { value: true });
|
16 | const babel = require("@babel/types");
|
17 | const ast_value_1 = require("../javascript/ast-value");
|
18 | const class_scanner_1 = require("../javascript/class-scanner");
|
19 | const esutil = require("../javascript/esutil");
|
20 | const esutil_1 = require("../javascript/esutil");
|
21 | const jsdoc = require("../javascript/jsdoc");
|
22 | const polymer_element_mixin_1 = require("./polymer-element-mixin");
|
23 | const polymer2_config_1 = require("./polymer2-config");
|
24 | class MixinVisitor {
|
25 | constructor(document, prototypeMemberFinder) {
|
26 | this.mixins = [];
|
27 | this._currentMixin = null;
|
28 | this._currentMixinNode = null;
|
29 | this._currentMixinFunction = null;
|
30 | this.warnings = [];
|
31 | this._document = document;
|
32 | this._prototypeMemberFinder = prototypeMemberFinder;
|
33 | }
|
34 | enterAssignmentExpression(node, _parent, path) {
|
35 | this.tryInitializeMixin(path, node.left);
|
36 | }
|
37 | enterFunctionDeclaration(node, _parent, path) {
|
38 | this.tryInitializeMixin(path, node.id);
|
39 | }
|
40 | leaveFunctionDeclaration(node, _parent) {
|
41 | this.clearOnLeave(node);
|
42 | }
|
43 | enterVariableDeclaration(node, _parent, path) {
|
44 | this.tryInitializeMixin(path, node.declarations[0].id);
|
45 | }
|
46 | leaveVariableDeclaration(node, _parent) {
|
47 | this.clearOnLeave(node);
|
48 | }
|
49 | tryInitializeMixin(nodePath, nameNode) {
|
50 | const comment = esutil.getBestComment(nodePath);
|
51 | if (comment === undefined) {
|
52 | return;
|
53 | }
|
54 | const docs = jsdoc.parseJsdoc(comment);
|
55 | if (!hasMixinFunctionDocTag(docs)) {
|
56 | return;
|
57 | }
|
58 | const node = nodePath.node;
|
59 | const name = ast_value_1.getIdentifierName(nameNode);
|
60 | const namespacedName = name ? ast_value_1.getNamespacedIdentifier(name, docs) : undefined;
|
61 | if (namespacedName === undefined) {
|
62 |
|
63 | return;
|
64 | }
|
65 | const sourceRange = this._document.sourceRangeForNode(node);
|
66 | const summaryTag = jsdoc.getTag(docs, 'summary');
|
67 | const mixin = new polymer_element_mixin_1.ScannedPolymerElementMixin({
|
68 | name: namespacedName,
|
69 | sourceRange,
|
70 | astNode: { language: 'js', node, containingDocument: this._document },
|
71 | statementAst: esutil.getCanonicalStatement(nodePath),
|
72 | description: docs.description,
|
73 | summary: (summaryTag && summaryTag.description) || '',
|
74 | privacy: esutil_1.getOrInferPrivacy(namespacedName, docs),
|
75 | jsdoc: docs,
|
76 | mixins: jsdoc.getMixinApplications(this._document, node, docs, this.warnings, nodePath)
|
77 | });
|
78 | this._currentMixin = mixin;
|
79 | this._currentMixinNode = node;
|
80 | this.mixins.push(this._currentMixin);
|
81 | }
|
82 | clearOnLeave(node) {
|
83 | if (this._currentMixinNode === node) {
|
84 | this._currentMixin = null;
|
85 | this._currentMixinNode = null;
|
86 | this._currentMixinFunction = null;
|
87 | }
|
88 | }
|
89 | enterFunctionExpression(node, _parent) {
|
90 | if (this._currentMixin != null && this._currentMixinFunction == null) {
|
91 | this._currentMixinFunction = node;
|
92 | }
|
93 | }
|
94 | enterArrowFunctionExpression(node, _parent) {
|
95 | if (this._currentMixin != null && this._currentMixinFunction == null) {
|
96 | this._currentMixinFunction = node;
|
97 | }
|
98 | }
|
99 | enterClassExpression(node, parent) {
|
100 | if (!babel.isReturnStatement(parent) &&
|
101 | !babel.isArrowFunctionExpression(parent)) {
|
102 | return;
|
103 | }
|
104 | this._handleClass(node);
|
105 | }
|
106 | enterClassDeclaration(node, _parent) {
|
107 | const comment = esutil.getAttachedComment(node) || '';
|
108 | const docs = jsdoc.parseJsdoc(comment);
|
109 | const isMixinClass = hasMixinClassDocTag(docs);
|
110 | if (isMixinClass) {
|
111 | this._handleClass(node);
|
112 | }
|
113 | }
|
114 | _handleClass(node) {
|
115 | const mixin = this._currentMixin;
|
116 | if (mixin == null) {
|
117 | return;
|
118 | }
|
119 | mixin.classAstNode = node;
|
120 | const classProperties = class_scanner_1.extractPropertiesFromClass(node, this._document);
|
121 | for (const prop of classProperties.values()) {
|
122 | mixin.addProperty(prop);
|
123 | }
|
124 | polymer2_config_1.getPolymerProperties(node, this._document)
|
125 | .forEach((p) => mixin.addProperty(p));
|
126 | esutil_1.getMethods(node, this._document).forEach((m) => mixin.addMethod(m));
|
127 | esutil_1.getStaticMethods(node, this._document)
|
128 | .forEach((m) => mixin.staticMethods.set(m.name, m));
|
129 | mixin.events = esutil.getEventComments(node);
|
130 |
|
131 |
|
132 |
|
133 |
|
134 | const name = ast_value_1.getIdentifierName(node.id);
|
135 | if (name !== undefined) {
|
136 | const prototypeMembers = this._prototypeMemberFinder.members.get(name);
|
137 | if (prototypeMembers !== undefined) {
|
138 | for (const [, property] of prototypeMembers.properties) {
|
139 | mixin.addProperty(property);
|
140 | }
|
141 | for (const [, method] of prototypeMembers.methods) {
|
142 | mixin.addMethod(method);
|
143 | }
|
144 | }
|
145 | }
|
146 | }
|
147 | }
|
148 | exports.MixinVisitor = MixinVisitor;
|
149 | function hasMixinFunctionDocTag(docs) {
|
150 |
|
151 | return (jsdoc.hasTag(docs, 'polymer') &&
|
152 | jsdoc.hasTag(docs, 'mixinFunction')) ||
|
153 | jsdoc.hasTag(docs, 'polymerMixin');
|
154 | }
|
155 | exports.hasMixinFunctionDocTag = hasMixinFunctionDocTag;
|
156 | function hasMixinClassDocTag(docs) {
|
157 |
|
158 | return (jsdoc.hasTag(docs, 'polymer') && jsdoc.hasTag(docs, 'mixinClass')) ||
|
159 | jsdoc.hasTag(docs, 'polymerMixinClass');
|
160 | }
|
161 | exports.hasMixinClassDocTag = hasMixinClassDocTag;
|
162 |
|
\ | No newline at end of file |