From 657b8ce5a84fd1940f2c30ba4a83189eda0c016f Mon Sep 17 00:00:00 2001 From: Leonid Beschastny Date: Wed, 11 Oct 2023 19:20:10 +0200 Subject: [PATCH] Convert src from coffescript to es6 --- .gitignore | 1 - package.json | 4 +-- src/args.coffee | 17 ----------- src/args.js | 23 +++++++++++++++ src/index.coffee | 13 --------- src/index.js | 8 ++++++ src/io.coffee | 59 ------------------------------------- src/io.js | 60 ++++++++++++++++++++++++++++++++++++++ src/utils.coffee | 38 ------------------------ src/utils.js | 52 +++++++++++++++++++++++++++++++++ src/webp.coffee | 33 --------------------- src/webp.js | 38 ++++++++++++++++++++++++ src/wrapper.coffee | 56 ------------------------------------ src/wrapper.js | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 254 insertions(+), 220 deletions(-) delete mode 100644 src/args.coffee create mode 100644 src/args.js delete mode 100644 src/index.coffee create mode 100644 src/index.js delete mode 100644 src/io.coffee create mode 100644 src/io.js delete mode 100644 src/utils.coffee create mode 100644 src/utils.js delete mode 100644 src/webp.coffee create mode 100644 src/webp.js delete mode 100644 src/wrapper.coffee create mode 100644 src/wrapper.js diff --git a/.gitignore b/.gitignore index f247ded..97d4044 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ out.json -lib/ test/*.js test/*/*.js node_modules/ diff --git a/package.json b/package.json index 638519d..c2cb4ac 100644 --- a/package.json +++ b/package.json @@ -15,12 +15,10 @@ "type": "git", "url": "https://github.com/Intervox/node-webp.git" }, - "main": "lib/index.js", + "main": "src/index.js", "scripts": { - "clean": "rm -rf lib/ cwebp-*.tgz", "test": "mocha test/*.coffee", "list-files": "tar -tzf `npm pack | tail -n 1`", - "prepack": "npm run clean && coffee -o lib/ -cb src/", "postpublish": "git push origin +HEAD:latest --follow-tags" }, "engines": { diff --git a/src/args.coffee b/src/args.coffee deleted file mode 100644 index f8336a8..0000000 --- a/src/args.coffee +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = - command: (args...) -> - @_args._.push args... - return @ - - _arg: (key, vals...) -> - @_args[key] = vals - return @ - - args: -> - args = [] - if preset = @_args.preset - args.push '-preset', preset... - for key, vals of @_args - continue if key in ['_', '-', 'preset'] - args.push "-#{key}", vals... - args.concat @_args._ diff --git a/src/args.js b/src/args.js new file mode 100644 index 0000000..1e2d831 --- /dev/null +++ b/src/args.js @@ -0,0 +1,23 @@ +module.exports = { + command(...args) { + this._args._.push(...args); + return this; + }, + _arg(key, ...vals) { + this._args[key] = vals; + return this; + }, + args() { + const args = []; + if (this._args.preset) { + args.push('-preset', ...this._args.preset); + } + for (const key in this._args) { + if (key === '_' || key === '-' || key === 'preset') { + continue; + } + args.push(`-${key}`, ...this._args[key]); + } + return args.concat(this._args._); + } +}; diff --git a/src/index.coffee b/src/index.coffee deleted file mode 100644 index 130b669..0000000 --- a/src/index.coffee +++ /dev/null @@ -1,13 +0,0 @@ -path = require 'path' -fs = require 'fs' - -{CWebp, DWebp} = require './webp' - -pkg = path.resolve __dirname, '../package.json' -{version} = JSON.parse fs.readFileSync pkg, 'utf8' - -module.exports = exports = CWebp - -exports.CWebp = CWebp -exports.DWebp = DWebp -exports.version = version diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..a8dfbbb --- /dev/null +++ b/src/index.js @@ -0,0 +1,8 @@ +const path = require('path'); +const fs = require('fs'); +const { CWebp, DWebp } = require('./webp'); + +const pkg = path.resolve(__dirname, '../package.json'); +const { version } = JSON.parse(fs.readFileSync(pkg, 'utf8')); + +module.exports = Object.assign(CWebp, { CWebp, DWebp, version }); diff --git a/src/io.coffee b/src/io.coffee deleted file mode 100644 index c522344..0000000 --- a/src/io.coffee +++ /dev/null @@ -1,59 +0,0 @@ -streamToBuffer = require 'raw-body' - -{Buffer} = require 'buffer' -{Stream, PassThrough} = require 'stream' - -bindCallback = (promise, next) -> - if typeof next is 'function' - promise.then (result) -> - process.nextTick next, null, result - , (err) -> - process.nextTick next, err - promise - -module.exports = - _write: (source, outname) -> - outname ||= '-' - stdin = (typeof source isnt 'string') - stdout = outname is '-' - args = [].concat @args(), [ - '-o', outname - '--', (if stdin then '-' else source) - ] - unless stdin - @_spawn args, stdin, stdout - else if Buffer.isBuffer source - res = @_spawn args, stdin, stdout - res.stdin.end source - res - else if source instanceof Stream - res = @_spawn args, stdin, stdout - source.pipe res.stdin - res - else - promise: Promise.reject new Error 'Mailformed source' - - write: (outname, next) -> - promise = if outname - (@_write @source, outname).promise - else - Promise.reject new Error 'outname in not specified' - bindCallback promise, next - - toBuffer: (next) -> - bindCallback (streamToBuffer @stream()), next - - stream: -> - outstream = new PassThrough() - res = @_write @source, '-' - promise = if res.stdout - res.stdout.pipe outstream, end: false - res.promise - else - res.promise.then -> - Promise.reject new Error 'Failed to pipe stdout' - promise.then -> - outstream.end() - .catch (err) -> - outstream.emit 'error', err - outstream diff --git a/src/io.js b/src/io.js new file mode 100644 index 0000000..5c9660c --- /dev/null +++ b/src/io.js @@ -0,0 +1,60 @@ +const streamToBuffer = require('raw-body'); +const { Buffer } = require('buffer'); +const { Stream, PassThrough } = require('stream'); + +const bindCallback = (promise, next) => { + if (typeof next === 'function') { + promise.then( + (result) => process.nextTick(next, null, result), + (err) => process.nextTick(next, err) + ); + } + return promise; +}; + +module.exports = { + _write(source, outname = '-') { + const stdin = typeof source !== 'string'; + const stdout = outname === '-'; + const args = [ + ...this.args(), + '-o', outname, + '--', (stdin ? '-' : source) + ]; + if (!stdin) { + return this._spawn(args, stdin, stdout); + } else if (Buffer.isBuffer(source)) { + const res = this._spawn(args, stdin, stdout); + res.stdin.end(source); + return res; + } else if (source instanceof Stream) { + const res = this._spawn(args, stdin, stdout); + source.pipe(res.stdin); + return res; + } else { + return { + promise: Promise.reject(new Error('Mailformed source')) + }; + } + }, + write(outname, next) { + const promise = outname + ? (this._write(this.source, outname)).promise + : Promise.reject(new Error('outname in not specified')); + return bindCallback(promise, next); + }, + toBuffer(next) { + return bindCallback(streamToBuffer(this.stream()), next); + }, + stream() { + const outstream = new PassThrough(); + const { promise, stdout } = this._write(this.source, '-'); + if (stdout) { + stdout.pipe(outstream, { end: false }); + } + promise + .then(() => outstream.end()) + .catch((err) => outstream.destroy(err)); + return outstream; + } +}; diff --git a/src/utils.coffee b/src/utils.coffee deleted file mode 100644 index a64a305..0000000 --- a/src/utils.coffee +++ /dev/null @@ -1,38 +0,0 @@ -exports.mixin = (cls, proto) -> - for name, method of proto - cls::[name] = method - return - -exports.compile = (methods) -> - proto = {} - for name, params of methods then do (name, params) -> - {key, type, description, exclude, aliases} = params - key ||= name - method = if type is 'boolean' - (val) -> - if val or arguments.length is 0 - if exclude then for k in [].concat exclude - delete @_args[methods[k].key || k] - @_args[key] = [] - else - delete @_args[key] - return @ - else - type = [type || 'string'] unless Array.isArray type - (args...) -> - if args.length < type.length - throw new Error 'Not enough arguments' - vals = [] - for t in type - val = args.shift() - if (t is 'number') and (Number.isFinite nval = Number val) - val = nval - if typeof val isnt t - throw new Error "Expected #{t}, got #{typeof val}" - vals.push val - @_args[key] = vals - return @ - method.description = description - for alias in [].concat name, (aliases || []) - proto[alias] = method - proto diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..6901f3a --- /dev/null +++ b/src/utils.js @@ -0,0 +1,52 @@ +exports.mixin = (cls, proto) => { + for (const name in proto) { + cls.prototype[name] = proto[name]; + } +}; + +exports.compile = (methods) => { + const proto = {}; + for (const name in methods) { + const { key = name, type, description, exclude, aliases } = methods[name]; + const typeArray = Array.isArray(type) ? type : [type || 'string']; + + const method = type === 'boolean' ? function(val) { + if (val || arguments.length === 0) { + if (exclude) { + [].concat(exclude).forEach((k) => { + delete this._args[methods[k].key || k]; + }); + } + this._args[key] = []; + } else { + delete this._args[key]; + } + return this; + } : function(...args) { + if (args.length < typeArray.length) { + throw new Error('Not enough arguments'); + } + const vals = []; + typeArray.forEach((t) => { + let val = args.shift(); + if (t === 'number') { + const nval = Number(val); + if (Number.isFinite(nval)) { + val = nval; + } + } + if (typeof val !== t) { + throw new Error(`Expected ${t}, got ${typeof val}`); + } + vals.push(val); + }); + this._args[key] = vals; + return this; + }; + proto[name] = Object.assign(method, { description }); + (aliases || []).forEach((alias) => { + proto[alias] = proto[name]; + }); + } + return proto; +}; diff --git a/src/webp.coffee b/src/webp.coffee deleted file mode 100644 index def246f..0000000 --- a/src/webp.coffee +++ /dev/null @@ -1,33 +0,0 @@ -{mixin, compile} = require './utils' -Wrapper = require './wrapper' -methods = require '../methods' - - -exports.CWebp = class CWebp extends Wrapper - mixin this, compile methods.global - mixin this, compile methods.cwebp - - @bin: 'cwebp' - @verbose: false - - constructor: (source, bin) -> - unless @ instanceof CWebp - return new CWebp source, bin - - super - - if @constructor.verbose - @_args.v = [] - - -exports.DWebp = class DWebp extends Wrapper - mixin this, compile methods.global - mixin this, compile methods.dwebp - - @bin: 'dwebp' - - constructor: (source, bin) -> - unless @ instanceof DWebp - return new DWebp source, bin - - super diff --git a/src/webp.js b/src/webp.js new file mode 100644 index 0000000..a59fc0b --- /dev/null +++ b/src/webp.js @@ -0,0 +1,38 @@ +const { inherits } = require('util'); +const { mixin, compile } = require('./utils'); +const Wrapper = require('./wrapper'); +const methods = require('../methods.json'); + +function CWebp(source, bin) { + if (!(this instanceof CWebp)) { + return new CWebp(source, bin); + } + Wrapper.call(this, source, bin); + if (this.constructor.verbose) { + this._args.v = []; + } +} + +inherits(CWebp, Wrapper); + +mixin(CWebp, compile(methods.global)); +mixin(CWebp, compile(methods.cwebp)); + +CWebp.bin = 'cwebp'; +CWebp.verbose = false; + +function DWebp(source, bin) { + if (!(this instanceof DWebp)) { + return new DWebp(source, bin); + } + Wrapper.call(this, source, bin); +} + +inherits(DWebp, Wrapper); + +mixin(DWebp, compile(methods.global)); +mixin(DWebp, compile(methods.dwebp)); + +DWebp.bin = 'dwebp'; + +module.exports = { CWebp, DWebp }; diff --git a/src/wrapper.coffee b/src/wrapper.coffee deleted file mode 100644 index a6aec4a..0000000 --- a/src/wrapper.coffee +++ /dev/null @@ -1,56 +0,0 @@ -{spawn} = require 'child_process' - -{mixin} = require './utils' - -defer = () -> - res = {} - res.promise = new Promise (resolve, reject) -> - res.resolve = resolve - res.reject = reject - res - -module.exports = class Wrapper - mixin this, require './args' - mixin this, require './io' - - constructor: (source, bin) -> - @_args = {_: []} - @_opts = {} - @source = source - @bin = bin || @constructor.bin - - spawnOptions: (options) -> - for key, value of options - @_opts[key] = value - return @ - - _spawn: (args, stdin = false, stdout = false) -> - {resolve, reject, promise} = defer() - stderr = '' - @_opts.stdio = [ - if stdin then 'pipe' else 'ignore' - if stdout then 'pipe' else 'ignore' - 'pipe' # stderr - ] - proc = spawn @bin, args, @_opts - proc.once 'error', onError = (err) -> - reject err unless err.code is 'OK' is err.errno - proc.once 'close', onClose = (code, signal) -> - if code isnt 0 or signal isnt null - err = new Error "Command failed: #{stderr}" - err.code = code - err.signal = signal - reject err - else - resolve() - proc.stderr.on 'data', onErrData = (data) -> - stderr += data - promise = promise.finally -> - # Cleanup - proc.removeListener 'error', onError - proc.removeListener 'close', onClose - proc.stderr.removeListener 'data', onErrData - res = {promise} - res.stdin = proc.stdin if stdin - res.stdout = proc.stdout if stdout - return res diff --git a/src/wrapper.js b/src/wrapper.js new file mode 100644 index 0000000..df27ad8 --- /dev/null +++ b/src/wrapper.js @@ -0,0 +1,72 @@ +const { spawn } = require('child_process'); +const { mixin } = require('./utils'); + +const defer = () => { + const res = {}; + res.promise = new Promise((resolve, reject) => { + Object.assign(res, { resolve, reject }); + }); + return res; +}; + +function Wrapper(source, bin) { + this._args = { _: [] }; + this._opts = {}; + this.source = source; + this.bin = bin || this.constructor.bin; +} + +mixin(Wrapper, require('./args')); +mixin(Wrapper, require('./io')); + +Wrapper.prototype.spawnOptions = function(options) { + for (const key in options) { + this._opts[key] = options[key]; + } + return this; +}; + +Wrapper.prototype._spawn = function(args, stdin = false, stdout = false) { + const { promise, resolve, reject } = defer(); + const stdio = [ + stdin ? 'pipe' : 'ignore', + stdout ? 'pipe' : 'ignore', + 'pipe' + ]; + let stderr = ''; + const proc = spawn(this.bin, args, { ...this._opts, stdio }); + const onError = (err) => { + if (err.code !== 'OK' || err.errno !== 'OK') { + reject(err); + } + }; + const onClose = (code, signal) => { + if (code !== 0 || signal !== null) { + const err = new Error(`Command failed: ${stderr}`); + return reject(Object.assign(err, { code, signal })); + } else { + return resolve(); + } + }; + const onErrData = (data) => { + stderr += data; + }; + proc.once('error', onError); + proc.once('close', onClose); + proc.stderr.on('data', onErrData); + const res = {}; + res.promise = promise.finally(() => { + proc.removeListener('error', onError); + proc.removeListener('close', onClose); + proc.stderr.removeListener('data', onErrData); + }); + if (stdin) { + res.stdin = proc.stdin; + } + if (stdout) { + res.stdout = proc.stdout; + } + return res; +}; + +module.exports = Wrapper;