UNPKG

4.1 kBJavaScriptView Raw
1const
2 extend = require('extend'),
3 sgUtil = require('../util'),
4 CssAnalyzer = require('../analyser/CssAnalyzer'),
5 scalpel = require('scalpel').createParser();
6
7class PatternDataLoader {
8
9 constructor(conf) {
10
11 const
12 regex = /\[block\]([^\[]+)\[element\]([^\[]+)\[modifier\]/g,
13 bemPattern = conf.get('bemPattern', '[block]__[element]--[modifier]'),
14 [, blockSeparator, modifierSeperator] = regex.exec(bemPattern);
15
16 this.cssSource = conf.get('cssSource');
17 this.viewerDest = `${conf.get('viewerDest')}/css`;
18 this.viewerRootPath = conf.get('app.viewerRootPath');
19 this.dest = conf.get('dest');
20 this.globOptions = conf.get('globOptions');
21 this.blockSeparator = blockSeparator;
22 this.modifierSeperator = modifierSeperator;
23
24 this.CssAnalyzer = new CssAnalyzer(this.cssSource, this.globOptions);
25 }
26
27 aggregateData() {
28
29 this.css = this.CssAnalyzer.getAnalysis();
30
31 let update = false;
32
33 if (this.CssAnalyzer.getVersion() !== this.cssAnalyzerVersion) {
34 this.cssAnalyzerVersion = this.CssAnalyzer.getVersion();
35 update = true;
36 }
37
38 if (update === true) {
39 this.collectVersions();
40 }
41 }
42
43 getVersions() {
44 this.aggregateData();
45 return this.versions;
46 }
47
48 getAssignedVersions(modifiers) {
49 const versions = this.getVersions();
50 return modifiers.reduce((assignedVersions, modifier) => {
51 const
52 [blockName] = modifier['blockIdentifier'].split('.'),
53 {[blockName]: version = []} = versions;
54
55 assignedVersions[modifier['blockIdentifier']] = version;
56 return assignedVersions;
57 }, {});
58 }
59
60 getData(file) {
61
62 const
63 {filename, cssFiles, modifiers, warnOnMissingDataFile} = file,
64 data = sgUtil.readRelatedData(filename, warnOnMissingDataFile),
65 description = sgUtil.readRelatedMarkdown(filename);
66
67 extend(true, data, {
68 app: {cssFiles},
69 locals: {versions: this.getAssignedVersions(modifiers)},
70 description
71 });
72
73 return data;
74 }
75
76 parseSelector(selector) {
77 try {
78 return scalpel.parse(selector).map((parsed) => {
79 const {body = []} = parsed;
80 parsed.body = body.map((item) => {
81 item.selectorString = selector;
82 return item;
83 });
84 return parsed;
85 });
86 }
87 catch (error) {
88 sgUtil.log(`${error} in ${selector}`, 'warn');
89 }
90 return false;
91 }
92
93 flatten(array, value = []) {
94 return array.concat(value);
95 }
96
97 collectVersions() {
98
99 const versions = {};
100
101 this.css.selectors.values
102 .map(this.parseSelector)
103 .reduce((selectors, selector = []) => selectors.concat(selector), [])
104 .filter((selector) => selector !== false && selector.type === 'selector')
105 .reduce((selectors, selector) => selectors.concat(selector.body), [])
106 .filter((selector) => selector !== false && selector.type === 'classSelector')
107 .filter((selector, index, selectors) => selectors.findIndex((item) => item.name === selector.name) === index)
108 .map((selector, index) => {
109 const
110 {name, selectorString} = selector,
111 [blockElement, modifier = '', errorModifier = false] = name.split(this.modifierSeperator),
112 [block, element = '', errorBlock = false] = blockElement.split(this.blockSeparator),
113 modifierClass = modifier !== '' ? name : '',
114 commentData = this.css.getCommentData(selectorString);
115
116 if (errorModifier || errorBlock) {
117 sgUtil.log(`${this.constructor.name}: '.${name}' is not following BEM naming conventions.`, 'error');
118 }
119 return {index, block, element, modifier, blockElement, modifierClass, selectorString, commentData};
120 })
121 .sort((a, b) => a.element === b.element ? a.index - b.index : (a.element < b.element ? -1 : 1))
122 .map((version) => {
123 const {blockElement} = version;
124 if (versions[blockElement] === undefined) {
125 versions[blockElement] = [];
126 }
127 versions[blockElement].push(version);
128 });
129
130 this.versions = versions;
131 }
132}
133
134module.exports = PatternDataLoader;
\No newline at end of file