UNPKG

5.61 kBJavaScriptView Raw
1/*
2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15'use strict';
16
17const Decorated = require('./decorated');
18const ModelUtil = require('../modelutil');
19
20/**
21 * Property representing an attribute of a class declaration,
22 * either a Field or a Relationship.
23 *
24 * @class
25 * @memberof module:concerto-core
26 */
27class Property extends Decorated {
28
29 /**
30 * Create a Property.
31 * @param {ClassDeclaration} parent - the owner of this property
32 * @param {Object} ast - The AST created by the parser
33 * @throws {IllegalModelException}
34 */
35 constructor(parent, ast) {
36 super(parent.getModelFile(), ast);
37 this.parent = parent;
38 this.process();
39 this._isProperty = true;
40 }
41
42 /**
43 * Returns the owner of this property
44 * @return {ClassDeclaration} the parent class declaration
45 */
46 getParent() {
47 return this.parent;
48 }
49
50 /**
51 * Process the AST and build the model
52 * @throws {IllegalModelException}
53 * @private
54 */
55 process() {
56 super.process();
57
58 this.name = this.ast.id.name;
59 this.decorator = null;
60
61 if(!this.name) {
62 throw new Error('No name for type ' + this.ast );
63 }
64
65 if(this.ast.propertyType) {
66 this.type = this.ast.propertyType.name;
67 }
68 else {
69 this.type = null;
70 }
71 this.array = false;
72
73 if(this.ast.array) {
74 this.array = true;
75 }
76
77 if(this.ast.optional) {
78 this.optional = true;
79 }
80 else {
81 this.optional = false;
82 }
83 }
84
85 /**
86 * Validate the property
87 * @param {ClassDeclaration} classDecl the class declaration of the property
88 * @throws {IllegalModelException}
89 * @private
90 */
91 validate(classDecl) {
92 super.validate();
93
94 if(this.type) {
95 classDecl.getModelFile().resolveType( 'property ' + this.getFullyQualifiedName(), this.type);
96 }
97 }
98
99 /**
100 * Returns the name of a property
101 * @return {string} the name of this field
102 */
103 getName() {
104 return this.name;
105 }
106
107 /**
108 * Returns the type of a property
109 * @return {string} the type of this field
110 */
111 getType() {
112 return this.type;
113 }
114
115 /**
116 * Returns true if the field is optional
117 * @return {boolean} true if the field is optional
118 */
119 isOptional() {
120 return this.optional;
121 }
122
123 /**
124 * Returns the fully qualified type name of a property
125 * @return {string} the fully qualified type of this property
126 */
127 getFullyQualifiedTypeName() {
128 if(this.isPrimitive()) {
129 return this.type;
130 }
131
132 const parent = this.getParent();
133 if(!parent) {
134 throw new Error('Property ' + this.name + ' does not have a parent.');
135 }
136 const modelFile = parent.getModelFile();
137 if(!modelFile) {
138 throw new Error('Parent of property ' + this.name + ' does not have a ModelFile!');
139 }
140
141 const result = modelFile.getFullyQualifiedTypeName(this.type);
142 if(!result) {
143 throw new Error('Failed to find fully qualified type name for property ' + this.name + ' with type ' + this.type );
144 }
145
146 return result;
147 }
148
149 /**
150 * Returns the fully name of a property (ns + class name + property name)
151 * @return {string} the fully qualified name of this property
152 */
153 getFullyQualifiedName() {
154 return this.getParent().getFullyQualifiedName() + '.' + this.getName();
155 }
156
157 /**
158 * Returns the namespace of the parent of this property
159 * @return {string} the namespace of the parent of this property
160 */
161 getNamespace() {
162 return this.getParent().getNamespace();
163 }
164
165 /**
166 * Returns true if the field is declared as an array type
167 * @return {boolean} true if the property is an array type
168 */
169 isArray() {
170 return this.array;
171 }
172
173
174 /**
175 * Returns true if the field is declared as an enumerated value
176 * @return {boolean} true if the property is an enumerated value
177 */
178 isTypeEnum() {
179 if(this.isPrimitive()) {
180 return false;
181 }
182 else {
183 const type = this.getParent().getModelFile().getType(this.getType());
184 return type.isEnum();
185 }
186 }
187
188 /**
189 * Returns true if this property is a primitive type.
190 *@return {boolean} true if the property is a primitive type.
191 */
192 isPrimitive() {
193 return ModelUtil.isPrimitiveType(this.getType());
194 }
195
196 /**
197 * Alternative instanceof that is reliable across different module instances
198 * @see https://github.com/hyperledger/composer-concerto/issues/47
199 *
200 * @param {object} object - The object to test against
201 * @returns {boolean} - True, if the object is an instance of a Property
202 */
203 static [Symbol.hasInstance](object){
204 return typeof object !== 'undefined' && object !== null && Boolean(object._isProperty);
205 }
206}
207
208module.exports = Property;