zapier-platform-cli
Version:
The CLI for apps in the Zapier Developer Platform.
279 lines (222 loc) • 8.22 kB
JavaScript
;
var _ = require('lodash');
var path = require('path');
var _require = require('./misc'),
camelCase = _require.camelCase,
snakeCase = _require.snakeCase;
var _require2 = require('./files'),
readFile = _require2.readFile,
writeFile = _require2.writeFile,
ensureDir = _require2.ensureDir;
var _require3 = require('./display'),
printStarting = _require3.printStarting,
printDone = _require3.printDone;
var MIN_HELP_TEXT_LENGTH = 10;
var TEMPLATE_DIR = path.join(__dirname, '../../scaffold/convert');
// map v2 field types to v2 types
var typesMap = {
unicode: 'string',
textarea: 'text',
integer: 'integer',
float: 'number',
boolean: 'boolean',
datetime: 'datetime',
file: 'file',
password: 'password'
};
// map v2 step names to cli names
var stepNamesMap = {
triggers: 'trigger',
searches: 'search',
actions: 'create'
};
var renderTemplate = function renderTemplate(templateFile, templateContext) {
return readFile(templateFile).then(function (templateBuf) {
return templateBuf.toString();
}).then(function (template) {
return _.template(template, { interpolate: /<%=([\s\S]+?)%>/g })(templateContext);
});
};
var createFile = function createFile(content, fileName, dir) {
var destFile = path.join(dir, fileName);
return ensureDir(path.dirname(destFile)).then(function () {
return writeFile(destFile, content);
}).then(function () {
printStarting('Writing ' + fileName);
printDone();
});
};
var padHelpText = function padHelpText(text) {
var msg = '(help text must be at least ' + MIN_HELP_TEXT_LENGTH + ' characters)';
if (!_.isString(text)) {
return msg;
}
if (text.length < MIN_HELP_TEXT_LENGTH) {
return text + ' ' + msg;
}
return text;
};
var renderProp = function renderProp(key, value) {
return key + ': ' + value;
};
var quote = function quote(s) {
return '\'' + s + '\'';
};
var renderField = function renderField(definition, key) {
var type = definition.type && typesMap[definition.type.toLowerCase()] || 'string';
var props = [];
props.push(renderProp('key', quote(key)));
if (definition.label) {
props.push(renderProp('label', quote(definition.label)));
}
props.push(renderProp('helpText', quote(padHelpText(definition.help_text))));
props.push(renderProp('type', quote(type)));
props.push(renderProp('required', Boolean(definition.required)));
if (definition.placeholder) {
props.push(renderProp('placeholder', quote(definition.placeholder)));
}
props = props.map(function (s) {
return ' '.repeat(8) + s;
});
return ' {\n' + props.join(',\n') + '\n }';
};
var renderSampleField = function renderSampleField(def) {
var type = typesMap[def.type] || 'string';
if (def.label) {
return ' {\n key: ' + quote(def.key) + ',\n type: ' + quote(type) + ',\n label: ' + quote(def.label) + '\n }';
}
return ' {\n key: ' + quote(def.key) + ',\n type: ' + quote(type) + '\n }';
};
var renderSample = function renderSample(definition) {
var fields = _.map(definition.sample_result_fields, renderSampleField);
if (!fields.length) {
return '';
}
return ' outputFields: [\n' + fields.join(',\n') + '\n ]';
};
var renderBasicAuth = function renderBasicAuth(definition) {
var fields = _.map(definition.auth_fields, renderField);
var auth = '{\n type: \'basic\',\n test: {\n url: \'http://www.example.com/auth\' // TODO just an example, you\'ll need to supply the real URL\n },\n fields: [\n ' + fields.join(',\n') + '\n ]\n }';
return Promise.resolve(auth);
};
var renderOAuth2 = function renderOAuth2(definition) {
var authorizeUrl = _.get(definition, ['general', 'auth_urls', 'authorization_url'], 'TODO');
var accessTokenUrl = _.get(definition, ['general', 'auth_urls', 'access_token_url'], 'TODO');
var templateContext = {
AUTHORIZE_URL: authorizeUrl,
ACCESS_TOKEN_URL: accessTokenUrl
};
var templateFile = path.join(TEMPLATE_DIR, '/oauth2.template.js');
return renderTemplate(templateFile, templateContext);
};
var renderAuth = function renderAuth(definition) {
var authTypeMap = {
'Basic Auth': 'basic',
'OAuth V2': 'oauth2'
};
var type = authTypeMap[definition.general.auth_type];
if (type === 'basic') {
return renderBasicAuth(definition);
} else if (type === 'oauth2') {
return renderOAuth2(definition);
} else {
return Promise.resolve('{\n // TODO: complete auth settings\n }');
}
};
// convert a trigger, create or search
var renderStep = function renderStep(type, definition, key) {
var fields = _.map(definition.fields, renderField);
var sample = !_.isEmpty(definition.sample_result_fields) ? renderSample(definition) + ',\n' : '';
var url = definition.url ? quote(definition.url) + ',' : '\'http://example.com/api/' + key + '.json\', // TODO this is just an example';
var templateContext = {
KEY: snakeCase(key),
CAMEL: camelCase(key),
NOUN: _.capitalize(key),
LOWER_NOUN: key.toLowerCase(),
FIELDS: fields.join(',\n'),
SAMPLE: sample,
URL: url
};
var templateFile = path.join(TEMPLATE_DIR, '/' + type + '.template.js');
return renderTemplate(templateFile, templateContext);
};
// write a new trigger, create, or search
var writeStep = function writeStep(type, definition, key, newAppDir) {
var stepTypeMap = {
trigger: 'triggers',
search: 'searches',
create: 'creates'
};
var fileName = stepTypeMap[type] + '/' + snakeCase(key) + '.js';
return renderStep(type, definition, key).then(function (content) {
return createFile(content, fileName, newAppDir);
});
};
var renderIndex = function renderIndex(legacyApp) {
return renderAuth(legacyApp).then(function (auth) {
var importLines = [];
var dirMap = {
trigger: 'triggers',
search: 'searches',
create: 'creates'
};
var templateContext = {
AUTHENTICATION: auth,
TRIGGERS: '',
SEARCHES: '',
CREATES: ''
};
_.each(stepNamesMap, function (cliType, v2Type) {
var lines = [];
_.each(legacyApp[v2Type], function (definition, name) {
var varName = '' + camelCase(name) + _.capitalize(camelCase(cliType));
var requireFile = dirMap[cliType] + '/' + snakeCase(name);
importLines.push('const ' + varName + ' = require(\'./' + requireFile + '\');');
lines.push('[' + varName + '.key]: ' + varName + ',');
});
var section = dirMap[cliType].toUpperCase();
templateContext[section] = lines.join(',\n');
});
templateContext.REQUIRES = importLines.join('\n');
var templateFile = path.join(TEMPLATE_DIR, '/index.template.js');
return renderTemplate(templateFile, templateContext);
});
};
var writeIndex = function writeIndex(legacyApp, newAppDir) {
return renderIndex(legacyApp).then(function (content) {
return createFile(content, 'index.js', newAppDir);
});
};
var renderPackageJson = function renderPackageJson(legacyApp) {
var templateContext = {
NAME: _.kebabCase(legacyApp.general.title),
DESCRIPTION: legacyApp.general.description,
ZAPIER_CORE_VERSION: require('../../package.json').version
};
var templateFile = path.join(TEMPLATE_DIR, '/package.template.json');
return renderTemplate(templateFile, templateContext);
};
var writePackageJson = function writePackageJson(legacyApp, newAppDir) {
return renderPackageJson(legacyApp).then(function (content) {
return createFile(content, 'package.json', newAppDir);
});
};
var convertApp = function convertApp(legacyApp, newAppDir) {
var promises = [];
_.each(stepNamesMap, function (cliType, v2Type) {
_.each(legacyApp[v2Type], function (definition, key) {
promises.push(writeStep(cliType, definition, key, newAppDir));
});
});
promises.push(writeIndex(legacyApp, newAppDir));
promises.push(writePackageJson(legacyApp, newAppDir));
return Promise.all(promises);
};
module.exports = {
convertApp: convertApp,
renderAuth: renderAuth,
renderField: renderField,
renderSample: renderSample,
renderStep: renderStep,
renderTemplate: renderTemplate
};