UNPKG

grunt-gss

Version:

Save your Google Spreadsheets as CSV or JSON.

143 lines (119 loc) 4.33 kB
module.exports = (grunt) -> csv2json = require './lib/csv2json' done = undefined extend = require 'deep-extend' google = require 'googleapis' http = require 'http' open = require 'open' request = require 'request' toType = (o) -> ({}).toString.call(o).match(/\s([a-zA-Z]+)/)[1].toLowerCase() getCsv = (id, secret, fileId, gid, callback) -> getAuth id, secret, 'http://localhost:4477/', 'offline', 'https://www.googleapis.com/auth/drive.readonly', (auth) -> getFile auth, fileId, (file) -> getSheet auth, file, gid, callback _sheets = {} getSheet = (auth, file, gid, callback) -> grunt.verbose.write 'export...' uri = file['exportLinks']['text/csv'] + '&gid=' + gid if not _sheets[uri] headers = Authorization: "Bearer #{auth.credentials.access_token}" request {uri, headers}, (err, sheet) -> if err and err.message grunt.log.error err.message done false else callback _sheets[uri] = sheet.body else callback _sheets[uri] _files = {} getFile = (auth, fileId, callback) -> grunt.verbose.write 'drive...' if not _files[fileId] drive = google.drive {version: 'v2', auth} drive.files.get {fileId}, (err, file) -> if err and err.message grunt.log.error err.message done false else callback _files[fileId] = file else callback _files[fileId] _auths = {} getAuth = (id, secret, redirect, access_type, scope, callback) -> grunt.verbose.write 'auth...' if not _auths[id] client = _auths[id] = new google.auth.OAuth2 id, secret, redirect getAccessToken client.generateAuthUrl({access_type, scope}), (code) -> client.getToken code, (err, tokens) -> if err and err.message grunt.log.error err.message done false else client.setCredentials tokens callback _auths[id] = client else callback _auths[id] getAccessToken = (url, callback) -> grunt.verbose.write 'token...' open url server = http.createServer (req, rep) -> rep.end() req.connection.destroy() server.close() callback req.url.substr 7 server.maxConnections = 1 server.listen 4477 # ggss rxFileIdAndGid = /^.*[\/\=](\w{44}).*gid=(\d+).*$/i rxTrue = /^true$/i grunt.registerMultiTask 'gss', -> done = @async() data = @data (next = (file, files) -> # extend file matches = file.src[0].match rxFileIdAndGid fileId = matches[1] gid = matches[2] opts = extend {}, data.options, file.options or {} grunt.log.write "Processing #{file.dest}..." getCsv opts.clientId, opts.clientSecret, fileId, gid, (out) -> # json if opts.json grunt.log.write 'parse...' out = JSON.parse csv2json out # mapping if opts.mapping grunt.log.write 'map...' cols = [] types = [] for col, type of opts.mapping cols.push col types.push type for row in out for type, i in types col = cols[i] val = row[col] # convert if toType(type) is 'function' row[col] = type val, row else if toType(val) isnt type if type is 'array' then row[col] = if not val then [] else if val.indexOf(',') isnt -1 then val.split ',' else [val] else if type is 'boolean' then row[col] = rxTrue.test val else if type is 'number' then row[col] = parseFloat val or 0 else if type is 'undefined' then delete row[col] # prettify if opts.json and opts.prettify grunt.log.write 'prettify...' out = JSON.stringify out, null, 2 # wrap if toType(opts.wrap) is 'function' grunt.log.write 'wrap...' out = opts.wrap out # write grunt.log.write 'write...' grunt.file.write file.dest, out grunt.log.ok() # loop if not files.length then done true else next files.shift().orig, files ) @files.shift().orig, @files null null