Skip to content

Commit c26176a

Browse files
author
Sébastien Van Eyck
committed
feat(patterns|INS-499): NPM library must parse a pattern folder to produce matching json files
1 parent a70bdb3 commit c26176a

6 files changed

+360
-0
lines changed

index.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
'use strict';
2+
3+
var main = require('./src/main');
4+
main.init('./patterns');

package.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "local-sync-frontify",
3+
"private": true,
4+
"version": "0.1.0",
5+
"scripts": {},
6+
"main": "./src/main.js",
7+
"dependencies": {
8+
"@frontify/frontify-api": "0.3.1",
9+
"lodash": "4.16.3",
10+
"cli-color": "1.1.0"
11+
},
12+
"devDependencies": {},
13+
"engines": {
14+
"node": ">=0.10.0"
15+
}
16+
}

src/files.service.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
'use strict';
2+
var fs = require('fs');
3+
var _ = require('lodash');
4+
5+
var Logger = require('./logger.service');
6+
7+
/**
8+
* Read directory synchronously
9+
* @param {String} path Path to read
10+
* @return {Array} Array of files
11+
*/
12+
function readDir(path) {
13+
var response;
14+
15+
try {
16+
return fs.readdirSync(path);
17+
}
18+
catch(err) {
19+
var error = "Error:" + err.message;
20+
Logger.error(error);
21+
return null;
22+
}
23+
}
24+
25+
/**
26+
* Check if file is a directory
27+
* @param {String} path Path to check
28+
* @param {Boolean} won't trigger an error if path is not found or not a directory
29+
* @return {Boolean}
30+
*/
31+
function checkIfDir(path, silent) {
32+
try {
33+
fs.accessSync(path, fs.F_OK);
34+
return fs.statSync(path).isDirectory();
35+
}
36+
catch(err) {
37+
if (silent) {
38+
return false;
39+
}
40+
var error = "Error: " + err.message;
41+
Logger.error(error);
42+
return false;
43+
}
44+
}
45+
46+
/**
47+
* Returns file extension
48+
* @param {String} path Path to parse
49+
* @return {String} File extension
50+
*/
51+
function getExtension(path) {
52+
return path.split('.').pop();
53+
}
54+
55+
module.exports = {
56+
readDir: readDir,
57+
checkIfDir: checkIfDir,
58+
getExtension: getExtension
59+
};

src/logger.service.js

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use strict';
2+
3+
var colors = require('cli-color');
4+
5+
/**
6+
* Log usecases => error, warning, info and success
7+
* @param {String} message [description]
8+
* @return {[type]} [description]
9+
*/
10+
function error(message) {
11+
return log('error', message);
12+
}
13+
function warning(message) {
14+
return log('warning', message);
15+
}
16+
function info(message) {
17+
return log('info', message);
18+
}
19+
function success(message) {
20+
return log('success', message);
21+
}
22+
23+
/**
24+
* Colorized console logger
25+
* @param {String} type Type of message
26+
* @param {String} message Message to display
27+
*/
28+
function log(type, message) {
29+
var color;
30+
switch(type) {
31+
case "error":
32+
color = "red";
33+
break;
34+
case "warning":
35+
color = "orange";
36+
break;
37+
case "info":
38+
color = "cyan";
39+
break;
40+
case "success":
41+
color = "green";
42+
break;
43+
default:
44+
color = "white";
45+
}
46+
console.log(colors[color](message));
47+
}
48+
49+
module.exports = {
50+
error: error,
51+
warning: warning,
52+
info: info,
53+
success: success
54+
}

src/main.js

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
'use strict';
2+
3+
var fs = require('fs');
4+
var _ = require('lodash');
5+
6+
var frontifyApi = require('@frontify/frontify-api');
7+
var frontifyPattern = require('@frontify/frontify-api/lib/core/patterns.js');
8+
9+
var Patterns = require('./patterns.service');
10+
var Files = require('./files.service');
11+
var Logger = require('./logger.service');
12+
13+
function init(patternsFolder) {
14+
generatePatterns(patternsFolder);
15+
}
16+
17+
18+
/**
19+
* Generate JSON files for found patterns
20+
*/
21+
function generatePatterns(patternsFolder) {
22+
walk(patternsFolder);
23+
var patternsList = Patterns.getList();
24+
if (!patternsList.length) {
25+
var error = "Error: no patterns found";
26+
Logger.error(error);
27+
return;
28+
}
29+
30+
// Create temp folder
31+
var tmpFolder = './tmp-frontify';
32+
if(!Files.checkIfDir(tmpFolder, true)) {
33+
fs.mkdirSync(tmpFolder);
34+
}
35+
// Create JSON files
36+
_.forEach(patternsList, function(pattern) {
37+
var patternAsString = JSON.stringify(pattern);
38+
fs.writeFileSync(tmpFolder + '/' + pattern.name + '.json', patternAsString, 'utf8');
39+
});
40+
41+
Logger.success('Created/updated ' + patternsList.length + ' patterns');
42+
}
43+
44+
/**
45+
* Walk through a directory and create patterns
46+
* @param {String} dir Directory to walk through
47+
* @param {Object} currentPattern Current pattern object
48+
* @param {Boolean} startPattern Indicate that current files should be patterns directories
49+
*/
50+
function walk(dir, currentPattern, startPattern) {
51+
// File is not a directory, we stop here
52+
if (!Files.checkIfDir(dir)) {
53+
var error = "Error: file " + dir + " is not a directory";
54+
Logger.error(error);
55+
return;
56+
}
57+
58+
// List files and run checks
59+
var paths = Files.readDir(dir);
60+
_.forEach(paths, function(path) {
61+
path = dir + '/' + path;
62+
if (Files.checkIfDir(path)) {
63+
if(startPattern) {
64+
currentPattern = Patterns.getOrCreate(path);
65+
walk(path, currentPattern);
66+
return;
67+
}
68+
69+
if (Patterns.checkType(path)) {
70+
walk(path, currentPattern, true);
71+
}
72+
} else {
73+
var fileExtension = Files.getExtension(path);
74+
if (Patterns.isAuthorizedAsset(fileExtension)) {
75+
Patterns.registerAsset(path, currentPattern);
76+
}
77+
}
78+
});
79+
}
80+
81+
module.exports = {
82+
init: init
83+
};

