@frontify/frontify-api
Version:
Simplifies asset management and UI pattern creation within Frontify.
294 lines (254 loc) • 7.83 kB
JavaScript
var path = require('path');
var globby = require('globby');
var rp = require('request-promise');
var extend = require('extend');
var _ = require('lodash');
var fs = require('mz/fs');
var humanize = require('humanize-string');
var auth = require('./auth');
var cache = require('./cache');
/*
* Get status of remote assets in Frontify
*/
function getRemoteStatus(meta) {
if (cache.get('patternlibrary')) {
return cache.get('patternlibrary');
}
var library = Promise.resolve().then(function () {
var options = auth(meta);
options.uri = '/v1/patterns/list/' + meta.project;
options.method = 'GET';
return rp(options).then(function(data) {
data.remote = true;
return data;
}).catch(function (err) {
throw new Error('Unable to get pattern library data. ' + err.message);
});
});
cache.set('patternlibrary', library);
return library;
}
function getGranularity(value) {
value = value.toUpperCase();
var granularities = [
'ATOM',
'MOLECULE',
'ORGANISM'
];
var granularity = _.find(granularities, function (granularity) {
return value.indexOf(granularity) !== -1;
});
if (!granularity) {
granularity = granularities[0];
}
return granularity;
}
function getStability(value) {
// according to https://www.npmjs.com/package/stability-badges
value = _.toString(value).toLowerCase();
var stability;
switch (value) {
case '0':
case 'deprecated':
stability = 0;
break;
case '1':
case 'experimental':
stability = 0;
break;
case '2':
case 'unstable':
stability = 0;
break;
case '3':
case 'stable':
stability = 0;
break;
case '4':
case 'frozen':
stability = 0;
break;
case '5':
case 'locked':
stability = 0;
break;
default:
stability = 1;
}
return stability;
}
function hasChanged(pattern, existing) {
var changed = true;
return changed;
}
function getPattern(meta, pattern) {
return Promise.resolve().then(function () {
var options = auth(meta);
if (!pattern) {
throw new Error('Please provide pattern data');
}
return getRemoteStatus(meta).then(function (data) {
pattern.mode = 'CODE';
var existing = null;
if (pattern.id) {
// check whether the pattern already exists
existing = _.find(data.patterns, function (item) {
return item.id == pattern.id;
});
if (!existing) {
throw new Error('The pattern id ' + pattern.id + ' does not exist in your pattern library');
}
}
else {
// check whether the api id (eg. path) already exists
existing = _.find(data.patterns, function (item) {
return item.id_api == pattern.id_api;
});
if (existing) {
// update
_.forIn(pattern.snippets, function (snippet, lang) {
if (existing.snippets[lang]) {
snippet.id = parseInt(existing.snippets[lang].id);
}
});
}
}
// skip pattern if it is unchanged
if(existing) {
pattern.id = parseInt(existing.id);
if(!hasChanged(pattern, existing)) {
return Promise.resolve(null);
}
}
return Promise.resolve(pattern);
});
});
}
function getSnippets(opts, assets) {
var promises = [];
_.forIn(assets, function (values, lang) {
promises.push(Promise.resolve().then(function () {
return Promise.all(values.map(function (value) {
return fs.readFile(path.resolve(opts.cwd, value), 'utf8');
})).then(function (data) {
return {lang: lang, code: indent(data.join('\n')), id_api: opts.idApi + '-' + lang};
});
}));
});
return Promise.all(promises).then(function (data) {
var snippets = {};
data.forEach(function (snippet) {
if (snippet.lang) {
snippets[snippet.lang] = snippet;
}
});
return snippets;
});
}
function indent(value) {
return value.replace(/\t/g, ' ');
}
function syncPatterns(meta, patterns) {
var opts = {};
opts.cwd = meta.cwd || '';
// reset library cache
cache.reset();
return globby(patterns, opts).then(function (files) {
if (files.length === 0) {
throw new Error('No files found');
}
return Promise.all(files.map(function (file) {
var filename = path.resolve(opts.cwd, file);
if (path.extname(filename) === '.json') {
return fs.readFile(filename, 'utf8').then(function (content) {
var localOpts = extend(true, {}, opts, {
idApi: _.kebabCase(file.substr(0, file.length - 5))
});
var def = JSON.parse(content);
var patternData = {
id: def.id || null,
id_api: localOpts.idApi,
name: def.name || humanize(path.basename(filename, '.json')),
description: def.description || '',
granularity: getGranularity(def.type),
stability: getStability(def.stability)
};
return getSnippets(localOpts, def.assets).then(function (snippets) {
patternData.snippets = snippets;
return getPattern(meta, patternData);
}).then(function (parent) {
var promises = [ parent ];
if (def.variations) {
_.forIn(def.variations, function (variation, key) {
var variationData = extend(true, {}, patternData, {
id: variation.id || null,
id_api: localOpts.idApi + '-' + _.kebabCase(key),
pattern: parent.id,
description: variation.description || '',
name: variation.name || patternData.name + ' ' + humanize(key)
});
promises.push(getSnippets(localOpts, variation.assets).then(function (snippets) {
variationData.snippets = snippets;
return getPattern(meta, variationData);
}));
});
}
return Promise.all(promises);
});
});
}
else if (path.extname(filename) === '.html') {
return fs.readFile(filename, 'utf8').then(function (content) {
var idApi = _.kebabCase(file.substr(0, file.length - 5));
var promises = [];
promises.push(getPattern(meta, {
name: humanize(path.basename(filename, '.html')),
id_api: idApi,
snippets: {
html: {
lang: 'html',
id_api: idApi + '-html',
code: indent(content)
}
}
}));
return Promise.all(promises);
}).catch(function (err) {
throw new Error('An error occured reading ' + filename + ' : ' + err.message);
});
}
}));
}).then(function(patternLists) {
var options = auth(meta);
options.uri = '/v1/patterns/';
options.method = 'POST';
var patterns = [];
patternLists.forEach(function (patternList) {
patterns = patterns.concat(patternList);
});
options.body = { patterns: patterns, project: meta.project };
if(meta.dryRun) {
return Promise.resolve(patterns);
}
return rp(options)
.then(function (data) {
if (!data.success) {
if (data.errors && data.errors.length > 0) {
throw new Error(data.errors.join('\n'));
}
else {
throw new Error(data);
}
}
return data.patterns;
})
.catch(function (err) {
throw new Error('Could not create/update your patterns. ' + err.message);
});
});
}
module.exports = {
syncPatterns: syncPatterns,
getRemoteStatus: getRemoteStatus,
getPattern: getPattern
};