Format helpers.js (#205)

* Format helpers.js with prettier

* Adding docs on how to run prettier
This commit is contained in:
Manatsawin Hanmongkolchai 2017-09-16 00:12:09 +07:00 committed by Craig Peterson
parent 7c015bd56c
commit 4bffc37d15
5 changed files with 274 additions and 247 deletions

1
.gitignore vendored
View file

@ -10,3 +10,4 @@ docs/_site
powershell.log powershell.log
zones/ zones/
*.env *.env
node_modules

3
.prettierrc Normal file
View file

@ -0,0 +1,3 @@
tabWidth: 4
singleQuote: true
trailingComma: es5

View file

@ -60,7 +60,12 @@ is the Javascript file that defines `dnsconfig.js`'s functions like
`A()` and `MX()`. Look at the definition of A, MX and CAA for good `A()` and `MX()`. Look at the definition of A, MX and CAA for good
examples to use as a base. examples to use as a base.
Please add the function alphabetically with the others. Please add the function alphabetically with the others. Also, please run
[prettier](https://github.com/prettier/prettier) on the file to ensure
your code conforms to our coding standard:
npm install prettier
node_modules/.bin/prettier --write pkg/js/helpers.js
## Step 3: Search for `#rtype_variations` ## Step 3: Search for `#rtype_variations`

View file

@ -1,143 +1,153 @@
"use strict"; 'use strict';
var conf = { var conf = {
registrars: [], registrars: [],
dns_providers: [], dns_providers: [],
domains: [] domains: [],
}; };
var defaultArgs = []; var defaultArgs = [];
function initialize(){ function initialize() {
conf = { conf = {
registrars: [], registrars: [],
dns_providers: [], dns_providers: [],
domains: [] domains: [],
}; };
defaultArgs = []; defaultArgs = [];
} }
function NewRegistrar(name,type,meta) { function NewRegistrar(name, type, meta) {
if (type) { if (type) {
type == "MANUAL"; type == 'MANUAL';
} }
var reg = {name: name, type: type, meta: meta}; var reg = { name: name, type: type, meta: meta };
conf.registrars.push(reg); conf.registrars.push(reg);
return name; return name;
} }
function NewDnsProvider(name, type, meta) { function NewDnsProvider(name, type, meta) {
if ((typeof meta === 'object') && ('ip_conversions' in meta)) { if (typeof meta === 'object' && 'ip_conversions' in meta) {
meta.ip_conversions = format_tt(meta.ip_conversions) meta.ip_conversions = format_tt(meta.ip_conversions);
} }
var dsp = {name: name, type: type, meta: meta}; var dsp = { name: name, type: type, meta: meta };
conf.dns_providers.push(dsp); conf.dns_providers.push(dsp);
return name; return name;
} }
function newDomain(name,registrar) { function newDomain(name, registrar) {
return {name: name, registrar: registrar, meta:{}, records:[], dnsProviders: {}, defaultTTL: 0, nameservers:[]}; return {
name: name,
registrar: registrar,
meta: {},
records: [],
dnsProviders: {},
defaultTTL: 0,
nameservers: [],
};
} }
function processDargs(m, domain) { function processDargs(m, domain) {
// for each modifier, if it is a... // for each modifier, if it is a...
// function: call it with domain // function: call it with domain
// array: process recursively // array: process recursively
// object: merge it into metadata // object: merge it into metadata
if (_.isFunction(m)) { if (_.isFunction(m)) {
m(domain); m(domain);
} else if (_.isArray(m)) { } else if (_.isArray(m)) {
for (var j in m) { for (var j in m) {
processDargs(m[j], domain) processDargs(m[j], domain);
}
} else if (_.isObject(m)) {
_.extend(domain.meta,m);
} else {
throw "WARNING: domain modifier type unsupported: "+ typeof m + " Domain: "+ domain.name;
} }
} else if (_.isObject(m)) {
_.extend(domain.meta, m);
} else {
throw 'WARNING: domain modifier type unsupported: ' +
typeof m +
' Domain: ' +
domain.name;
}
} }
// D(name,registrar): Create a DNS Domain. Use the parameters as records and mods. // D(name,registrar): Create a DNS Domain. Use the parameters as records and mods.
function D(name,registrar) { function D(name, registrar) {
var domain = newDomain(name,registrar); var domain = newDomain(name, registrar);
for (var i = 0; i< defaultArgs.length; i++){ for (var i = 0; i < defaultArgs.length; i++) {
processDargs(defaultArgs[i],domain) processDargs(defaultArgs[i], domain);
}
for (var i = 2; i<arguments.length; i++) {
var m = arguments[i];
processDargs(m, domain)
} }
conf.domains.push(domain) for (var i = 2; i < arguments.length; i++) {
var m = arguments[i];
processDargs(m, domain);
}
conf.domains.push(domain);
} }
// DEFAULTS provides a set of default arguments to apply to all future domains. // DEFAULTS provides a set of default arguments to apply to all future domains.
// Each call to DEFAULTS will clear any previous values set. // Each call to DEFAULTS will clear any previous values set.
function DEFAULTS(){ function DEFAULTS() {
defaultArgs = []; defaultArgs = [];
for (var i = 0; i<arguments.length; i++) { for (var i = 0; i < arguments.length; i++) {
defaultArgs.push(arguments[i]); defaultArgs.push(arguments[i]);
} }
} }
// TTL(v): Set the TTL for a DNS record. // TTL(v): Set the TTL for a DNS record.
function TTL(v) { function TTL(v) {
if (_.isString(v)){ if (_.isString(v)) {
v = stringToDuration(v); v = stringToDuration(v);
} }
return function(r) { return function(r) {
r.ttl = v; r.ttl = v;
} };
} }
function stringToDuration(v){ function stringToDuration(v) {
var matches = v.match(/^(\d+)([smhdwny]?)$/); var matches = v.match(/^(\d+)([smhdwny]?)$/);
if (matches == null){ if (matches == null) {
throw v + " is not a valid duration string" throw v + ' is not a valid duration string';
} }
unit = "s" unit = 's';
if (matches[2]){ if (matches[2]) {
unit = matches[2] unit = matches[2];
} }
v = parseInt(matches[1]) v = parseInt(matches[1]);
var u = {"s":1, "m":60, "h":3600} var u = { s: 1, m: 60, h: 3600 };
u["d"] = u.h * 24 u['d'] = u.h * 24;
u["w"] = u.d * 7 u['w'] = u.d * 7;
u["n"] = u.d * 30 u['n'] = u.d * 30;
u["y"] = u.d * 365 u['y'] = u.d * 365;
v *= u[unit]; v *= u[unit];
return v return v;
} }
// DefaultTTL(v): Set the default TTL for the domain. // DefaultTTL(v): Set the default TTL for the domain.
function DefaultTTL(v) { function DefaultTTL(v) {
if (_.isString(v)){ if (_.isString(v)) {
v = stringToDuration(v); v = stringToDuration(v);
} }
return function(d) { return function(d) {
d.defaultTTL = v; d.defaultTTL = v;
} };
} }
function makeCAAFlag(value){ function makeCAAFlag(value) {
return function(record){ return function(record) {
record.caaflag |= value; record.caaflag |= value;
}; };
} }
// CAA_CRITICAL: Critical CAA flag // CAA_CRITICAL: Critical CAA flag
var CAA_CRITICAL = makeCAAFlag(1<<0); var CAA_CRITICAL = makeCAAFlag(1 << 0);
// DnsProvider("providerName", 0)
// DnsProvider("providerName", 0)
// nsCount of 0 means don't use or register any nameservers. // nsCount of 0 means don't use or register any nameservers.
// nsCount not provider means use all. // nsCount not provider means use all.
function DnsProvider(name, nsCount){ function DnsProvider(name, nsCount) {
if(typeof nsCount === 'undefined'){ if (typeof nsCount === 'undefined') {
nsCount = -1; nsCount = -1;
} }
return function(d) { return function(d) {
d.dnsProviders[name] = nsCount; d.dnsProviders[name] = nsCount;
} };
} }
// A(name,ip, recordModifiers...) // A(name,ip, recordModifiers...)
@ -151,18 +161,14 @@ var ALIAS = recordBuilder('ALIAS');
// CAA(name,tag,value, recordModifiers...) // CAA(name,tag,value, recordModifiers...)
var CAA = recordBuilder('CAA', { var CAA = recordBuilder('CAA', {
// TODO(tlim): It should be an error if value is not 0 or 128. // TODO(tlim): It should be an error if value is not 0 or 128.
args: [ args: [['name', _.isString], ['tag', _.isString], ['value', _.isString]],
['name', _.isString], transform: function(record, args, modifiers) {
['tag', _.isString],
['value', _.isString],
],
transform: function(record, args, modifiers){
record.name = args.name; record.name = args.name;
record.caatag = args.tag; record.caatag = args.tag;
record.target = args.value; record.target = args.value;
}, },
modifierNumber: function(record, value){ modifierNumber: function(record, value) {
record.caaflags |= value; record.caaflags |= value;
}, },
}); });
@ -182,7 +188,7 @@ var SRV = recordBuilder('SRV', {
['port', _.isNumber], ['port', _.isNumber],
['target', _.isString], ['target', _.isString],
], ],
transform: function(record, args, modifiers){ transform: function(record, args, modifiers) {
record.name = args.name; record.name = args.name;
record.srvpriority = args.priority; record.srvpriority = args.priority;
record.srvweight = args.weight; record.srvweight = args.weight;
@ -200,7 +206,7 @@ var TLSA = recordBuilder('TLSA', {
['matchingtype', _.isNumber], ['matchingtype', _.isNumber],
['target', _.isString], //recordBuilder needs a "target" argument ['target', _.isString], //recordBuilder needs a "target" argument
], ],
transform: function(record, args, modifiers){ transform: function(record, args, modifiers) {
record.name = args.name; record.name = args.name;
record.tlsausage = args.usage; record.tlsausage = args.usage;
record.tlsaselector = args.selector; record.tlsaselector = args.selector;
@ -219,20 +225,20 @@ var MX = recordBuilder('MX', {
['priority', _.isNumber], ['priority', _.isNumber],
['target', _.isString], ['target', _.isString],
], ],
transform: function(record, args, modifiers){ transform: function(record, args, modifiers) {
record.name = args.name; record.name = args.name;
record.mxpreference = args.priority; record.mxpreference = args.priority;
record.target = args.target; record.target = args.target;
}, },
}); });
function checkArgs(checks, args, desc){ function checkArgs(checks, args, desc) {
if (args.length < checks.length){ if (args.length < checks.length) {
throw(desc) throw desc;
} }
for (var i = 0; i< checks.length; i++){ for (var i = 0; i < checks.length; i++) {
if (!checks[i](args[i])){ if (!checks[i](args[i])) {
throw(desc+" - argument "+i+" is not correct type") throw desc + ' - argument ' + i + ' is not correct type';
} }
} }
} }
@ -243,51 +249,46 @@ var NS = recordBuilder('NS');
// NAMESERVER(name,target) // NAMESERVER(name,target)
function NAMESERVER(name, target) { function NAMESERVER(name, target) {
return function(d) { return function(d) {
d.nameservers.push({name: name, target: target}) d.nameservers.push({ name: name, target: target });
} };
} }
function format_tt(transform_table) { function format_tt(transform_table) {
// Turn [[low: 1, high: 2, newBase: 3], [low: 4, high: 5, newIP: 6]] // Turn [[low: 1, high: 2, newBase: 3], [low: 4, high: 5, newIP: 6]]
// into "1 ~ 2 ~ 3 ~; 4 ~ 5 ~ ~ 6" // into "1 ~ 2 ~ 3 ~; 4 ~ 5 ~ ~ 6"
var lines = [] var lines = [];
for (var i=0; i < transform_table.length; i++) { for (var i = 0; i < transform_table.length; i++) {
var ip = transform_table[i]; var ip = transform_table[i];
var newIP = ip.newIP; var newIP = ip.newIP;
if (newIP){ if (newIP) {
if(_.isArray(newIP)){ if (_.isArray(newIP)) {
newIP = _.map(newIP,function(i){return num2dot(i)}).join(",") newIP = _.map(newIP, function(i) {
}else{ return num2dot(i);
newIP = num2dot(newIP); }).join(',');
} else {
newIP = num2dot(newIP);
}
} }
} var newBase = ip.newBase;
var newBase = ip.newBase; if (newBase) {
if (newBase){ if (_.isArray(newBase)) {
if(_.isArray(newBase)){ newBase = _.map(newBase, function(i) {
newBase = _.map(newBase,function(i){return num2dot(i)}).join(",") return num2dot(i);
}else{ }).join(',');
newBase = num2dot(newBase); } else {
newBase = num2dot(newBase);
}
} }
var row = [num2dot(ip.low), num2dot(ip.high), newBase, newIP];
lines.push(row.join(' ~ '));
} }
var row = [ return lines.join(' ; ');
num2dot(ip.low),
num2dot(ip.high),
newBase,
newIP
]
lines.push(row.join(" ~ "))
}
return lines.join(" ; ")
} }
// IMPORT_TRANSFORM(translation_table, domain) // IMPORT_TRANSFORM(translation_table, domain)
var IMPORT_TRANSFORM = recordBuilder('IMPORT_TRANSFORM', { var IMPORT_TRANSFORM = recordBuilder('IMPORT_TRANSFORM', {
args: [ args: [['translation_table'], ['domain'], ['ttl', _.isNumber]],
['translation_table'], transform: function(record, args, modifiers) {
['domain'],
['ttl', _.isNumber],
],
transform: function(record, args, modifiers){
record.name = '@'; record.name = '@';
record.target = args.domain; record.target = args.domain;
record.meta['transform_table'] = format_tt(args.translation_table); record.meta['transform_table'] = format_tt(args.translation_table);
@ -297,21 +298,21 @@ var IMPORT_TRANSFORM = recordBuilder('IMPORT_TRANSFORM', {
// PURGE() // PURGE()
function PURGE(d) { function PURGE(d) {
d.KeepUnknown = false d.KeepUnknown = false;
} }
// NO_PURGE() // NO_PURGE()
function NO_PURGE(d) { function NO_PURGE(d) {
d.KeepUnknown = true d.KeepUnknown = true;
} }
/** /**
* @deprecated * @deprecated
*/ */
function getModifiers(args,start) { function getModifiers(args, start) {
var mods = []; var mods = [];
for (var i = start;i<args.length; i++) { for (var i = start; i < args.length; i++) {
mods.push(args[i]) mods.push(args[i]);
} }
return mods; return mods;
} }
@ -326,12 +327,9 @@ function getModifiers(args,start) {
* applied before this function. It should mutate the given record. * applied before this function. It should mutate the given record.
* @param {function=} opts.applyModifier Function to apply modifiers to the record * @param {function=} opts.applyModifier Function to apply modifiers to the record
*/ */
function recordBuilder(type, opts){ function recordBuilder(type, opts) {
opts = _.defaults({}, opts, { opts = _.defaults({}, opts, {
args: [ args: [['name', _.isString], ['target']],
['name', _.isString],
['target'],
],
transform: function(record, args, modifiers) { transform: function(record, args, modifiers) {
// record will have modifiers already applied // record will have modifiers already applied
@ -357,21 +355,30 @@ function recordBuilder(type, opts){
} }
_.extend(record.meta, mod); _.extend(record.meta, mod);
} else { } else {
throw "ERROR: Unknown modifier type"; throw 'ERROR: Unknown modifier type';
} }
} }
}, },
}); });
return function(){ return function() {
var parsedArgs = {}; var parsedArgs = {};
var modifiers = []; var modifiers = [];
if (arguments.length < opts.args.length) { if (arguments.length < opts.args.length) {
var argumentsList = opts.args.map(function(item){ var argumentsList = opts.args
return item[0]; .map(function(item) {
}).join(', '); return item[0];
throw type + " record requires " + opts.args.length + " arguments (" + argumentsList + "). Only " + arguments.length + " were supplied"; })
.join(', ');
throw type +
' record requires ' +
opts.args.length +
' arguments (' +
argumentsList +
'). Only ' +
arguments.length +
' were supplied';
return; return;
} }
@ -381,8 +388,11 @@ function recordBuilder(type, opts){
var value = arguments[i]; var value = arguments[i];
if (argDefinition.length > 1) { if (argDefinition.length > 1) {
// run validator if supplied // run validator if supplied
if(!argDefinition[1](value)){ if (!argDefinition[1](value)) {
throw type + " record " + argDefinition[0] + " argument validation failed"; throw type +
' record ' +
argDefinition[0] +
' argument validation failed';
} }
} }
parsedArgs[argDefinition[0]] = value; parsedArgs[argDefinition[0]] = value;
@ -393,7 +403,7 @@ function recordBuilder(type, opts){
modifiers.push(arguments[i]); modifiers.push(arguments[i]);
} }
return function(d){ return function(d) {
var record = { var record = {
type: type, type: type,
meta: {}, meta: {},
@ -412,30 +422,41 @@ function recordBuilder(type, opts){
/** /**
* @deprecated * @deprecated
*/ */
function addRecord(d,type,name,target,mods) { function addRecord(d, type, name, target, mods) {
// if target is number, assume ip address. convert it. // if target is number, assume ip address. convert it.
if (_.isNumber(target)) { if (_.isNumber(target)) {
target = num2dot(target); target = num2dot(target);
} }
var rec = {type: type, name: name, target: target, ttl:d.defaultTTL, priority: 0, meta:{}}; var rec = {
type: type,
name: name,
target: target,
ttl: d.defaultTTL,
priority: 0,
meta: {},
};
// for each modifier, decide based on type: // for each modifier, decide based on type:
// - Function: call is with the record as the argument // - Function: call is with the record as the argument
// - Object: merge it into the metadata // - Object: merge it into the metadata
// - Number: IF MX record assume it is priority // - Number: IF MX record assume it is priority
if (mods) { if (mods) {
for (var i = 0; i< mods.length; i++) { for (var i = 0; i < mods.length; i++) {
var m = mods[i] var m = mods[i];
if (_.isFunction(m)) { if (_.isFunction(m)) {
m(rec); m(rec);
} else if (_.isObject(m)) { } else if (_.isObject(m)) {
//convert transforms to strings //convert transforms to strings
if (m.transform && _.isArray(m.transform)){ if (m.transform && _.isArray(m.transform)) {
m.transform = format_tt(m.transform) m.transform = format_tt(m.transform);
} }
_.extend(rec.meta,m); _.extend(rec.meta, m);
_.extend(rec.meta,m); _.extend(rec.meta, m);
} else { } else {
console.log("WARNING: Modifier type unsupported:", typeof m, "(Skipping!)"); console.log(
'WARNING: Modifier type unsupported:',
typeof m,
'(Skipping!)'
);
} }
} }
} }
@ -445,69 +466,66 @@ function addRecord(d,type,name,target,mods) {
//ip conversion functions from http://stackoverflow.com/a/8105740/121660 //ip conversion functions from http://stackoverflow.com/a/8105740/121660
// via http://javascript.about.com/library/blipconvert.htm // via http://javascript.about.com/library/blipconvert.htm
function IP(dot) function IP(dot) {
{
var d = dot.split('.'); var d = dot.split('.');
return ((((((+d[0])*256)+(+d[1]))*256)+(+d[2]))*256)+(+d[3]); // prettier-ignore
return ((((((+d[0]) * 256) + (+d[1])) * 256) + (+d[2])) * 256) + (+d[3]);
} }
function num2dot(num) function num2dot(num) {
{ if (num === undefined) {
if(num === undefined){ return '';
return "";
} }
if (_.isString(num)){ if (_.isString(num)) {
return num return num;
} }
var d = num%256; var d = num % 256;
for (var i = 3; i > 0; i--) for (var i = 3; i > 0; i--) {
{ num = Math.floor(num / 256);
num = Math.floor(num/256); d = num % 256 + '.' + d;
d = num%256 + '.' + d;
} }
return d; return d;
} }
// Cloudflare aliases: // Cloudflare aliases:
// Meta settings for individual records. // Meta settings for individual records.
var CF_PROXY_OFF = {'cloudflare_proxy': 'off'}; // Proxy disabled. var CF_PROXY_OFF = { cloudflare_proxy: 'off' }; // Proxy disabled.
var CF_PROXY_ON = {'cloudflare_proxy': 'on'}; // Proxy enabled. var CF_PROXY_ON = { cloudflare_proxy: 'on' }; // Proxy enabled.
var CF_PROXY_FULL = {'cloudflare_proxy': 'full'}; // Proxy+Railgun enabled. var CF_PROXY_FULL = { cloudflare_proxy: 'full' }; // Proxy+Railgun enabled.
// Per-domain meta settings: // Per-domain meta settings:
// Proxy default off for entire domain (the default): // Proxy default off for entire domain (the default):
var CF_PROXY_DEFAULT_OFF = {'cloudflare_proxy_default': 'off'}; var CF_PROXY_DEFAULT_OFF = { cloudflare_proxy_default: 'off' };
// Proxy default on for entire domain: // Proxy default on for entire domain:
var CF_PROXY_DEFAULT_ON = {'cloudflare_proxy_default': 'on'}; var CF_PROXY_DEFAULT_ON = { cloudflare_proxy_default: 'on' };
// CUSTOM, PROVIDER SPECIFIC RECORD TYPES // CUSTOM, PROVIDER SPECIFIC RECORD TYPES
function _validateCloudFlareRedirect(value){ function _validateCloudFlareRedirect(value) {
if(!_.isString(value)){ if (!_.isString(value)) {
return false; return false;
} }
return value.indexOf(",") === -1; return value.indexOf(',') === -1;
} }
var CF_REDIRECT = recordBuilder("CF_REDIRECT", { var CF_REDIRECT = recordBuilder('CF_REDIRECT', {
args: [ args: [
["source", _validateCloudFlareRedirect], ['source', _validateCloudFlareRedirect],
["destination", _validateCloudFlareRedirect], ['destination', _validateCloudFlareRedirect],
], ],
transform: function(record, args, modifiers){ transform: function(record, args, modifiers) {
record.name = "@"; record.name = '@';
record.target = args.source + "," + args.destination; record.target = args.source + ',' + args.destination;
}, },
}); });
var CF_TEMP_REDIRECT = recordBuilder("CF_TEMP_REDIRECT", { var CF_TEMP_REDIRECT = recordBuilder('CF_TEMP_REDIRECT', {
args: [ args: [
["source", _validateCloudFlareRedirect], ['source', _validateCloudFlareRedirect],
["destination", _validateCloudFlareRedirect], ['destination', _validateCloudFlareRedirect],
], ],
transform: function(record, args, modifiers){ transform: function(record, args, modifiers) {
record.name = "@"; record.name = '@';
record.target = args.source + "," + args.destination; record.target = args.source + ',' + args.destination;
}, },
}); });

View file

@ -190,75 +190,75 @@ var _escData = map[string]*_escFile{
"/helpers.js": { "/helpers.js": {
local: "pkg/js/helpers.js", local: "pkg/js/helpers.js",
size: 14087, size: 14682,
modtime: 0, modtime: 0,
compressed: ` compressed: `
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 AAD//4nEKeNaOQAA
`, `,
}, },