Skip to content
This repository was archived by the owner on Feb 4, 2018. It is now read-only.

Commit aa08471

Browse files
authored
Merge pull request #104 from bem-sdk/refactor/test
Refactor tests
2 parents 44eab42 + 541e940 commit aa08471

24 files changed

+714
-632
lines changed

index.js

Lines changed: 1 addition & 403 deletions
Large diffs are not rendered by default.

lib/entity-name.js

Lines changed: 391 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,391 @@
1+
'use strict';
2+
3+
const util = require('util');
4+
5+
const stringifyEntity = require('@bem/naming').stringify;
6+
const deprecate = require('depd')(require('../package.json').name);
7+
8+
const EntityTypeError = require('./entity-type-error');
9+
10+
/**
11+
* Enum for types of BEM entities.
12+
*
13+
* @readonly
14+
* @enum {string}
15+
*/
16+
const TYPES = {
17+
BLOCK: 'block',
18+
BLOCK_MOD: 'blockMod',
19+
ELEM: 'elem',
20+
ELEM_MOD: 'elemMod'
21+
};
22+
23+
class BemEntityName {
24+
/**
25+
* @param {BemSDK.EntityName.Options} obj — representation of entity name.
26+
*/
27+
constructor(obj) {
28+
if (!obj.block) {
29+
throw new EntityTypeError(obj, 'the field `block` is undefined');
30+
}
31+
32+
const data = this._data = { block: obj.block };
33+
34+
obj.elem && (data.elem = obj.elem);
35+
36+
const modObj = obj.mod;
37+
const modName = (typeof modObj === 'string' ? modObj : modObj && modObj.name) || obj.modName;
38+
const hasModVal = modObj && modObj.hasOwnProperty('val') || obj.hasOwnProperty('modVal');
39+
40+
if (modName) {
41+
data.mod = {
42+
name: modName,
43+
val: hasModVal ? modObj && modObj.val || obj.modVal : true
44+
};
45+
} else if (modObj || hasModVal) {
46+
throw new EntityTypeError(obj, 'the field `mod.name` is undefined');
47+
}
48+
49+
this.__isBemEntityName__ = true;
50+
}
51+
52+
/**
53+
* Returns the name of block to which this entity belongs.
54+
*
55+
* @example
56+
* const BemEntityName = require('@bem/entity-name');
57+
* const name = new BemEntityName({ block: 'button' });
58+
*
59+
* name.block; // button
60+
*
61+
* @returns {string} name of entity block.
62+
*/
63+
get block() { return this._data.block; }
64+
65+
/**
66+
* Returns the element name of this entity.
67+
*
68+
* If entity is not element or modifier of element then returns empty string.
69+
*
70+
* @example
71+
* const BemEntityName = require('@bem/entity-name');
72+
* const name = new BemEntityName({ block: 'button', elem: 'text' });
73+
*
74+
* name.elem; // text
75+
*
76+
* @returns {?string} - name of entity element.
77+
*/
78+
get elem() { return this._data.elem; }
79+
80+
/**
81+
* Returns the modifier of this entity.
82+
*
83+
* Important: If entity is not a modifier then returns `undefined`.
84+
*
85+
* @example
86+
* const BemEntityName = require('@bem/entity-name');
87+
*
88+
* const blockName = new BemEntityName({ block: 'button' });
89+
* const modName = new BemEntityName({ block: 'button', mod: 'disabled' });
90+
*
91+
* modName.mod; // { name: 'disabled', val: true }
92+
* blockName.mod; // undefined
93+
*
94+
* @returns {?BemSDK.EntityName.ModifierRepresentation} - entity modifier.
95+
*/
96+
get mod() { return this._data.mod; }
97+
98+
/**
99+
* Returns the modifier name of this entity.
100+
*
101+
* If entity is not modifier then returns `undefined`.
102+
*
103+
* @returns {?string} - entity modifier name.
104+
* @deprecated use {@link BemEntityName#mod.name}
105+
*/
106+
get modName() {
107+
deprecate(`modName is kept just for compatibility and can be dropped in the future. Use mod.name instead in ${this.inspect()} at`);
108+
109+
return this.mod && this.mod.name;
110+
}
111+
112+
/**
113+
* Returns the modifier value of this entity.
114+
*
115+
* If entity is not modifier then returns `undefined`.
116+
*
117+
* @returns {?(string|true)} - entity modifier name.
118+
* @deprecated use {@link BemEntityName#mod.val}
119+
*/
120+
get modVal() {
121+
deprecate(`modVal is kept just for compatibility and can be dropped in the future. Use mod.val instead in ${this.inspect()} at`);
122+
123+
return this.mod && this.mod.val;
124+
}
125+
126+
/**
127+
* Returns id for this entity.
128+
*
129+
* Important: should only be used to determine uniqueness of entity.
130+
*
131+
* If you want to get string representation in accordance with the provisions naming convention
132+
* you should use `@bem/naming` package.
133+
*
134+
* @example
135+
* const BemEntityName = require('@bem/entity-name');
136+
* const name = new BemEntityName({ block: 'button', mod: 'disabled' });
137+
*
138+
* name.id; // button_disabled
139+
*
140+
* @returns {string} - id of entity.
141+
*/
142+
get id() {
143+
if (this._id) { return this._id; }
144+
145+
this._id = stringifyEntity(this._data);
146+
147+
return this._id;
148+
}
149+
150+
/**
151+
* Returns type for this entity.
152+
*
153+
* @example <caption>type of element</caption>
154+
* const BemEntityName = require('@bem/entity-name');
155+
* const name = new BemEntityName({ block: 'button', elem: 'text' });
156+
*
157+
* name.type; // elem
158+
*
159+
* @example <caption>type of element modifier</caption>
160+
* const BemEntityName = require('@bem/entity-name');
161+
* const name = new BemEntityName({ block: 'menu', elem: 'item', mod: 'current' });
162+
*
163+
* name.type; // elemMod
164+
*
165+
* @returns {string} - type of entity. One of 'block', 'elem', 'blockMod', 'elemMod'.
166+
*/
167+
get type() {
168+
if (this._type) { return this._type; }
169+
170+
const data = this._data;
171+
const isMod = data.mod;
172+
173+
this._type = data.elem
174+
? isMod ? TYPES.ELEM_MOD : TYPES.ELEM
175+
: isMod ? TYPES.BLOCK_MOD : TYPES.BLOCK;
176+
177+
return this._type;
178+
}
179+
180+
/**
181+
* Determines whether modifier simple or not
182+
*
183+
* @example <caption>simple mod</caption>
184+
* const BemEntityName = require('@bem/entity-name');
185+
* const name = new BemEntityName({ block: 'button', mod: { name: 'theme' } });
186+
*
187+
* name.isSimpleMod(); // true
188+
*
189+
* @example <caption>mod with value</caption>
190+
* const BemEntityName = require('@bem/entity-name');
191+
* const name = new BemEntityName({ block: 'button', mod: { name: 'theme', val: 'normal' } });
192+
*
193+
* name.isSimpleMod(); // false
194+
*
195+
* @example <caption>block</caption>
196+
* const BemEntityName = require('@bem/entity-name');
197+
* const name = new BemEntityName({ block: 'button' });
198+
*
199+
* name.isSimpleMod(); // null
200+
*
201+
* @returns {(boolean|null)}
202+
*/
203+
isSimpleMod() {
204+
return this.mod ? this.mod.val === true : null;
205+
}
206+
207+
/**
208+
* Returns string representing the entity name.
209+
*
210+
* Important: If you want to get string representation in accordance with the provisions naming convention
211+
* you should use `@bem/naming` package.
212+
*
213+
* @example
214+
* const BemEntityName = require('@bem/entity-name');
215+
* const name = new BemEntityName({ block: 'button', mod: 'focused' });
216+
*
217+
* name.toString(); // button_focused
218+
*
219+
* @returns {string}
220+
*/
221+
toString() { return this.id; }
222+
223+
/**
224+
* Returns object representing the entity name. Is needed for debug in Node.js.
225+
*
226+
* In some browsers `console.log()` calls `valueOf()` on each argument.
227+
* This method will be called to get custom string representation of the object.
228+
*
229+
* The representation object contains only `block`, `elem` and `mod` fields
230+
* without private and deprecated fields (`modName` and `modVal`).
231+
*
232+
* @example
233+
* const BemEntityName = require('@bem/entity-name');
234+
* const name = new BemEntityName({ block: 'button', mod: 'focused' });
235+
*
236+
* name.valueOf();
237+
*
238+
* // ➜ { block: 'button', mod: { name: 'focused', value: true } }
239+
*
240+
* @returns {BemSDK.EntityName.StrictRepresentation}
241+
*/
242+
valueOf() { return this._data; }
243+
244+
/**
245+
* Returns object representing the entity name. Is needed for debug in Node.js.
246+
*
247+
* In Node.js, `console.log()` calls `util.inspect()` on each argument without a formatting placeholder.
248+
* This method will be called to get custom string representation of the object.
249+
*
250+
* The representation object contains only `block`, `elem` and `mod` fields
251+
* without private and deprecated fields (`modName` and `modVal`).
252+
*
253+
* @example
254+
* const BemEntityName = require('@bem/entity-name');
255+
* const name = new BemEntityName({ block: 'button' });
256+
*
257+
* console.log(name); // BemEntityName { block: 'button' }
258+
*
259+
* @param {number} depth — tells inspect how many times to recurse while formatting the object.
260+
* @param {object} options — An optional `options` object may be passed
261+
* that alters certain aspects of the formatted string.
262+
*
263+
* @returns {string}
264+
*/
265+
inspect(depth, options) {
266+
const stringRepresentation = util.inspect(this._data, options);
267+
268+
return `BemEntityName ${stringRepresentation}`;
269+
}
270+
271+
/**
272+
* Return raw data for `JSON.stringify()`.
273+
*
274+
* @returns {BemSDK.EntityName.StrictRepresentation}
275+
*/
276+
toJSON() {
277+
return this._data;
278+
}
279+
280+
/**
281+
* Determines whether specified entity is the deepEqual entity.
282+
*
283+
* @example
284+
* const BemEntityName = require('@bem/entity-name');
285+
*
286+
* const inputName = new BemEntityName({ block: 'input' });
287+
* const buttonName = new BemEntityName({ block: 'button' });
288+
*
289+
* inputName.isEqual(buttonName); // false
290+
* buttonName.isEqual(buttonName); // true
291+
*
292+
* @param {BemEntityName} entityName - the entity to compare.
293+
* @returns {boolean} - A Boolean indicating whether or not specified entity is the deepEqual entity.
294+
*/
295+
isEqual(entityName) {
296+
return entityName && (this.id === entityName.id);
297+
}
298+
299+
/**
300+
* Determines whether specified entity belongs to this.
301+
*
302+
* @example
303+
* const BemEntityName = require('@bem/entity-name');
304+
*
305+
* const buttonName = new BemEntityName({ block: 'button' });
306+
* const buttonTextName = new BemEntityName({ block: 'button', elem: 'text' });
307+
* const buttonTextBoldName = new BemEntityName({ block: 'button', elem: 'text', mod: 'bold' });
308+
*
309+
* buttonTextName.belongsTo(buttonName); // true
310+
* buttonName.belongsTo(buttonTextName); // false
311+
* buttonTextBoldName.belongsTo(buttonTextName); // true
312+
* buttonTextBoldName.belongsTo(buttonName); // false
313+
*
314+
* @param {BemEntityName} entityName - the entity to compare.
315+
*
316+
* @returns {boolean}
317+
*/
318+
belongsTo(entityName) {
319+
if (entityName.block !== this.block) { return false; }
320+
321+
return entityName.type === TYPES.BLOCK && (this.type === TYPES.BLOCK_MOD || this.type === TYPES.ELEM)
322+
|| entityName.elem === this.elem && (entityName.type === TYPES.ELEM && this.type === TYPES.ELEM_MOD);
323+
}
324+
325+
/**
326+
* Determines whether specified entity is instance of BemEntityName.
327+
*
328+
* @example
329+
* const BemEntityName = require('@bem/entity-name');
330+
*
331+
* const entityName = new BemEntityName({ block: 'input' });
332+
*
333+
* BemEntityName.isBemEntityName(entityName); // true
334+
* BemEntityName.isBemEntityName({}); // false
335+
*
336+
* @param {*} entityName - the entity to check.
337+
* @returns {boolean} A Boolean indicating whether or not specified entity is instance of BemEntityName.
338+
*/
339+
static isBemEntityName(entityName) {
340+
return entityName && entityName.__isBemEntityName__;
341+
}
342+
343+
/**
344+
* Creates BemEntityName instance by any object representation.
345+
*
346+
* @example
347+
* const BemEntityName = require('@bem/entity-name');
348+
*
349+
* BemEntityName.create({ block: 'my-button', mod: 'theme', val: 'red' });
350+
* BemEntityName.create({ block: 'my-button', modName: 'theme', modVal: 'red' });
351+
* // → BemEntityName { block: 'my-button', mod: { name: 'theme', val: 'red' } }
352+
*
353+
* @param {(BemSDK.EntityName.NonStrictRepresentation|string)} obj — representation of entity name.
354+
* @returns {BemEntityName} An object representing entity name.
355+
*/
356+
static create(obj) {
357+
if (BemEntityName.isBemEntityName(obj)) {
358+
return obj;
359+
}
360+
361+
if (typeof obj === 'string') {
362+
obj = { block: obj };
363+
}
364+
365+
const data = { block: obj.block };
366+
const mod = obj.mod;
367+
368+
obj.elem && (data.elem = obj.elem);
369+
370+
if (mod || obj.modName) {
371+
const isString = typeof mod === 'string';
372+
const modName = (isString ? mod : mod && mod.name) || obj.modName;
373+
const modObj = !isString && mod || obj;
374+
const hasModVal = modObj.hasOwnProperty('val') || obj.hasOwnProperty('modVal');
375+
376+
data.mod = {
377+
name: modName,
378+
val: hasModVal ? modObj.val || obj.modVal : true
379+
};
380+
}
381+
382+
return new BemEntityName(data);
383+
}
384+
}
385+
386+
module.exports = BemEntityName;
387+
388+
// TypeScript imports the `default` property for
389+
// an ES2015 default import (`import BemEntityName from '@bem/entity-name'`)
390+
// See: https://github.com/Microsoft/TypeScript/issues/2242#issuecomment-83694181
391+
module.exports.default = BemEntityName;

0 commit comments

Comments
 (0)