src/patterns.service.js

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
'use strict';
2+
3+
var _ = require('lodash');
4+
5+
var Files = require('./files.service');
6+
var Logger = require('./logger.service');
7+
8+
var patternsList = [];
9+
// Default pattern JSON structure
10+
var defaultPattern = {
11+
name: "",
12+
description: "",
13+
type: "",
14+
stability: "stable",
15+
assets: {
16+
html: [],
17+
css: []
18+
}
19+
};
20+
21+
/**
22+
* Get patterns list
23+
* @return {Array}
24+
*/
25+
function getList() {
26+
return patternsList;
27+
}
28+
29+
/**
30+
* Get type of pattern
31+
* @param {String} path Path to match
32+
* @return {String} Granularity type
33+
*/
34+
function getType(path) {
35+
var pattern = /(atoms|molecules|organisms)/i;
36+
var type = pattern.exec(path);
37+
if (type) {
38+
return type[1];
39+
}
40+
}
41+
42+
/**
43+
* Get pattern name
44+
* @param {String} path Path to retrieve name
45+
* @return {String} Extracted name
46+
*/
47+
function getName(path) {
48+
var pattern = /(?:\/([^\/]*)\/?)$/i;
49+
var name = pattern.exec(path);
50+
if (name) {
51+
return name[1];
52+
}
53+
}
54+
55+
/**
56+
* Check if type of granularity is authorized
57+
* @param {String} path Path to check
58+
* @return {Boolean}
59+
*/
60+
function checkType(path) {
61+
var pattern = /(atoms|molecules|organisms)/;
62+
return pattern.test(path);
63+
}
64+
65+
/**
66+
* Get pattern or create a new one
67+
* @param {String} path Path to retrieve name
68+
* @return {Object} Returns a pattern object
69+
*/
70+
function getOrCreate(path) {
71+
var UIPatternName = getName(path)
72+
if(isExistingPattern(UIPatternName)) {
73+
return patternsList[UIPatternName];
74+
}
75+
76+
if (UIPatternName) {
77+
var newUiPattern = _.cloneDeep(defaultPattern);
78+
newUiPattern.name = UIPatternName;
79+
newUiPattern.type = getType(path);
80+
patternsList.push(newUiPattern);
81+
return newUiPattern;
82+
}
83+
}
84+
85+
/**
86+
* Check for existing pattern name
87+
* @param {String} name Name to check
88+
* @return {Boolean}
89+
*/
90+
function isExistingPattern(name) {
91+
return _.findIndex(patternsList, {name: name}) !== -1;
92+
}
93+
94+
/**
95+
* Check if asset type is authorized
96+
* @param {String} ext Extension to check
97+
* @return {Boolean}
98+
*/
99+
function isAuthorizedAsset(ext) {
100+
var possibleAssetsExtensions = ['css', 'scss', 'html'];
101+
return _.indexOf(possibleAssetsExtensions, ext) !== -1;
102+
}
103+
104+
/**
105+
* Check if current pattern asset is already registered
106+
* @param {Object} currentPattern Pattern object
107+
* @param {String} assetType Type of asset
108+
* @param {String} path Asset path to check
109+
* @return {Boolean}
110+
*/
111+
function hasAsset(currentPattern, assetType, path) {
112+
return _.indexOf(currentPattern.assets[assetType], path) !== -1;
113+
}
114+
115+
/**
116+
* Register a new asset if not already done
117+
* @param {String} path Asset path
118+
* @param {Object} currentPattern Pattern Object
119+
*/
120+
function registerAsset(path, currentPattern) {
121+
var fileExtension = Files.getExtension(path);
122+
var overrideMessage = "Asset already registered, last declaration is taken into account";
123+
switch(fileExtension) {
124+
case 'css':
125+
case 'scss':
126+
hasAsset(currentPattern, 'css', fileExtension) ?
127+
Logger.warning(overrideMessage + path):
128+
currentPattern.assets.css.push(path);
129+
break;
130+
case 'html':
131+
hasAsset(currentPattern, 'html', fileExtension) ?
132+
Logger.warning(overrideMessage + path):
133+
currentPattern.assets.html.push(path);
134+
break;
135+
}
136+
}
137+
138+
module.exports = {
139+
checkType: checkType,
140+
getOrCreate: getOrCreate,
141+
isAuthorizedAsset: isAuthorizedAsset,
142+
registerAsset: registerAsset,
143+
getList: getList
144+
};

0 commit comments

Comments
 (0)