From 2254fd0b61cc00aa197c2f9254727bad5ecbf22d Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Thu, 29 Oct 2020 13:02:11 +0100 Subject: [PATCH 01/52] var => const/let + other modernizations --- modules/assert.js | 220 +++++++++++++++++++--------------------------- 1 file changed, 89 insertions(+), 131 deletions(-) diff --git a/modules/assert.js b/modules/assert.js index 4330a6cc6..21a93152b 100644 --- a/modules/assert.js +++ b/modules/assert.js @@ -28,13 +28,13 @@ const { * @returns The comment appended to the expected arguments, if any * @type String */ -function evalArguments(args, argsExpected) { - if (!(args.length == argsExpected || - (args.length == argsExpected + 1 && getType(args[args.length - 1]) == "string"))) { +const evalArguments = (args, argsExpected) => { + if (!(args.length === argsExpected || + (args.length === argsExpected + 1 && getType(args[args.length - 1]) === "string"))) { throw new ArgumentsError("Insufficient arguments passed to assertion function"); } return args[argsExpected]; -} +}; /** * Deep-compares both arguments. @@ -44,7 +44,7 @@ function evalArguments(args, argsExpected) { * @returns True if arguments are equal, false otherwise * @type Boolean */ -function isDeepEqual(value1, value2) { +const isDeepEqual = (value1, value2) => { if (value1 === value2) { return true; } else if (value1 instanceof Date && value2 instanceof Date) { @@ -63,7 +63,7 @@ function isDeepEqual(value1, value2) { * @returns True if the objects are equal, false otherwise * @type Boolean */ -function objectsAreEqual(obj1, obj2) { +const objectsAreEqual = (obj1, obj2) => { if (isNullOrUndefined(obj1) || isNullOrUndefined(obj2)) { return false; } @@ -78,9 +78,9 @@ function objectsAreEqual(obj1, obj2) { return false; } // compare object keys (objects *and* arrays) - var keys1 = getOwnKeys(obj1); - var keys2 = getOwnKeys(obj2); - var propsAreEqual = keys1.length === keys2.length && keys1.every(function(name, idx) { + const keys1 = getOwnKeys(obj1); + const keys2 = getOwnKeys(obj2); + const propsAreEqual = keys1.length === keys2.length && keys1.every(function(name, idx) { return name === keys2[idx] && isDeepEqual(obj1[name], obj2[name]); }); if (propsAreEqual === false) { @@ -93,7 +93,7 @@ function objectsAreEqual(obj1, obj2) { }); } return true; -} +}; /** * Returns true if the argument is null or undefined @@ -101,9 +101,9 @@ function objectsAreEqual(obj1, obj2) { * @returns True if the argument is null or undefined * @type Boolean */ -function isNullOrUndefined(obj) { +const isNullOrUndefined = (obj) => { return obj === null || obj === undefined; -} +}; /** * Returns the names of owned properties of the object passed as argument. @@ -113,9 +113,9 @@ function isNullOrUndefined(obj) { * @returns The property names * @type Array */ -function getOwnKeys(obj) { - return [key for (key in obj) if (Object.prototype.hasOwnProperty.call(obj, key))].sort(); -} +const getOwnKeys = (obj) => { + return Object.keys(obj).sort(); +}; /** * Basic failure method. Fails an assertion without checking any preconditions. @@ -128,21 +128,21 @@ function getOwnKeys(obj) { * assert.fail("This should not be reached!"); * } */ -function fail(options) { +const fail = exports.fail = function fail(options) { throw new AssertionError(options); -} +}; /** * Prepends the comment to the message, if given * @returns The message * @type String */ -function prependComment(message, comment) { +const prependComment = (message, comment) => { if (getType(comment) === "string" && comment.length > 0) { return comment + "\n" + message; } return message; -} +}; /*************************** @@ -163,48 +163,34 @@ function prependComment(message, comment) { */ const AssertionError = exports.AssertionError = function AssertionError(options) { // accept a single string argument - if (getType(options) === "string") { - options = { - "message": options - }; - } - var stackTrace = getStackTrace(); - - Object.defineProperty(this, "name", { - get: function() { - return "AssertionError"; - } - }); - - Object.defineProperty(this, "message", { - get: function() { - return options.message; - } - }); - - Object.defineProperty(this, "actual", { - get: function() { - return options.actual; - } - }); - - Object.defineProperty(this, "expected", { - get: function() { - return options.expected; - } - }); - - Object.defineProperty(this, "stackTrace", { - get: function() { - return stackTrace; + options = (getType(options) === "string") ? + {"message": options} : + options || {}; + + Object.defineProperties(this, { + "name": { + "value": "AssertionError" + }, + "message": { + "value": options.message + }, + "actual": { + "value": options.actual + }, + "expected": { + "value": options.expected + }, + "stackTrace": { + "value": getStackTrace() } }); return this; -} +}; /** @ignore */ -AssertionError.prototype = new Error(); +AssertionError.prototype = Object.create(Error.prototype); +AssertionError.prototype.constructor = AssertionError; /** @ignore */ AssertionError.toString = function() { @@ -226,17 +212,12 @@ AssertionError.prototype.toString = function() { */ const ArgumentsError = exports.ArgumentsError = function ArgumentsError(message) { - var stackTrace = getStackTrace(); - - Object.defineProperty(this, "message", { - get: function() { - return message; - } - }); - - Object.defineProperty(this, "stackTrace", { - get: function() { - return stackTrace; + Object.defineProperties(this, { + "message": { + "value": message + }, + "stackTrace": { + "value": getStackTrace() } }); @@ -244,7 +225,8 @@ const ArgumentsError = exports.ArgumentsError = function ArgumentsError(message) } /** @ignore */ -ArgumentsError.prototype = new Error(); +ArgumentsError.prototype = Object.create(Error.prototype); +ArgumentsError.prototype.constructor = ArgumentsError; /** @ignore */ ArgumentsError.toString = function() { @@ -286,8 +268,8 @@ ArgumentsError.prototype.toString = function() { * @throws ArgumentsError * @throws AssertionError */ -function ok(value) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.ok = function ok(value) { + const comment = evalArguments(arguments, arguments.callee.length); if (!!value === false) { fail({ "message": prependComment("Expected " + jsDump(value) + " to be truthy", comment), @@ -316,8 +298,8 @@ function ok(value) { * @throws ArgumentsError * @throws AssertionError */ -function equal(actual, expected) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.equal = function equal(actual, expected) { + const comment = evalArguments(arguments, arguments.callee.length); if (actual != expected) { fail({ "message": prependComment("Expected " + jsDump(expected) + ", got " + jsDump(actual), comment), @@ -344,8 +326,8 @@ function equal(actual, expected) { * @throws ArgumentsError * @throws AssertionError */ -function notEqual(actual, expected) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.notEqual = function notEqual(actual, expected) { + const comment = evalArguments(arguments, arguments.callee.length); if (actual == expected) { fail({ "message": prependComment("Expected different value than " + jsDump(expected) + @@ -376,8 +358,8 @@ function notEqual(actual, expected) { * @throws ArgumentsError * @throws AssertionError */ -function deepEqual(actual, expected) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.deepEqual = function deepEqual(actual, expected) { + const comment = evalArguments(arguments, arguments.callee.length); if (isDeepEqual(actual, expected) === false) { fail({ "message": prependComment("Expected " + jsDump(expected) + ", got " + jsDump(actual), comment), @@ -404,8 +386,8 @@ function deepEqual(actual, expected) { * @throws ArgumentsError * @throws AssertionError */ -function notDeepEqual(actual, expected) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.notDeepEqual = function notDeepEqual(actual, expected) { + const comment = evalArguments(arguments, arguments.callee.length); if (isDeepEqual(actual, expected) === true) { fail({ "message": prependComment("Expected different value than " + jsDump(expected) + @@ -428,7 +410,7 @@ function notDeepEqual(actual, expected) { * assert.strictEqual("1", "1"); * assert.strictEqual(true, true);
* // passing assertion - * var obj = {}; + * const obj = {}; * assert.strictEqual(obj, obj);
* // failing assertions * assert.strictEqual(null, undefined); @@ -441,8 +423,8 @@ function notDeepEqual(actual, expected) { * @throws ArgumentsError * @throws AssertionError */ -function strictEqual(actual, expected) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.strictEqual = function strictEqual(actual, expected) { + const comment = evalArguments(arguments, arguments.callee.length); if (actual !== expected) { fail({ "message": prependComment("Expected " + jsDump(expected) + ", got " + jsDump(actual), comment), @@ -467,8 +449,8 @@ function strictEqual(actual, expected) { * @throws ArgumentsError * @throws AssertionError */ -function notStrictEqual(actual, expected) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.notStrictEqual = function notStrictEqual(actual, expected) { + const comment = evalArguments(arguments, arguments.callee.length); if (actual === expected) { fail({ "message": prependComment("Expected different value than " + jsDump(expected) + @@ -483,8 +465,8 @@ function notStrictEqual(actual, expected) { * Checks if the function passed as argument throws a defined exception. * It can also assert certain Java exceptions thrown by the function. * - * @example var foo = function() { throw "foo"; }; - * var bar = function() { (new java.util.Vector()).get(0); }
+ * @example const foo = function() { throw "foo"; }; + * const bar = function() { (new java.util.Vector()).get(0); }
* // passes * assert.throws(foo, "foo");
* // fails @@ -498,15 +480,15 @@ function notStrictEqual(actual, expected) { * @throws ArgumentsError * @throws AssertionError */ -function throws(func, expectedError) { +exports.throws = function throws(func, expectedError) { if (!(func instanceof Function)) { throw new ArgumentsError("First argument to throws() must be a function"); } try { func(); } catch (e) { - var isExpected = false; - var thrown = e; + let isExpected = false; + let thrown = e; if (expectedError == null) { // accept everything isExpected = true; @@ -565,8 +547,8 @@ function throws(func, expectedError) { * @throws ArgumentsError * @throws AssertionError */ -function isTrue(value) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.isTrue = function isTrue(value) { + const comment = evalArguments(arguments, arguments.callee.length); if (getType(value) !== "boolean") { throw new ArgumentsError("Invalid argument to assertTrue(boolean): " + jsDump(value)); @@ -591,8 +573,8 @@ function isTrue(value) { * @throws ArgumentsError * @throws AssertionError */ -function isFalse(value) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.isFalse = function isFalse(value) { + const comment = evalArguments(arguments, arguments.callee.length); if (getType(value) !== "boolean") { throw new ArgumentsError("Invalid argument to assertFalse(boolean): " + jsDump(value)); @@ -618,8 +600,8 @@ function isFalse(value) { * @throws ArgumentsError * @throws AssertionError */ -function isNull(value) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.isNull = function isNull(value) { + const comment = evalArguments(arguments, arguments.callee.length); if (value !== null) { fail({ "message": prependComment("Expected " + jsDump(value) + " to be null", comment), @@ -642,8 +624,8 @@ function isNull(value) { * @throws ArgumentsError * @throws AssertionError */ -function isNotNull(value) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.isNotNull = function isNotNull(value) { + const comment = evalArguments(arguments, arguments.callee.length); if (value === null) { fail({ "message": prependComment("Expected " + jsDump(value) + " to be not null", comment), @@ -665,8 +647,8 @@ function isNotNull(value) { * @throws ArgumentsError * @throws AssertionError */ -function isUndefined(value) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.isUndefined = function isUndefined(value) { + const comment = evalArguments(arguments, arguments.callee.length); if (value !== undefined) { fail({ "message": prependComment("Expected " + jsDump(value) + " to be undefined", comment), @@ -689,8 +671,8 @@ function isUndefined(value) { * @throws ArgumentsError * @throws AssertionError */ -function isNotUndefined(value) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.isNotUndefined = function isNotUndefined(value) { + const comment = evalArguments(arguments, arguments.callee.length); if (value === undefined) { fail({ "message": prependComment("Expected argument to be not undefined", comment), @@ -706,8 +688,8 @@ function isNotUndefined(value) { * @throws ArgumentsError * @throws AssertionError */ -function isNaN(value) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.isNaN = function isNaN(value) { + const comment = evalArguments(arguments, arguments.callee.length); if (global.isNaN(value) === false) { fail({ "message": prependComment("Expected " + jsDump(value) + " to be NaN", comment), @@ -724,8 +706,8 @@ function isNaN(value) { * @throws ArgumentsError * @throws AssertionError */ -function isNotNaN(value) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.isNotNaN = function isNotNaN(value) { + const comment = evalArguments(arguments, arguments.callee.length); if (global.isNaN(value) === true) { fail({ "message": prependComment("Expected " + jsDump(value) + " to be a number", comment), @@ -746,8 +728,8 @@ function isNotNaN(value) { * @throws ArgumentsError * @throws AssertionError */ -function stringContains(value, pattern) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.stringContains = function stringContains(value, pattern) { + const comment = evalArguments(arguments, arguments.callee.length); if (getType(pattern) === "string") { if (value.indexOf(pattern) < 0) { fail(prependComment("Expected string " + jsDump(pattern) + @@ -770,8 +752,8 @@ function stringContains(value, pattern) { * @throws ArgumentsError * @throws AssertionError */ -function matches(value, expr) { - var comment = evalArguments(arguments, arguments.callee.length); +exports.matches = function matches(value, expr) { + const comment = evalArguments(arguments, arguments.callee.length); if (getType(expr) === "regexp") { if (expr.test(value) === false) { fail(prependComment("Expected pattern " + jsDump(expr) + " to match " + @@ -782,27 +764,3 @@ function matches(value, expr) { jsDump(expr)); } } - -module.exports.fail = fail; - -// Commonjs assertion methods -module.exports.ok = ok; -module.exports.equal = equal; -module.exports.notEqual = notEqual; -module.exports.deepEqual = deepEqual; -module.exports.notDeepEqual = notDeepEqual; -module.exports.strictEqual = strictEqual; -module.exports.notStrictEqual = notStrictEqual; -module.exports.throws = throws; - -// Ringo assertion methods -module.exports.isTrue = isTrue; -module.exports.isFalse = isFalse; -module.exports.matches = matches; -module.exports.stringContains = stringContains; -module.exports.isNull = isNull; -module.exports.isNotNull = isNotNull; -module.exports.isUndefined = isUndefined; -module.exports.isNotUndefined = isNotUndefined; -module.exports.isNaN = isNaN; -module.exports.isNotNaN = isNotNaN; From fa23f475ce0dfea0d561bef3a7b2e44546362c0a Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Thu, 29 Oct 2020 13:08:37 +0100 Subject: [PATCH 02/52] replaced var with const in examples --- modules/binary.js | 59 +++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/modules/binary.js b/modules/binary.js index fe1ce2da9..52116ad3c 100644 --- a/modules/binary.js +++ b/modules/binary.js @@ -22,7 +22,7 @@ * * @example * // raw network streams only accept Binary as input - * var stream = socket.getStream(); + * const stream = socket.getStream(); * stream.write(new ByteArray([0xFA, 0xF0, 0x10, 0x58, 0xFF])); * * // network protocols like HTTP/1.1 require ASCII @@ -34,8 +34,8 @@ * fs.write("id_dsa.pub", ByteArray.wrap(publicKey.getEncoded())); * * // Generates a salt for hashing - * var random = java.security.SecureRandom.getInstance("SHA1PRNG"); - * var salt = new ByteArray(8); + * const random = java.security.SecureRandom.getInstance("SHA1PRNG"); + * const salt = new ByteArray(8); * random.nextBytes(salt); // fills up salt with random bytes * * @see http://wiki.commonjs.org/wiki/Binary/B @@ -84,7 +84,7 @@ exports.ByteString = ByteString; * Converts the String to a mutable ByteArray using the specified encoding. * @param {String} charset the name of the string encoding. Defaults to 'UTF-8' * @returns {ByteArray} a ByteArray representing the string - * @example var ba = "hello world".toByteArray(); + * @example const ba = "hello world".toByteArray(); */ Object.defineProperty(String.prototype, 'toByteArray', { value: function(charset) { @@ -97,7 +97,7 @@ Object.defineProperty(String.prototype, 'toByteArray', { * Converts the String to an immutable ByteString using the specified encoding. * @param {String} charset the name of the string encoding. Defaults to 'UTF-8' * @returns {ByteString} a ByteString representing the string - * @example var bs = "hello world".toByteString(); + * @example const bs = "hello world".toByteString(); */ Object.defineProperty(String.prototype, 'toByteString', { value: function(charset) { @@ -109,7 +109,7 @@ Object.defineProperty(String.prototype, 'toByteString', { /** * Reverses the content of the ByteArray in-place. * @returns {ByteArray} this ByteArray with its elements reversed - * @example var ba = new ByteArray([0,1,2,3,4,5,6,7,8]); + * @example const ba = new ByteArray([0,1,2,3,4,5,6,7,8]); * ba.reverse(); * print(ba[0] == 8); // --> true */ @@ -123,14 +123,13 @@ Object.defineProperty(ByteArray.prototype, 'reverse', { * Sorts the content of the ByteArray in-place. * @param {Function} comparator the function to compare entries * @returns {ByteArray} this ByteArray with its elements sorted - * @example var ba = "hello world".toByteArray(); + * @example const ba = "hello world".toByteArray(); * ba.sort(); * ba.decodeToString() // --> "dehllloorw" */ Object.defineProperty(ByteArray.prototype, 'sort', { value: function(fn) { - fn = fn || function(a, b) a - b; - return Array.prototype.sort.call(this, fn); + return Array.prototype.sort.call(this, fn || ((a, b) => a - b)); }, writable: true }); @@ -138,7 +137,7 @@ Object.defineProperty(ByteArray.prototype, 'sort', { * Apply a function for each element in the ByteArray. * @param {Function} fn the function to call for each element * @param {Object} thisObj optional this-object for callback - * @example var ba = "hello world".toByteArray(); + * @example const ba = "hello world".toByteArray(); * // prints 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100 * ba.forEach(function(byte) { console.log(byte) }); */ @@ -154,8 +153,8 @@ Object.defineProperty(ByteArray.prototype, 'forEach', { * @param {Function} callback the filter function * @param {Object} thisObj optional this-object for callback * @returns {ByteArray} a new ByteArray - * @example var ba = "hello world".toByteArray(); - * var bf = ba.filter(function(byte) { return byte > 110 }); + * @example const ba = "hello world".toByteArray(); + * const bf = ba.filter(function(byte) { return byte > 110 }); * bf.decodeToString(); // returns "owor" */ Object.defineProperty(ByteArray.prototype, 'filter', { @@ -170,7 +169,7 @@ Object.defineProperty(ByteArray.prototype, 'filter', { * @param {Function} callback the callback function * @param {Object} thisObj optional this-object for callback * @returns {Boolean} true if at least one invocation of callback returns true - * @example var ba = new ByteArray([0,1,2,3,4,5,6,7,8]); + * @example const ba = new ByteArray([0,1,2,3,4,5,6,7,8]); * ba.some(function(byte) { return byte > 10; }); // --> false * ba.some(function(byte) { return byte < 10; }); // --> true */ @@ -186,7 +185,7 @@ Object.defineProperty(ByteArray.prototype, 'some', { * @param {Function} callback the callback function * @param {Object} thisObj optional this-object for callback * @returns {Boolean} true if every invocation of callback returns true - * @example var ba = new ByteArray([0,1,2,3,4,5,6,7,8]); + * @example const ba = new ByteArray([0,1,2,3,4,5,6,7,8]); * ba.every(function(byte) { return byte > 5; }); // --> false * ba.every(function(byte) { return byte < 10; }); // --> true */ @@ -202,8 +201,8 @@ Object.defineProperty(ByteArray.prototype, 'every', { * @param {Function} callback the callback * @param {Object} thisObj optional this-object for callback * @returns {ByteArray} a new ByteArray - * @example var ba1 = new ByteArray([0,1,2,3,4,5,6,7,8]); - * var ba2 = ba1.map(function(byte) { return 2 * byte; }); + * @example const ba1 = new ByteArray([0,1,2,3,4,5,6,7,8]); + * const ba2 = ba1.map(function(byte) { return 2 * byte; }); * console.log(ba2.toArray()); // prints [0, 2, 4, 6, 8, 10, 12, 14, 16] */ Object.defineProperty(ByteArray.prototype, 'map', { @@ -218,7 +217,7 @@ Object.defineProperty(ByteArray.prototype, 'map', { * @param {Object} initialValue optional argument to be used as the first argument to the first call to the callback * @returns the return value of the last callback invocation * @see Array.prototype.reduce() - * @example var ba = new ByteArray([0,1,2,3,4,5,6,7,8]); + * @example const ba = new ByteArray([0,1,2,3,4,5,6,7,8]); * ba.reduce(function(prev, curr) { return prev + curr; }); // --> 36 */ Object.defineProperty(ByteArray.prototype, 'reduce', { @@ -248,7 +247,7 @@ Object.defineProperty(ByteArray.prototype, 'reduceRight', { /** * Removes the last element from an array and returns that element. * @returns {Number} - * @example var ba = new ByteArray([0,1,2,4,8]); + * @example const ba = new ByteArray([0,1,2,4,8]); * ba.pop() === 8; // --> true */ Object.defineProperty(ByteArray.prototype, 'pop', { @@ -261,7 +260,7 @@ Object.defineProperty(ByteArray.prototype, 'pop', { * Appends the given elements and returns the new length of the array. * @param {Number...} num... one or more numbers to append * @returns {Number} the new length of the ByteArray - * @example var ba = new ByteArray([0,1,2,4,8]); + * @example const ba = new ByteArray([0,1,2,4,8]); * ba.push(16); * console.log(ba.toArray()); // [0, 1, 2, 4, 8, 16] */ @@ -275,7 +274,7 @@ Object.defineProperty(ByteArray.prototype, 'push', { * Removes the first element from the ByteArray and returns that element. * This method changes the length of the ByteArray * @returns {Number} the removed first element - * @example var ba = new ByteArray([0,1,2,4,8]); + * @example const ba = new ByteArray([0,1,2,4,8]); * ba.shift(); * console.log(ba.toArray()); // [1, 2, 4, 8] */ @@ -290,7 +289,7 @@ Object.defineProperty(ByteArray.prototype, 'shift', { * new length. * @param {Number...} num... one or more numbers to append * @returns {Number} the new length of the ByteArray - * @example var ba = new ByteArray([0,1,2,4,8]); + * @example const ba = new ByteArray([0,1,2,4,8]); * ba.unshift(-8, -4, -2, -1); * console.log(ba.toArray()); // [248, 252, 254, 255, 0, 1, 2, 4, 8] */ @@ -307,7 +306,7 @@ Object.defineProperty(ByteArray.prototype, 'unshift', { * @param {Number} howMany The number of elements to remove at the given * position * @param {Number...} elements... the new elements to add at the given position - * @example var ba = new ByteArray([0,1,2,4,8]); + * @example const ba = new ByteArray([0,1,2,4,8]); * ba.splice(2,2); * console.log(ba.toArray()); // [0, 1, 8] */ @@ -323,7 +322,7 @@ Object.defineProperty(ByteArray.prototype, 'splice', { * @param {Number} offset * @returns {ByteArray} * @function - * @example var ba = new ByteArray([0,1,2,4,8]); + * @example const ba = new ByteArray([0,1,2,4,8]); * ba.byteAt(0); // --> [ByteArray 1] */ @@ -333,7 +332,7 @@ Object.defineProperty(ByteArray.prototype, 'splice', { * @param {Number} offset * @returns {ByteArray} * @function - * @example var ba = new ByteArray([0,1,2,4,8]); + * @example const ba = new ByteArray([0,1,2,4,8]); * ba.charAt(0); // --> [ByteArray 1] */ @@ -343,7 +342,7 @@ Object.defineProperty(ByteArray.prototype, 'splice', { * @param {Number} offset * @returns {Number} * @function - * @example var ba = new ByteArray([0,1,2,4,8]); + * @example const ba = new ByteArray([0,1,2,4,8]); * ba.charCodeAt(0); // --> 0 */ @@ -410,7 +409,7 @@ Object.defineProperty(ByteArray.prototype, 'splice', { * Returns a String representation of the ByteArray. * @name ByteArray.prototype.toString * @function - * @example var ba = new ByteArray([0,1,2,4,8]); + * @example const ba = new ByteArray([0,1,2,4,8]); * console.log(ba.toString()); // prints '[ByteArray 5]' */ @@ -419,7 +418,7 @@ Object.defineProperty(ByteArray.prototype, 'splice', { * @param {String} encoding the name of the encoding to use * @name ByteArray.prototype.decodeToString * @function - * @example var ba = new ByteArray([240, 159, 152, 130]); + * @example const ba = new ByteArray([240, 159, 152, 130]); * console.log(ba.decodeToString("UTF-8")); // prints 😂 */ @@ -493,7 +492,7 @@ Object.defineProperty(ByteArray.prototype, 'splice', { * @param {Number} offset * @param {Number} value * @function - * @example var ba = new ByteArray([0,255]); + * @example const ba = new ByteArray([0,255]); * ba[0] = 64; * print(ba[0]); // prints 64 */ @@ -505,7 +504,7 @@ Object.defineProperty(ByteArray.prototype, 'splice', { * @param {Number} offset * @returns {Number} * @function - * @example var ba = new ByteArray([0,255]); + * @example const ba = new ByteArray([0,255]); * print(ba[0]); // prints 0 */ @@ -675,4 +674,4 @@ Object.defineProperty(ByteArray.prototype, 'splice', { * silently fails. * @type Number * @name ByteString.prototype.length - */ \ No newline at end of file + */ From 088e53bf4554583583bb847be45412a5c2c8bc79 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Thu, 29 Oct 2020 14:47:55 +0100 Subject: [PATCH 03/52] code modernization --- modules/fs.js | 538 ++++++++++++++++++++++---------------------------- 1 file changed, 241 insertions(+), 297 deletions(-) diff --git a/modules/fs.js b/modules/fs.js index 5e9b24754..8c73c1020 100644 --- a/modules/fs.js +++ b/modules/fs.js @@ -5,9 +5,9 @@ * proposal. * * @example // Writes a simple text file - * var fs = require('fs'); + * const fs = require('fs'); * if (!fs.exists('test.txt')) { - * var textStream = fs.open('test.txt', { + * const textStream = fs.open('test.txt', { * write: true, * binary: false * }); @@ -26,13 +26,12 @@ include('io'); include('binary'); -var security = java.lang.System.getSecurityManager(); +const security = java.lang.System.getSecurityManager(); -var log = require("ringo/logging").getLogger(module.id); -var arrays = require('ringo/utils/arrays'); -var {PosixPermissions} = require('ringo/utils/files'); +const arrays = require('ringo/utils/arrays'); +const {PosixPermissions} = require('ringo/utils/files'); -var {Paths, +const {Paths, Files, FileSystems, LinkOption, @@ -41,15 +40,15 @@ var {Paths, FileVisitor, FileVisitResult} = java.nio.file; -var {FileTime, PosixFileAttributeView} = java.nio.file.attribute; +const {FileTime, PosixFileAttributeView} = java.nio.file.attribute; -var getPath = Paths.get; +const getPath = Paths.get; -var FS = FileSystems.getDefault(); -var SEPARATOR = FS.getSeparator(); -var SEPARATOR_RE = SEPARATOR == '/' ? - new RegExp(SEPARATOR) : - new RegExp(SEPARATOR.replace("\\", "\\\\") + "|/"); +const FS = FileSystems.getDefault(); +const SEPARATOR = FS.getSeparator(); +const SEPARATOR_RE = (SEPARATOR === '/') ? + new RegExp(SEPARATOR) : + new RegExp(SEPARATOR.replace("\\", "\\\\") + "|/"); /** * Open the file corresponding to `path` for reading or writing, @@ -80,24 +79,24 @@ var SEPARATOR_RE = SEPARATOR == '/' ? * @param {Object|String} options options as object properties or as mode string * @return {Stream|TextStream} a Stream object in binary mode, otherwise a TextStream * @example // Opens a m4a file in binary mode - * var m4aStream = fs.open('music.m4a', { + * const m4aStream = fs.open('music.m4a', { * binary: true, * read: true * }); * * // The equivalent call with options as string - * var m4aStream = fs.open('music.m4a', 'br'); + * const m4aStream = fs.open('music.m4a', 'br'); * * // Opens a text file - * var textStream = fs.open('example.txt', { read: true }); + * const textStream = fs.open('example.txt', { read: true }); * * // The equivalent call with options as string - * var textStream = fs.open('example.txt', 'r'); + * const textStream = fs.open('example.txt', 'r'); */ -function open(path, options) { +const open = exports.open = function(path, options) { options = checkOptions(options); - var nioPath = resolvePath(path); - var {read, write, append, update, binary, charset} = options; + const nioPath = resolvePath(path); + let {read, write, append, update, binary, charset} = options; if (read === true && write === true) { throw new Error("Cannot open a file for reading and writing at the same time"); @@ -108,7 +107,7 @@ function open(path, options) { } // configure the NIO options - var nioOptions = []; + const nioOptions = []; if (append === true) { nioOptions.push(StandardOpenOption.APPEND); } @@ -119,7 +118,7 @@ function open(path, options) { nioOptions.push(StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); } - var stream = new Stream(read ? + const stream = new Stream(read ? Files.newInputStream(nioPath, nioOptions) : Files.newOutputStream(nioPath, nioOptions)); if (binary) { return stream; @@ -145,11 +144,11 @@ function open(path, options) { * @returns {Stream} * @see #open */ -function openRaw(path, options) { - var nioPath = resolvePath(path); +const openRaw = exports.openRaw = function(path, options) { + const nioPath = resolvePath(path); options = checkOptions(options || {}); - var {read, write, append} = options; + let {read, write, append} = options; if (!read && !write && !append) { read = true; } else if (read === true && write === true) { @@ -157,7 +156,7 @@ function openRaw(path, options) { } // configure the NIO options - var nioOptions = []; + const nioOptions = []; if (append === true) { nioOptions.push(StandardOpenOption.APPEND); } @@ -181,10 +180,10 @@ function openRaw(path, options) { * @param {Object} options optional options * @return {String|Binary} the content of the file */ -function read(path, options) { +const read = exports.read = function(path, options) { options = options === undefined ? {} : checkOptions(options); options.read = true; - var stream = open(path, options); + const stream = open(path, options); try { return stream.read(); } finally { @@ -202,11 +201,11 @@ function read(path, options) { * @see ByteArray or * ByteString for binary data */ -function write(path, content, options) { +const write = exports.write = function(path, content, options) { options = options === undefined ? {} : checkOptions(options); options.write = true; options.binary = content instanceof Binary; - var stream = open(path, options); + const stream = open(path, options); try { stream.write(content); stream.flush(); @@ -223,9 +222,9 @@ function write(path, content, options) { * @example // Copies file from a temporary upload directory into /var/www * fs.copy('/tmp/uploads/fileA.txt', '/var/www/fileA.txt'); */ -function copy(from, to) { - var sourcePath = resolvePath(from); - var targetPath = resolvePath(to); +const copy = exports.copy = function(from, to) { + const sourcePath = resolvePath(from); + const targetPath = resolvePath(to); if (!Files.exists(sourcePath) || Files.isDirectory(sourcePath)) { throw new Error(sourcePath + " does not exist!"); @@ -259,29 +258,27 @@ function copy(from, to) { *    │   └── example.m4a *    └── baz */ -function copyTree(from, to) { - var source = resolvePath(from); - var target = resolvePath(to); +const copyTree = exports.copyTree = function(from, to) { + const source = resolvePath(from); + const target = resolvePath(to); - if (String(target) == String(source)) { + if (String(target) === String(source)) { throw new Error("Source and target files are equal in copyTree."); - } else if (String(target).indexOf(String(source) + SEPARATOR) == 0) { + } else if (String(target).indexOf(String(source) + SEPARATOR) === 0) { throw new Error("Target is a child of source in copyTree"); } if (Files.isDirectory(source)) { makeTree(target); - - var files = list(source); - for each (var file in files) { - var s = join(source.toString(), file); - var t = join(target.toString(), file); + list(source).forEach(file => { + const s = join(source.toString(), file); + const t = join(target.toString(), file); if (isLink(s)) { symbolicLink(readLink(s), t); } else { copyTree(s, t); } - } + }); } else { copy(source.toString(), target.toString()); } @@ -302,9 +299,8 @@ function copyTree(from, to) { *    └── bar *    └── baz */ -function makeTree(path) { - var fullPath = resolvePath(path); - Files.createDirectories(fullPath); +const makeTree = exports.makeTree = function(path) { + Files.createDirectories(resolvePath(path)); } /** @@ -325,20 +321,20 @@ function makeTree(path) { * // returned array: * [ '', 'foo', 'foo/bar', 'foo/bar/baz' ] */ -function listDirectoryTree(path) { +const listDirectoryTree = exports.listDirectoryTree = function(path) { path = path === '' ? '.' : String(path); - var result = ['']; - list(path).forEach(function (child) { - var childPath = join(path, child); + list(path).reduce((result, child) => { + const childPath = join(path, child); if (isDirectory(childPath)) { if (!isLink(childPath)) { result.push.apply(result, - listDirectoryTree(childPath).map(function (p) join(child, p))); + listDirectoryTree(childPath).map(p => join(child, p))); } else { // Don't follow symlinks. result.push(child); } } - }); + return result; + }, ['']); return result.sort(); } @@ -362,20 +358,19 @@ function listDirectoryTree(path) { * // returned array: * ['', 'foo', 'foo/bar', 'foo/bar/baz', 'musicfile.m4a', 'test.txt'] */ -function listTree(path) { +const listTree = exports.listTree = function(path) { path = path === '' ? '.' : String(path); - var result = ['']; - list(path).forEach(function (child) { - var childPath = join(path, child); + list(path).reduce((result, child) => { + const childPath = join(path, child); // Don't follow directory symlinks, but include them if (isDirectory(childPath) && !isLink(childPath)) { result.push.apply(result, - listTree(childPath).map(function (p) join(child, p))); + listTree(childPath).map(p => join(child, p))); } else { // Add file or symlinked directory. result.push(child); } - }); + }, ['']); return result.sort(); } @@ -397,20 +392,18 @@ function listTree(path) { * ├── musicfile.m4a * └── test.txt */ -function removeTree(path) { - var nioPath = resolvePath(path); +const removeTree = exports.removeTree = function(path) { + const nioPath = resolvePath(path); Files.walkFileTree(nioPath, new FileVisitor({ - visitFile: function (file, attrs) { + visitFile: (file, attrs) => { Files.delete(file); return FileVisitResult.CONTINUE; }, - visitFileFailed: function(file, e) { + visitFileFailed: (file, e) => { throw e; }, - preVisitDirectory: function() { - return FileVisitResult.CONTINUE; - }, - postVisitDirectory: function (dir, e) { + preVisitDirectory: () => FileVisitResult.CONTINUE, + postVisitDirectory: (dir, e) => { if (e == null) { Files.delete(dir); return FileVisitResult.CONTINUE; @@ -432,7 +425,7 @@ function removeTree(path) { * >> fs.isAbsolute('/Users/username/Desktop/example.txt'); * true */ -function isAbsolute(path) { +const isAbsolute = exports.isAbsolute = function(path) { return getPath(path).isAbsolute(); } @@ -443,7 +436,7 @@ function isAbsolute(path) { * @param {String} path the path to check * @returns {Boolean} true if path is relative, false if not */ -function isRelative(path) { +const isRelative = exports.isRelative = function(path) { return !isAbsolute(path); } @@ -456,7 +449,7 @@ function isRelative(path) { * @example >> fs.absolute('foo/bar/test.txt'); * '/Users/username/Desktop/working-directory/foo/bar/test.txt' */ -function absolute(path) { +const absolute = exports.absolute = function(path) { return resolve(workingDirectory(), path); } @@ -470,11 +463,11 @@ function absolute(path) { * @example >> fs.base('/a/b/c/foosomeext', 'someext'); * 'foo' */ -function base(path, ext) { - var name = arrays.peek(split(path)); +const base = exports.base = function(path, ext) { + const name = arrays.peek(split(path)); if (ext && name) { - var diff = name.length - ext.length; - if (diff > -1 && name.lastIndexOf(ext) == diff) { + const diff = name.length - ext.length; + if (diff > -1 && name.lastIndexOf(ext) === diff) { return name.substring(0, diff); } } @@ -489,7 +482,7 @@ function base(path, ext) { * @example >> fs.directory('/Users/username/Desktop/example/test.txt'); * '/Users/username/Desktop/example' */ -function directory(path) { +const directory = exports.directory = function(path) { return (getPath(path).getParent() || getPath('.')).toString(); } @@ -502,13 +495,13 @@ function directory(path) { * @example >> fs.extension('test.txt'); * '.txt' */ -function extension(path) { - var name = base(path); +const extension = exports.extension = function(path) { + let name = base(path); if (!name) { return ''; } name = name.replace(/^\.+/, ''); - var index = name.lastIndexOf('.'); + const index = name.lastIndexOf('.'); return index > 0 ? name.substring(index) : ''; } @@ -520,11 +513,11 @@ function extension(path) { * @returns {String} the joined path * @see java.nio.file.Paths.get(String first, String... more) * @example // build path to the config.json file - * var fullPath = fs.join(configDir, "config.json"); + * const fullPath = fs.join(configDir, "config.json"); */ -function join() { +const join = exports.join = function() { // filter out empty strings to avoid join("", "foo") -> "/foo" - var args = Array.prototype.filter.call(arguments, function(p) { + const args = Array.prototype.filter.call(arguments, function(p) { return p !== "" && p !== null && p !== undefined; }); @@ -538,7 +531,7 @@ function join() { * @example >> fs.split('/Users/someuser/Desktop/subdir/test.txt'); * [ '', 'Users', 'someuser', 'Desktop', 'subdir', 'test.txt' ] */ -function split(path) { +const split = exports.split = function(path) { if (!path) { return []; } @@ -553,7 +546,7 @@ function split(path) { * @example >> fs.normal('../redundant/../foo/./bar.txt'); * '../foo/bar.txt' */ -function normal(path) { +const normal = exports.normal = function(path) { return resolve(path); } @@ -568,17 +561,17 @@ function normal(path) { * @example >> fs.resolve('../.././foo/file.txt', 'bar/baz/', 'test.txt'); * '../../foo/bar/baz/test.txt' */ -function resolve() { - var root = ''; - var elements = []; - var leaf = ''; - var path; - for (var i = 0; i < arguments.length; i++) { +const resolve = exports.resolve = function() { + const elements = []; + let root = ''; + let leaf = ''; + let path; + for (let i = 0; i < arguments.length; i++) { path = String(arguments[i]); - if (path.trim() == '') { + if (path.trim() === '') { continue; } - var parts = path.split(SEPARATOR_RE); + let parts = path.split(SEPARATOR_RE); // Checking for absolute paths is not enough here as Windows has // something like quasi-absolute paths where a path starts with a // path separator instead of a drive character, e.g. \home\projects. @@ -587,22 +580,22 @@ function resolve() { // We still need to explicitly make absolute for the quasi-absolute // Windows paths mentioned above. root = String(getPath(parts.shift() + SEPARATOR).toAbsolutePath()); - elements = []; + elements.length = 0; } leaf = parts.pop(); - if (leaf == '.' || leaf == '..') { + if (leaf === '.' || leaf === '..') { parts.push(leaf); leaf = ''; } - for (var j = 0; j < parts.length; j++) { - var part = parts[j]; - if (part == '..') { - if (elements.length > 0 && arrays.peek(elements) != '..') { + for (let j = 0; j < parts.length; j++) { + let part = parts[j]; + if (part === '..') { + if (elements.length > 0 && arrays.peek(elements) !== '..') { elements.pop(); } else if (!root) { elements.push(part); } - } else if (part != '' && part != '.') { + } else if (part !== '' && part !== '.') { elements.push(part); } } @@ -628,7 +621,7 @@ function resolve() { * >> fs.relative('foo/bar/', 'foo/bar/baz/'); * 'baz/' */ -function relative(source, target) { +const relative = exports.relative = function(source, target) { if (!target) { target = source; source = workingDirectory(); @@ -638,10 +631,7 @@ function relative(source, target) { source = source.split(SEPARATOR_RE); target = target.split(SEPARATOR_RE); source.pop(); - while ( - source.length && - target.length && - target[0] == source[0]) { + while (source.length && target.length && target[0] === source[0]) { source.shift(); target.shift(); } @@ -661,10 +651,9 @@ function relative(source, target) { * @example // Moves file from a temporary upload directory into /var/www * fs.move('/tmp/uploads/fileA.txt', '/var/www/fileA.txt'); */ -function move(source, target) { - var from = resolvePath(source); - var to = resolvePath(target); - +const move = exports.move = function(source, target) { + const from = resolvePath(source); + const to = resolvePath(target); Files.move(from, to, [StandardCopyOption.REPLACE_EXISTING]); } @@ -674,8 +663,8 @@ function move(source, target) { * @param {String} path the path of the file to remove. * @throws Error if path is not a file or could not be removed. */ -function remove(path) { - var nioPath = resolvePath(path); +const remove = exports.remove = function(path) { + const nioPath = resolvePath(path); if (Files.isDirectory(nioPath)) { throw new Error(path + " is not a file"); @@ -688,7 +677,7 @@ function remove(path) { * Return true if the file denoted by `path` exists, false otherwise. * @param {String} path the file path. */ -function exists(path) { +const exists = exports.exists = function(path) { return Files.exists(resolvePath(path)); } @@ -696,7 +685,7 @@ function exists(path) { * Return the path name of the current working directory. * @returns {String} the current working directory */ -function workingDirectory() { +const workingDirectory = exports.workingDirectory = function() { return resolvePath(java.lang.System.getProperty('user.dir')) + SEPARATOR; } @@ -706,7 +695,7 @@ function workingDirectory() { * @param {String} path the directory path * @throws Error if the file or directory could not be removed. */ -function removeDirectory(path) { +const removeDirectory = exports.removeDirectory = function(path) { Files.delete(resolvePath(path)); } @@ -715,9 +704,9 @@ function removeDirectory(path) { * the given directory. There is no guarantee that the strings are in * any specific order. * - * @example var names = fs.list('/usr/local/'); + * @example const names = fs.list('/usr/local/'); * names.forEach(function(name) { - * var fullPath = fs.join(dir, name); + * const fullPath = fs.join(dir, name); * if (fs.isFile(fullPath)) { * // do something with the file * } @@ -725,16 +714,16 @@ function removeDirectory(path) { * @param {String} path the directory path * @returns {Array} an array of strings with the files, directories, or symbolic links */ -function list(path) { - var nioPath = resolvePath(path); +const list = exports.list = function(path) { + const nioPath = resolvePath(path); if (!Files.isDirectory(nioPath)) { throw new Error("failed to list directory " + path); } - var files = []; - var dirStream = Files.newDirectoryStream(nioPath); - var dirIterator = dirStream.iterator(); + const files = []; + const dirStream = Files.newDirectoryStream(nioPath); + const dirIterator = dirStream.iterator(); while (dirIterator.hasNext()) { files.push(String(dirIterator.next().getFileName())); } @@ -750,8 +739,8 @@ function list(path) { * @returns {Number} the file size in bytes * @throws Error if path is not a file */ -function size(path) { - var nioPath = resolvePath(path); +const size = exports.size = function(path) { + const nioPath = resolvePath(path); if (!Files.isRegularFile(nioPath)) { throw new Error(path + " is not a file"); } @@ -763,9 +752,9 @@ function size(path) { * @param {String} path the file path * @returns {Date} the date the file was last modified */ -function lastModified(path) { - var nioPath = resolvePath(path); - var fileTime = Files.getLastModifiedTime(nioPath); +const lastModified = exports.lastModified = function(path) { + const nioPath = resolvePath(path); + const fileTime = Files.getLastModifiedTime(nioPath); return new Date(fileTime.toMillis()); } @@ -779,8 +768,10 @@ function lastModified(path) { * @param {String} path the file path * @param {Number|String|java.util.Set} permissions optional the POSIX permissions */ -function makeDirectory(path, permissions) { - if (security) security.checkWrite(path); +const makeDirectory = exports.makeDirectory = function(path, permissions) { + if (security) { + security.checkWrite(path); + } // single-argument Files.createDirectory() respects the current umask if (permissions == null) { @@ -795,7 +786,7 @@ function makeDirectory(path, permissions) { * @param {String} path the file path * @returns {Boolean} whether the file exists and is readable */ -function isReadable(path) { +const isReadable = exports.isReadable = function(path) { return Files.isReadable(resolvePath(path)); } @@ -804,7 +795,7 @@ function isReadable(path) { * @param {String} path the file path * @returns {Boolean} whether the file exists and is writable */ -function isWritable(path) { +const isWritable = exports.isWritable = function(path) { return Files.isWritable(resolvePath(path)); } @@ -813,7 +804,7 @@ function isWritable(path) { * @param {String} path the file path * @returns {Boolean} whether the file exists and is a file */ -function isFile(path) { +const isFile = exports.isFile = function(path) { return Files.isRegularFile(resolvePath(path)); } @@ -822,7 +813,7 @@ function isFile(path) { * @param {String} path the file path * @returns {Boolean} whether the file exists and is a directory */ -function isDirectory(path) { +const isDirectory = exports.isDirectory = function(path) { return Files.isDirectory(resolvePath(path)); } @@ -832,8 +823,10 @@ function isDirectory(path) { * @param {String} path the file path * @returns {Boolean} true if the given file exists and is a symbolic link */ -function isLink(path) { - if (security) security.checkRead(path); +const isLink = exports.isLink = function(path) { + if (security) { + security.checkRead(path); + } return Files.isSymbolicLink(resolvePath(path)); } @@ -846,14 +839,14 @@ function isLink(path) { * @param {String} pathB the second path * @returns {Boolean} true iff the two paths locate the same file */ -function same(pathA, pathB) { +const same = exports.same = function(pathA, pathB) { if (security) { security.checkRead(pathA); security.checkRead(pathB); } // make canonical to resolve symbolic links - let nioPathA = getPath(canonical(pathA)); - let nioPathB = getPath(canonical(pathB)); + const nioPathA = getPath(canonical(pathA)); + const nioPathB = getPath(canonical(pathB)); return Files.isSameFile(nioPathA, nioPathB); } @@ -865,14 +858,14 @@ function same(pathA, pathB) { * @param {String} pathB the second path * @returns {Boolean} true if same file system, otherwise false */ -function sameFilesystem(pathA, pathB) { +const sameFilesystem = exports.sameFilesystem = function(pathA, pathB) { if (security) { security.checkRead(pathA); security.checkRead(pathB); } // make canonical to resolve symbolic links - let nioPathA = getPath(canonical(pathA)); - let nioPathB = getPath(canonical(pathB)); + const nioPathA = getPath(canonical(pathA)); + const nioPathB = getPath(canonical(pathB)); return nioPathA.getFileSystem().equals(nioPathB.getFileSystem()); } @@ -884,7 +877,7 @@ function sameFilesystem(pathA, pathB) { * @param {String} path a file path * @returns {String} the canonical path */ -function canonical(path) { +const canonical = exports.canonical = function(path) { return String(resolvePath(path).toRealPath().normalize()); } @@ -895,8 +888,8 @@ function canonical(path) { * @param {String} path the file path * @param {Date} mtime optional date */ -function touch(path, mtime) { - var nioPath = resolvePath(path); +const touch = exports.touch = function(path, mtime) { + const nioPath = resolvePath(path); if (!Files.exists(nioPath)) { Files.createFile(nioPath); } else { @@ -914,7 +907,7 @@ function touch(path, mtime) { * @param {String} link the link to create pointing to an existing path * @returns {String} the path to the symbolic link */ -function symbolicLink(existing, link) { +const symbolicLink = exports.symbolicLink = function(existing, link) { if (security) { security.checkRead(existing); security.checkWrite(link); @@ -931,7 +924,7 @@ function symbolicLink(existing, link) { * @param {String} link the link to create pointing to an existing path * @returns {String} the path to the link */ -function hardLink(existing, link) { +const hardLink = exports.hardLink = function(existing, link) { if (security) { security.checkRead(existing); security.checkWrite(link); @@ -945,7 +938,7 @@ function hardLink(existing, link) { * * @param {String} path a file path */ -function readLink(path) { +const readLink = exports.readLink = function(path) { if (security) security.checkRead(path); // Throws an exception if there is no symbolic link at the given path or the link cannot be read. @@ -962,20 +955,17 @@ function readLink(path) { * @param {String} path a directory path * @see MDN Iterators and Generators * @example // Iterates over the current working directory - * for (var name in fs.iterate(".")) { + * for (let name of fs.iterate(".")) { * console.log(name); * } */ -function iterate(path) { - var iter = function() { - for each (var item in list(path)) { +const iterate = exports.iterate = function(path) { + return function*() { + for (let item of list(path)) { yield item; } throw StopIteration; }(); - // spec requires iterator(), native iterators/generators only have __iterator__(). - iter.iterator = iter.__iterator__; - return iter; } /** @@ -983,8 +973,10 @@ function iterate(path) { * @param {String} path * @returns PosixFilePermission the POSIX permissions for the given path */ -function permissions(path) { - if (security) security.checkRead(path); +const permissions = exports.permissions = function(path) { + if (security) { + security.checkRead(path); + } return new PosixPermissions(Files.getPosixFilePermissions(getPath(path))); } @@ -993,8 +985,10 @@ function permissions(path) { * @param {String} path * @returns {String} the username of the owner, or null if not possible to determine */ -function owner(path) { - if (security) security.checkRead(path); +const owner = exports.owner = function(path) { + if (security) { + security.checkRead(path); + } try { return Files.getOwner(getPath(path)).getName(); } catch (error) { @@ -1009,10 +1003,12 @@ function owner(path) { * @param {String} path * @returns {String} the group's name, or null if not possible to determine */ -function group(path) { - if (security) security.checkRead(path); +const group = exports.group = function(path) { + if (security) { + security.checkRead(path); + } try { - let attributes = Files.getFileAttributeView(getPath(path), PosixFileAttributeView); + const attributes = Files.getFileAttributeView(getPath(path), PosixFileAttributeView); return attributes.readAttributes().group().getName(); } catch (error) { // do nothing @@ -1026,8 +1022,10 @@ function group(path) { * @param {String} path * @param {Number|String|java.util.Set} permissions the POSIX permissions */ -function changePermissions(path, permissions) { - if (security) security.checkWrite(path); +const changePermissions = exports.changePermissions = function(path, permissions) { + if (security) { + security.checkWrite(path); + } permissions = new PosixPermissions(permissions); return Files.setPosixFilePermissions(getPath(path), permissions.toJavaPosixFilePermissionSet()); } @@ -1038,11 +1036,13 @@ function changePermissions(path, permissions) { * @param {String} path * @param {String} owner the user name string */ -function changeOwner(path, user) { - if (security) security.checkWrite(path); +const changeOwner = exports.changeOwner = function(path, user) { + if (security) { + security.checkWrite(path); + } - var lookupService = FS.getUserPrincipalLookupService(); - var userPrincipal = lookupService.lookupPrincipalByName(user); + const lookupService = FS.getUserPrincipalLookupService(); + const userPrincipal = lookupService.lookupPrincipalByName(user); return Files.setOwner(getPath(path), userPrincipal); } @@ -1053,13 +1053,15 @@ function changeOwner(path, user) { * @param {String} path * @param {String} group group name string */ -function changeGroup(path, group) { - if (security) security.checkWrite(path); +const changeGroup = exports.changeGroup = function(path, group) { + if (security) { + security.checkWrite(path); + } - var lookupService = FS.getUserPrincipalLookupService(); - var groupPrincipal = lookupService.lookupPrincipalByGroupName(group); + const lookupService = FS.getUserPrincipalLookupService(); + const groupPrincipal = lookupService.lookupPrincipalByGroupName(group); - var attributes = Files.getFileAttributeView( + const attributes = Files.getFileAttributeView( getPath(path), PosixFileAttributeView, LinkOption.NOFOLLOW_LINKS @@ -1069,7 +1071,7 @@ function changeGroup(path, group) { return true; } -var optionsMask = { +const optionsMask = { read: 1, write: 1, append: 1, @@ -1083,7 +1085,7 @@ var optionsMask = { /** * Internal. */ -function checkOptions(options) { +const checkOptions = function(options) { if (!options) { options = {}; } else if (typeof options != 'object') { @@ -1095,13 +1097,13 @@ function checkOptions(options) { } } else { // run sanity check on user-provided options object - for (var key in options) { + Object.keys(options).forEach(key => { if (!(key in optionsMask)) { throw new Error("unsupported option: " + key); } - options[key] = key == 'charset' ? - String(options[key]) : Boolean(options[key]); - } + options[key] = (key === 'charset') ? + String(options[key]) : Boolean(options[key]); + }); } return options; } @@ -1109,35 +1111,35 @@ function checkOptions(options) { /** * Internal. Convert a mode string to an options object. */ -function applyMode(mode) { - var options = {}; - for (var i = 0; i < mode.length; i++) { +const applyMode = function(mode) { + const options = {}; + for (let i = 0; i < mode.length; i++) { switch (mode[i]) { - case 'r': - options.read = true; - break; - case 'w': - options.write = true; - break; - case 'a': - options.append = true; - break; - case '+': - options.update = true; - break; - case 'b': - options.binary = true; - break; - case 'x': - // FIXME botic: is this implemented? - options.exclusive = true; - break; - case 'c': - // FIXME botic: is this needed? - options.canonical = true; - break; - default: - throw new Error("unsupported mode argument: " + options); + case 'r': + options.read = true; + break; + case 'w': + options.write = true; + break; + case 'a': + options.append = true; + break; + case '+': + options.update = true; + break; + case 'b': + options.binary = true; + break; + case 'x': + // FIXME botic: is this implemented? + options.exclusive = true; + break; + case 'c': + // FIXME botic: is this needed? + options.canonical = true; + break; + default: + throw new Error("unsupported mode argument: " + options); } } return options; @@ -1146,8 +1148,8 @@ function applyMode(mode) { /** * Internal. */ -function resolvePath(path) { - if (path == undefined) { +const resolvePath = function(path) { + if (path === null || path === undefined) { throw new Error('undefined path argument'); } @@ -1159,7 +1161,7 @@ function resolvePath(path) { /** * A shorthand for creating a new `Path` without the `new` keyword. */ -function path() { +const path = exports.path = function() { return new Path(join.apply(null, arguments)); } @@ -1167,17 +1169,18 @@ function path() { * Path constructor. Path is a chainable shorthand for working with paths. * @augments String */ -function Path() { +const Path = exports.Path = function() { if (!(this instanceof Path)) { return new Path(join.apply(null, arguments)); } - var path = join.apply(null, arguments) - this.toString = function() path; + const path = join.apply(null, arguments); + this.toString = () => path; return this; } /** @ignore */ -Path.prototype = new String(); +Path.prototype = Object.create(String.prototype); +Path.prototype.constructor = Path; /** * This is a non-standard extension, not part of CommonJS Filesystem/A. @@ -1197,7 +1200,7 @@ Path.prototype.join = function() { /** * Resolve against this path. */ -Path.prototype.resolve = function () { +Path.prototype.resolve = function() { return new Path(resolve.apply( null, [this.toString()].concat(Array.prototype.slice.call(arguments)) @@ -1210,7 +1213,7 @@ Path.prototype.resolve = function () { * to `fs.Path(fs.relative(this, target))`. * @param {String} target */ -Path.prototype.to = function (target) { +Path.prototype.to = function(target) { return exports.Path(relative(this.toString(), target)); }; @@ -1219,7 +1222,7 @@ Path.prototype.to = function (target) { * to `fs.Path(fs.relative(source, this))`. * @param {String} target */ -Path.prototype.from = function (target) { +Path.prototype.from = function(target) { return exports.Path(relative(target, this.toString())); }; @@ -1228,10 +1231,10 @@ Path.prototype.from = function (target) { * wrapped in Path objects. */ Path.prototype.listPaths = function() { - return this.list().map(function (file) new Path(this, file), this).sort(); + return this.list().map(file => new Path(this, file), this).sort(); }; -var pathed = [ +const PATHED = [ 'absolute', 'base', 'canonical', @@ -1239,20 +1242,16 @@ var pathed = [ 'normal', 'relative' ]; +PATHED.forEach(name => { + Path.prototype[name] = function() { + return new Path(exports[name].apply( + this, + [this.toString()].concat(Array.prototype.slice.call(arguments)) + )); + }; +}); -for (var i = 0; i < pathed.length; i++) { - var name = pathed[i]; - Path.prototype[name] = (function (name) { - return function () { - return new Path(exports[name].apply( - this, - [this.toString()].concat(Array.prototype.slice.call(arguments)) - )); - }; - })(name); -} - -var trivia = [ +const TRIVIA = [ 'copy', 'copyTree', 'exists', @@ -1283,71 +1282,16 @@ var trivia = [ 'write' ]; -for (i = 0; i < trivia.length; i++) { - var name = trivia[i]; - Path.prototype[name] = (function (name) { - return function () { - var fn = exports[name]; - if (!fn) throw new Error("Not found: " + name); - var result = exports[name].apply( - this, - [this.toString()].concat(Array.prototype.slice.call(arguments)) - ); - if (result === undefined) - result = this; - return result; - }; - })(name); -} - -module.exports.absolute = absolute; -module.exports.base = base; -module.exports.copy = copy; -module.exports.copyTree = copyTree; -module.exports.directory = directory; -module.exports.extension = extension; -module.exports.isAbsolute = isAbsolute; -module.exports.isRelative = isRelative; -module.exports.join = join; -module.exports.makeTree = makeTree; -module.exports.listDirectoryTree = listDirectoryTree; -module.exports.listTree = listTree; -module.exports.normal = normal; -module.exports.open = open; -module.exports.path = path; -module.exports.Path = Path; -module.exports.read = read; -module.exports.relative = relative; -module.exports.removeTree = removeTree; -module.exports.resolve = resolve; -module.exports.write = write; -module.exports.split = split; -module.exports.canonical = canonical; -module.exports.workingDirectory = workingDirectory; -module.exports.exists = exists; -module.exports.isDirectory = isDirectory; -module.exports.isFile = isFile; -module.exports.isReadable = isReadable; -module.exports.isWritable = isWritable; -module.exports.list = list; -module.exports.makeDirectory = makeDirectory; -module.exports.move = move; -module.exports.lastModified = lastModified; -module.exports.openRaw = openRaw; -module.exports.remove = remove; -module.exports.removeDirectory = removeDirectory; -module.exports.size = size; -module.exports.touch = touch; -module.exports.symbolicLink = symbolicLink; -module.exports.hardLink = hardLink; -module.exports.readLink = readLink; -module.exports.isLink = isLink; -module.exports.same = same; -module.exports.sameFilesystem = sameFilesystem; -module.exports.iterate = iterate; -module.exports.owner = owner; -module.exports.group = group; -module.exports.changePermissions = changePermissions; -module.exports.changeOwner = changeOwner; -module.exports.changeGroup = changeGroup; -module.exports.permissions = permissions; +TRIVIA.forEach(name => { + Path.prototype[name] = function() { + const fn = exports[name]; + if (!fn) { + throw new Error("Not found: " + name); + } + const result = fn.apply( + this, + [this.toString()].concat(Array.prototype.slice.call(arguments)) + ); + return result === undefined ? this : result; + }; +}); From caff1110e86425c95717017646e1a8b4da862819 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Thu, 29 Oct 2020 15:02:59 +0100 Subject: [PATCH 04/52] code modernization, removed obsolete require of Binary, ByteArray and ByteString (these are globally defined) --- modules/io.js | 90 +++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/modules/io.js b/modules/io.js index 7168d4f35..f8426952f 100644 --- a/modules/io.js +++ b/modules/io.js @@ -10,8 +10,7 @@ * writing files. */ -var {Binary, ByteArray, ByteString} = require("binary"); -var {Encoder, Decoder} = require("ringo/encoding"); +const {Encoder, Decoder} = require("ringo/encoding"); defineClass(org.ringojs.wrappers.Stream); @@ -21,8 +20,6 @@ defineClass(org.ringojs.wrappers.Stream); */ exports.Stream = Stream; -var {InputStreamReader, BufferedReader, OutputStreamWriter, BufferedWriter} = java.io; - /** * Reads all data available from this stream and writes the result to the * given output stream, flushing afterwards. Note that this function does @@ -30,8 +27,9 @@ var {InputStreamReader, BufferedReader, OutputStreamWriter, BufferedWriter} = ja * @param {Stream} output The target Stream to be written to. */ Stream.prototype.copy = function(output) { - var read, length = 8192; - var buffer = new ByteArray(length); + const length = 8192; + const buffer = new ByteArray(length); + let read = -1; while ((read = this.readInto(buffer, 0, length)) > -1) { output.write(buffer, 0, read); } @@ -47,8 +45,9 @@ Stream.prototype.copy = function(output) { * @param {Object} [thisObj] optional this-object to use for callback */ Stream.prototype.forEach = function(fn, thisObj) { - var read, length = 8192; - var buffer = new ByteArray(length); + const length = 8192; + const buffer = new ByteArray(length); + let read = -1; while ((read = this.readInto(buffer, 0, length)) > -1) { buffer.length = read; fn.call(thisObj, buffer); @@ -75,8 +74,7 @@ Stream.prototype.forEach = function(fn, thisObj) { * @constructor */ exports.MemoryStream = function MemoryStream(binaryOrNumber) { - - var buffer, length; + let buffer, length; if (!binaryOrNumber) { buffer = new ByteArray(0); length = 0; @@ -90,10 +88,10 @@ exports.MemoryStream = function MemoryStream(binaryOrNumber) { throw new Error("Argument must be Binary, Number, or undefined"); } - var stream = Object.create(Stream.prototype); - var position = 0; - var closed = false; - var canWrite = buffer instanceof ByteArray; + const stream = Object.create(Stream.prototype); + const canWrite = buffer instanceof ByteArray; + let position = 0; + let closed = false; function checkClosed() { if (closed) { @@ -152,12 +150,12 @@ exports.MemoryStream = function MemoryStream(binaryOrNumber) { */ stream.read = function(maxBytes) { checkClosed(); - var result; + let result; if (isFinite(maxBytes)) { if (maxBytes < 0) { throw new Error("read(): argument must not be negative"); } - var end = Math.min(position + maxBytes, length); + const end = Math.min(position + maxBytes, length); result = ByteString.wrap(buffer.slice(position, end)); position = end; return result; @@ -195,7 +193,7 @@ exports.MemoryStream = function MemoryStream(binaryOrNumber) { } else if (begin > end) { throw new Error("readInto(): end must be greater than begin"); } - var count = Math.min(length - position, end - begin); + const count = Math.min(length - position, end - begin); buffer.copy(position, position + count, target, begin); position += count; return count; @@ -226,7 +224,7 @@ exports.MemoryStream = function MemoryStream(binaryOrNumber) { if (begin > end) { throw new Error("write(): end must be greater than begin"); } - var count = end - begin; + const count = end - begin; source.copy(begin, end, buffer, position); position += count; length = Math.max(length, position); @@ -348,13 +346,12 @@ exports.TextStream = function TextStream(io, options, buflen) { } options = options || {}; - var charset = options.charset || "utf8"; - var newline = options.hasOwnProperty("newline") ? options.newline : "\n"; - var delimiter = options.hasOwnProperty("delimiter") ? options.delimiter : " "; - var reader, writer; - var encoder, decoder; - var DEFAULTSIZE = 8192; + const charset = options.charset || "utf8"; + const newline = options.hasOwnProperty("newline") ? options.newline : "\n"; + const delimiter = options.hasOwnProperty("delimiter") ? options.delimiter : " "; + const DEFAULTSIZE = 8192; + let encoder, decoder; if (io.readable()) { decoder = new Decoder(charset, false, buflen || DEFAULTSIZE); decoder.readFrom(io); @@ -393,7 +390,7 @@ exports.TextStream = function TextStream(io, options, buflen) { * @returns {String} the next line */ this.readLine = function () { - var line = decoder.readLine(true); + const line = decoder.readLine(true); if (line === null) return ""; return String(line); @@ -411,8 +408,8 @@ exports.TextStream = function TextStream(io, options, buflen) { * Returns the next line of input without the newline. Throws * `StopIteration` if the end of the stream is reached. * @returns {String} the next line - * @example var fs = require('fs'); - * var txtStream = fs.open('./browserStats.csv', 'r'); + * @example const fs = require('fs'); + * const txtStream = fs.open('./browserStats.csv', 'r'); * try { * while (true) { * console.log(txtStream.next()); @@ -422,7 +419,7 @@ exports.TextStream = function TextStream(io, options, buflen) { * } */ this.next = function () { - var line = decoder.readLine(false); + const line = decoder.readLine(false); if (line == null) { throw StopIteration; } @@ -433,13 +430,13 @@ exports.TextStream = function TextStream(io, options, buflen) { * Calls `callback` with each line in the input stream. * @param {Function} callback the callback function * @param {Object} [thisObj] optional this-object to use for callback - * @example var txtStream = fs.open('./browserStats.csv', 'r'); + * @example const txtStream = fs.open('./browserStats.csv', 'r'); * txtStream.forEach(function(line) { * console.log(line); // Print one single line * }); */ this.forEach = function (callback, thisObj) { - var line = decoder.readLine(false); + let line = decoder.readLine(false); while (line != null) { callback.call(thisObj, line); line = decoder.readLine(false); @@ -452,18 +449,20 @@ exports.TextStream = function TextStream(io, options, buflen) { * empty string, but it does include a trailing newline at the end of every * line. * @returns {Array} an array of lines - * @example >> var fs = require('fs'); - * >> var txtStream = fs.open('./sampleData.csv', 'r'); - * >> var lines = txtStream.readLines(); + * @example >> const fs = require('fs'); + * >> const txtStream = fs.open('./sampleData.csv', 'r'); + * >> const lines = txtStream.readLines(); * >> console.log(lines.length + ' lines'); * 6628 lines */ this.readLines = function () { - var lines = []; + const lines = []; + let line; do { - var line = this.readLine(); - if (line.length) + line = this.readLine(); + if (line.length) { lines.push(line); + } } while (line.length); return lines; }; @@ -492,9 +491,10 @@ exports.TextStream = function TextStream(io, options, buflen) { */ this.copy = function (output) { while (true) { - var line = this.readLine(); - if (!line.length) + let line = this.readLine(); + if (!line.length) { break; + } output.write(line).flush(); } return this; @@ -503,8 +503,8 @@ exports.TextStream = function TextStream(io, options, buflen) { /** * Writes all arguments to the stream. * @return {TextStream} this stream - * @example >> var fs = require('fs'); - * >> var txtOutStream = fs.open('./demo.txt', 'w'); + * @example >> const fs = require('fs'); + * >> const txtOutStream = fs.open('./demo.txt', 'w'); * >> txtOutStream.write('foo', 'bar', 'baz'); * * // demo.txt content: @@ -515,7 +515,7 @@ exports.TextStream = function TextStream(io, options, buflen) { throw new Error("The TextStream is not writable!"); } - for (var i = 0; i < arguments.length; i++) { + for (let i = 0; i < arguments.length; i++) { encoder.encode(String(arguments[i])); } return this; @@ -546,8 +546,8 @@ exports.TextStream = function TextStream(io, options, buflen) { /** * Writes all argument values as a single line, delimiting the values using * a single blank. - * @example >> var fs = require('fs'); - * >> var txtOutStream = fs.open('./demo.txt', 'w'); + * @example >> const fs = require('fs'); + * >> const txtOutStream = fs.open('./demo.txt', 'w'); * >> txtOutStream.print('foo', 'bar', 'baz'); * * // demo.txt content: @@ -555,7 +555,7 @@ exports.TextStream = function TextStream(io, options, buflen) { * @return {TextStream} this stream */ this.print = function () { - for (var i = 0; i < arguments.length; i++) { + for (let i = 0; i < arguments.length; i++) { this.write(String(arguments[i])); if (i < arguments.length - 1) { this.write(delimiter); @@ -588,7 +588,7 @@ exports.TextStream = function TextStream(io, options, buflen) { */ Object.defineProperty(this, "content", { get: function() { - var wrappedContent = io.content; + const wrappedContent = io.content; if (!wrappedContent) { return ""; } From 88eaa88278170b199df21411be99a6017aa0d079 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Thu, 29 Oct 2020 16:55:25 +0100 Subject: [PATCH 05/52] code modernization, added tests for net module --- modules/net.js | 116 ++++++++++++++++++++++------------------------- test/all.js | 1 + test/net_test.js | 76 +++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 62 deletions(-) create mode 100644 test/net_test.js diff --git a/modules/net.js b/modules/net.js index 615e5196d..e1db44dd1 100644 --- a/modules/net.js +++ b/modules/net.js @@ -5,18 +5,18 @@ * binding is provided by the `java.net` package. * * @example // A simple TCP server - * var io = require('io'); - * var net = require('net'); + * const io = require('io'); + * const net = require('net'); * - * var server = new net.ServerSocket(); + * const server = new net.ServerSocket(); * server.bind('127.0.0.1', 6789); * - * var socket = server.accept(); - * var stream = new io.TextStream(socket.getStream(), { + * const socket = server.accept(); + * const stream = new io.TextStream(socket.getStream(), { * 'charset': 'US-ASCII' *}); * - * var line; + * let line; * do { * // Read one line from the client * line = stream.readLine(); @@ -31,13 +31,14 @@ * server.close(); */ -var io = require('io'); -var binary = require('binary'); -var net = java.net; +const io = require('io'); +const binary = require('binary'); -exports.Socket = Socket; -exports.ServerSocket = ServerSocket; -exports.DatagramSocket = DatagramSocket; +const toSocketAddress = function(host, port) { + host = host || ""; + port = port || 0; + return new java.net.InetSocketAddress(host, port); +}; /** * The Socket class is used to create a TCP socket. Newly created sockets must @@ -45,16 +46,16 @@ exports.DatagramSocket = DatagramSocket; * @constructor * @class Socket */ -function Socket() { - var socket, stream; - var arg = arguments[0]; +const Socket = exports.Socket = function() { + let stream; + const arg = arguments[0]; if(!(this instanceof Socket)) { return arg ? new Socket(arg) : new Socket(); } // Either create a new socket or a wrapper around an existing socket - socket = arg instanceof net.Socket ? arg : new net.Socket(); + const socket = arg instanceof java.net.Socket ? arg : new java.net.Socket(); /** * Initiate a connection on a socket. Connect to a remote port on the specified @@ -65,7 +66,7 @@ function Socket() { * @param {Number} [timeout] optional timeout value in milliseconds */ this.connect = function(host, port, timeout) { - var address = toSocketAddress(host, port); + const address = toSocketAddress(host, port); if (arguments.length < 3) { socket.connect(address); } else { @@ -82,7 +83,7 @@ function Socket() { * @param {Number} port port number to bind the socket to. */ this.bind = function(host, port) { - var address = toSocketAddress(host, port); + const address = toSocketAddress(host, port); socket.bind(address); return this; }; @@ -179,23 +180,40 @@ function Socket() { this.close = function() { socket.close(); }; -} + + return this; +}; /** * The DatagramSocket class is used to create a UDP socket. * @constructor */ -function DatagramSocket() { - - var socket; - var arg = arguments[0]; - +const DatagramSocket = exports.DatagramSocket = function() { + const arg = arguments[0]; if(!(this instanceof DatagramSocket)) { return arg ? new DatagramSocket(arg) : new DatagramSocket(); } // Either create a new socket or a wrapper around an existing socket - socket = arg instanceof net.DatagramSocket ? arg : new net.DatagramSocket(null); + const socket = arg instanceof java.net.DatagramSocket ? arg : new java.net.DatagramSocket(null); + + function receiveInternal(length, buffer) { + length = length || 1024; + buffer = buffer || new binary.ByteArray(length); + const packet = new java.net.DatagramPacket(buffer, length); + socket.receive(packet); + return packet; + } + + function toDatagramPacket(arg) { + if (arg instanceof binary.Binary) { + return new java.net.DatagramPacket(arg, arg.length); + } else if (typeof arg === "string") { + return new java.net.DatagramPacket(arg.toByteString(), arg.length); + } else { + throw new Error("Unsupported argument to send: " + arg); + } + } /** * Connect the socket to a remote address. If a DatagramSocket is connected, @@ -206,7 +224,7 @@ function DatagramSocket() { * @param {Number} port port number or service name */ this.connect = function(host, port) { - var address = toSocketAddress(host, port); + const address = toSocketAddress(host, port); socket.connect(address); return this; }; @@ -226,7 +244,7 @@ function DatagramSocket() { * @param {Number} port port number to bind the socket to. */ this.bind = function(host, port) { - var address = toSocketAddress(host, port); + const address = toSocketAddress(host, port); socket.bind(address); return this; }; @@ -292,7 +310,7 @@ function DatagramSocket() { * @return {ByteArray} the received data */ this.receive = function(length, buffer) { - var packet = receiveInternal(length, buffer); + const packet = receiveInternal(length, buffer); buffer = ByteArray.wrap(packet.getData()); buffer.length = packet.length; return buffer; @@ -311,7 +329,7 @@ function DatagramSocket() { * @return {Object} the received packet */ this.receiveFrom = function(length, buffer) { - var packet = receiveInternal(length, buffer); + const packet = receiveInternal(length, buffer); buffer = ByteArray.wrap(packet.getData()); buffer.length = packet.length; return { @@ -338,7 +356,7 @@ function DatagramSocket() { * @param {Binary} data the data to send */ this.sendTo = function(host, port, data) { - var packet = toDatagramPacket(data); + const packet = toDatagramPacket(data); packet.setSocketAddress(toSocketAddress(host, port)); socket.send(packet); } @@ -369,41 +387,22 @@ function DatagramSocket() { socket.close(); }; - function receiveInternal(length, buffer) { - length = length || 1024; - buffer = buffer || new binary.ByteArray(length); - var packet = new net.DatagramPacket(buffer, length); - socket.receive(packet); - return packet; - } - - function toDatagramPacket(arg) { - if (arg instanceof binary.Binary) { - return new net.DatagramPacket(arg, arg.length); - } else if (typeof arg === "string") { - return new net.DatagramPacket(arg.toByteString(), arg.length); - } else { - throw new Error("Unsupported argument to send: " + arg); - } - } -} + return this; +}; /** * This class implements a server socket. Server sockets wait for requests * coming in over the network. * @constructor */ -function ServerSocket() { - - var socket; - var arg = arguments[0]; - +const ServerSocket = exports.ServerSocket = function() { + const arg = arguments[0]; if(!(this instanceof ServerSocket)) { return arg ? new ServerSocket(arg) : new ServerSocket(); } // Either create a new socket or a wrapper around an existing socket - socket = arg instanceof net.ServerSocket ? arg : new net.ServerSocket(); + const socket = arg instanceof java.net.ServerSocket ? arg : new java.net.ServerSocket(); /** * Listens for a connection to be made to this socket and returns a new @@ -422,7 +421,7 @@ function ServerSocket() { * @param {Number} port port number to bind the socket to. */ this.bind = function(host, port, backlog) { - var address = toSocketAddress(host, port); + const address = toSocketAddress(host, port); if (arguments.length < 3) { socket.bind(address); } else { @@ -487,10 +486,3 @@ function ServerSocket() { socket.close(); }; } - -function toSocketAddress(host, port) { - host = host || ""; - port = port || 0; - return new net.InetSocketAddress(host, port); -} - diff --git a/test/all.js b/test/all.js index db3efa9e7..b3ec43b34 100644 --- a/test/all.js +++ b/test/all.js @@ -8,6 +8,7 @@ exports.testEncoding = require('./ringo/encoding_test'); exports.testEvents = require('./ringo/events_test'); exports.testHttpClient = require('./ringo/httpclient_test'); exports.testJsgi = require('./ringo/jsgi/all'); +exports.testNet = require('./net_test'); exports.testPromise = require('./ringo/promise_test'); exports.testScheduler = require('./ringo/scheduler_test'); exports.testWebSocket = require('./ringo/websocket_test'); diff --git a/test/net_test.js b/test/net_test.js new file mode 100644 index 000000000..2373f2229 --- /dev/null +++ b/test/net_test.js @@ -0,0 +1,76 @@ +const assert = require("assert"); +const {Socket, ServerSocket, DatagramSocket} = require("net"); +const {TextStream} = require("io"); +const {Semaphore} = require("ringo/concurrent"); +const {Arrays} = java.util; + +const HOST = "localhost"; +const HOST_IP = "127.0.0.1"; +const PORT = 65432; + +exports.testTCP = () => { + const semaphores = { + "server": new Semaphore(), + "client": new Semaphore() + }; + const messages = { + "toServer": null, + "toClient": null + }; + const serverSocket = new ServerSocket(); + serverSocket.bind(HOST, PORT); + spawn(() => { + const socket = serverSocket.accept(); + const stream = new TextStream(socket.getStream()); + messages.toServer = stream.readLine(); + stream.writeLine("world"); + semaphores.server.signal(); + }); + + const socket = new Socket(); + spawn(() => { + socket.connect(HOST, PORT); + const stream = new TextStream(socket.getStream()); + stream.writeLine("hello"); + messages.toClient = stream.readLine(); + semaphores.client.signal(); + }); + semaphores.server.tryWait(200); + semaphores.client.tryWait(200); + assert.strictEqual(messages.toServer, "hello\n"); + assert.strictEqual(messages.toClient, "world\n"); +}; + +exports.testUDP = () => { + const semaphores = { + "server": new Semaphore(), + "client": new Semaphore() + }; + const messages = { + "toServer": null, + "toClient": null + }; + const serverSocket = new DatagramSocket(); + serverSocket.bind(HOST, PORT); + spawn(() => { + messages.toServer = serverSocket.receiveFrom(5); + serverSocket.sendTo(HOST_IP, PORT + 1, "world"); + semaphores.server.signal(); + }); + + const clientSocket = new DatagramSocket(); + clientSocket.bind(HOST, PORT + 1); + spawn(() => { + clientSocket.sendTo(HOST_IP, PORT, "hello"); + semaphores.client.signal(); + messages.toClient = clientSocket.receiveFrom(5); + }); + semaphores.server.tryWait(200); + semaphores.client.tryWait(200); + assert.strictEqual(messages.toServer.address, HOST_IP); + assert.strictEqual(messages.toServer.port, PORT + 1); + assert.isTrue(Arrays.equals(messages.toServer.data, "hello".toByteArray())); + assert.strictEqual(messages.toClient.address, HOST_IP); + assert.strictEqual(messages.toClient.port, PORT); + assert.isTrue(Arrays.equals(messages.toClient.data, "world".toByteArray())); +}; From efbc42bded5266f428a720d9a8a23a8735736da3 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Thu, 29 Oct 2020 17:18:17 +0100 Subject: [PATCH 06/52] code modernization --- modules/system.js | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/modules/system.js b/modules/system.js index 3989868b3..725065c22 100644 --- a/modules/system.js +++ b/modules/system.js @@ -5,24 +5,26 @@ * function is provided. */ -var stdin, stdout, stderr; -var System = java.lang.System; +const {System} = java.lang; +let stdin, stdout, stderr; /** * A [TextStream](../io/#TextStream) to read from stdin. * @name stdin */ Object.defineProperty(exports, "stdin", { - get: function() { + get: () => { if (!stdin) { - var {Stream, TextStream} = require('io'); + const {Stream, TextStream} = require('io'); stdin = new TextStream(new Stream(System['in'])); } return stdin; }, - set: function(value) { + set: (value) => { stdin = value; - }, configurable: true, enumerable: true + }, + configurable: true, + enumerable: true }); /** @@ -30,16 +32,18 @@ Object.defineProperty(exports, "stdin", { * @name stdout */ Object.defineProperty(exports, "stdout", { - get: function() { + get: () => { if (!stdout) { - var {Stream, TextStream} = require('io'); + const {Stream, TextStream} = require('io'); stdout = new TextStream(new Stream(System.out)); } return stdout; }, - set: function(value) { + set: (value) => { stdout = value; - }, configurable: true, enumerable: true + }, + configurable: true, + enumerable: true }); /** @@ -47,16 +51,18 @@ Object.defineProperty(exports, "stdout", { * @name stderr */ Object.defineProperty(exports, "stderr", { - get: function() { + get: () => { if (!stderr) { - var {Stream, TextStream} = require('io'); + const {Stream, TextStream} = require('io'); stderr = new TextStream(new Stream(System.err)); } return stderr; }, - set: function(value) { + set: (value) => { stderr = value; - }, configurable: true, enumerable: true + }, + configurable: true, + enumerable: true }); /** @@ -99,4 +105,4 @@ exports.env = new ScriptableMap(System.getenv()); */ exports.exit = function(status) { System.exit(status || 0); -}; \ No newline at end of file +}; From 9213031160c54c588ed3b316dddde1915a18dce9 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Thu, 29 Oct 2020 17:43:22 +0100 Subject: [PATCH 07/52] code modernization --- modules/test.js | 136 ++++++++++++++++++++---------------------------- 1 file changed, 56 insertions(+), 80 deletions(-) diff --git a/modules/test.js b/modules/test.js index 855193529..22011ba81 100644 --- a/modules/test.js +++ b/modules/test.js @@ -33,17 +33,17 @@ * assertion library to write unit tests. */ -var strings = require("ringo/utils/strings"); -var term = require("ringo/term"); -var fs = require("fs"); +const strings = require("ringo/utils/strings"); +const term = require("ringo/term"); +const fs = require("fs"); const {AssertionError, ArgumentsError} = require("./assert"); -const { - jsDump, - getType, - getStackTrace -} = require("./ringo/utils/test"); +const {jsDump, getType, getStackTrace} = require("./ringo/utils/test"); + +exports.jsDump = jsDump; +exports.getStackTrace = getStackTrace; +exports.getType = getType; /** * The main runner method. This method can be called with one, two or three @@ -55,7 +55,7 @@ const { * @param {Object} writer Optional writer to use for displaying the test results. Defaults * to TermWriter. */ -function run(scope, name, writer) { +const run = exports.run = function(scope, name, writer) { if (arguments.length === 2) { if (typeof(arguments[1]) === "object") { writer = name; @@ -69,7 +69,7 @@ function run(scope, name, writer) { if (typeof(scope) === "string") { scope = require(fs.resolve(fs.workingDirectory(), scope)); } - var summary = { + const summary = { "testsRun": 0, "passed": 0, "errors": 0, @@ -77,7 +77,7 @@ function run(scope, name, writer) { "time": 0 }; writer.writeHeader(); - if (name != undefined) { + if (name !== undefined) { executeTest(scope, name, summary, writer, []); } else { executeTestScope(scope, summary, writer, []); @@ -85,7 +85,7 @@ function run(scope, name, writer) { scope = null; writer.writeSummary(summary); return summary.failures + summary.errors; -} +}; /** * Loops over all properties of a test scope and executes all methods whose @@ -95,16 +95,13 @@ function run(scope, name, writer) { * @param {Object} writer A writer instance for displaying test results * @param {Array} path An array containing property path segments */ -function executeTestScope(scope, summary, writer, path) { +const executeTestScope = (scope, summary, writer, path) => { // loop over all exported properties and see if there are test methods to run - for (var name in scope) { - var value = scope[name]; - if (name === "test" || !strings.startsWith(name, "test")) { - continue; + Object.keys(scope).forEach(name => { + if (name !== "test" && strings.startsWith(name, "test")) { + executeTest(scope, name, summary, writer, path); } - executeTest(scope, name, summary, writer, path); - } - return; + }); }; /** @@ -116,21 +113,21 @@ function executeTestScope(scope, summary, writer, path) { * @param {Object} writer A writer instance for displaying test results * @param {Array} path An array containing property path segments */ -function executeTest(scope, name, summary, writer, path) { - var value = scope[name]; +const executeTest = (scope, name, summary, writer, path) => { + const value = scope[name]; if (value instanceof Function) { writer.writeTestStart(name); - var start = null; - var time = 0; + let start = null; + let time = 0; try { // execute setUp, if defined if (typeof(scope.setUp) === "function") { scope.setUp(); } // execute test function - start = new Date(); + start = Date.now(); value(); - time = (new Date()).getTime() - start.getTime(); + time = Date.now() - start; writer.writeTestPassed(time); summary.passed += 1; } catch (e) { @@ -156,8 +153,7 @@ function executeTest(scope, name, summary, writer, path) { executeTestScope(value, summary, writer, path.concat([name])); writer.exitScope(name); } - return; -} +}; @@ -174,7 +170,7 @@ function executeTest(scope, name, summary, writer, path) { * @returns {TermWriter} A newly created TermWriter instance * @constructor */ -var TermWriter = function() { +const TermWriter = function() { this.indent = ""; return this; }; @@ -214,7 +210,6 @@ TermWriter.prototype.exitScope = function() { */ TermWriter.prototype.writeTestStart = function(name) { term.write(this.indent, "+ Running", name, "..."); - return; }; /** @@ -223,7 +218,6 @@ TermWriter.prototype.writeTestStart = function(name) { */ TermWriter.prototype.writeTestPassed = function(time) { term.writeln(term.BOLD, " PASSED", term.RESET, "(" + time + " ms)"); - return; }; /** @@ -243,7 +237,6 @@ TermWriter.prototype.writeTestFailed = function(exception) { term.writeln(" at " + exception.fileName + ":" + exception.lineNumber); } term.writeln(""); - return; }; /** @@ -258,7 +251,6 @@ TermWriter.prototype.writeSummary = function(summary) { } else { term.writeln("No tests found"); } - return; }; /** * Creates a new EvaluationError instance @@ -270,40 +262,13 @@ TermWriter.prototype.writeSummary = function(summary) { * @constructor * @exteds TestException */ -function EvaluationError(messageOrException) { - var message = undefined; - var exception = null; - var stackTrace = null; - var fileName = null; - var lineNumber = -1; - - Object.defineProperty(this, "message", { - get: function() { - return message; - } - }); +const EvaluationError = function(messageOrException) { + let message = undefined; + let exception = null; + let stackTrace = null; + let fileName = null; + let lineNumber = -1; - Object.defineProperty(this, "stackTrace", { - get: function() { - return stackTrace; - } - }); - - Object.defineProperty(this, "fileName", { - get: function() { - return fileName; - } - }); - - Object.defineProperty(this, "lineNumber", { - get: function() { - return lineNumber; - } - }); - - /** - * Main constructor body - */ if (messageOrException instanceof Error) { exception = messageOrException; } else if (typeof(messageOrException.toString) === 'function') { @@ -314,7 +279,7 @@ function EvaluationError(messageOrException) { if (exception != null) { if (exception.rhinoException != null) { - var e = exception.rhinoException; + const e = exception.rhinoException; message += e.details(); stackTrace = getStackTrace(e.getStackTrace()); } else if (exception instanceof Error) { @@ -326,28 +291,39 @@ function EvaluationError(messageOrException) { lineNumber = exception.lineNumber || null; } } + + Object.defineProperties(this, { + "message": { + "value": message + }, + "stackTrace": { + "value": stackTrace + }, + "fileName": { + "value": fileName + }, + "lineNumber": { + "value": lineNumber + } + }); + return this; }; -EvaluationError.prototype = new Error(); - -module.exports.run = run; -module.exports.jsDump = jsDump; -module.exports.getStackTrace = getStackTrace; -module.exports.getType = getType; +EvaluationError.prototype = Object.create(Error.prototype); +EvaluationError.prototype.constructor = EvaluationError; /** * Executed when called from the command line */ if (require.main === module) { - var system = require("system"); - if (system.args.length == 1) { + const system = require("system"); + if (system.args.length === 1) { term.writeln("Usage: bin/ringo test test/file1 test/file2"); } else { - var writer = new TermWriter(); - var failures = 0; - for (var i=1; i { + return result + this.run(arg, writer); + }, 0); system.exit(failures); } } From 3fdd0997721535e17418073079f21fc483e5ae90 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Sat, 31 Oct 2020 11:08:46 +0100 Subject: [PATCH 08/52] code modernization, added test for help() method --- modules/ringo/args.js | 189 +++++++++++++++++++--------------------- test/ringo/args_test.js | 39 +++++---- 2 files changed, 113 insertions(+), 115 deletions(-) diff --git a/modules/ringo/args.js b/modules/ringo/args.js index ef42a4897..b9109f8d6 100644 --- a/modules/ringo/args.js +++ b/modules/ringo/args.js @@ -14,16 +14,16 @@ * @example // ringo parserExample.js -v --size 123 -p 45678 * * include('ringo/term'); - * var system = require('system'); - * var {Parser} = require('ringo/args'); + * const system = require('system'); + * const {Parser} = require('ringo/args'); * - * var parser = new Parser(); + * const parser = new Parser(); * parser.addOption('s', 'size', 'SIZE', 'Sets the size to SIZE'); * parser.addOption('p', 'pid', 'PID', 'Kill the process with the PID'); * parser.addOption('v', 'verbose', null, 'Verbosely do something'); * parser.addOption('h', 'help', null, 'Show help'); * - * var options = parser.parse(system.args.slice(1)); + * const options = parser.parse(system.args.slice(1)); * if (options.help) { * writeln(parser.help()); *} else { @@ -45,13 +45,85 @@ * } */ -var strings = require("ringo/utils/strings"); +const strings = require("ringo/utils/strings"); +const missingValueError = (option) => new Error(option + " option requires a value."); +const unknownOptionError = (option) => new Error("Unknown option: " + option); + +const parseShortOption = (options, opt, args, result) => { + const length = opt.length; + let consumedNext = false; + for (let i = 0; i < length; i++) { + let def = null; + let c = opt.charAt(i); + for (let d of options) { + if (d.shortName === c) { + def = d; + break; + } + } + if (def == null) { + throw unknownOptionError("-" + c); + } + let optarg = null; + if (def.argument) { + if (i === length - 1) { + if (args.length <= 1) { + throw missingValueError("-" + def.shortName); + } + optarg = args[1]; + consumedNext = true; + } else { + optarg = opt.substring(i + 1); + if (optarg.length === 0) { + throw missingValueError("-" + def.shortName); + } + } + i = length; + } + let propertyName = def.longName || def.shortName; + result[strings.toCamelCase(propertyName)] = optarg || true; + } + args.splice(0, consumedNext ? 2 : 1); +}; + +const parseLongOption = (options, opt, args, result) => { + let def = null; + for (let d of options) { + if (opt === d.longName || (strings.startsWith(opt, d.longName) + && opt.charAt(d.longName.length) === '=')) { + def = d; + break; + } + } + if (def == null) { + throw unknownOptionError("--" + opt); + } + let optarg = null; + let consumedNext = false; + if (def.argument) { + if (opt === def.longName) { + if (args.length <= 1) { + throw missingValueError("--" + def.longName); + } + optarg = args[1]; + consumedNext = true; + } else { + const length = def.longName.length; + if (opt.charAt(length) !== '=') { + throw missingValueError("--" + def.longName); + } + optarg = opt.substring(length + 1); + } + } + result[strings.toCamelCase(def.longName)] = optarg || true; + args.splice(0, consumedNext ? 2 : 1); +}; /** * Create a new command line option parser. */ exports.Parser = function() { - var options = []; + const options = []; /** * Add an option to the parser. @@ -62,7 +134,7 @@ exports.Parser = function() { * @returns {Object} this parser for chained invocation */ this.addOption = function(shortName, longName, argument, helpText) { - if (shortName && shortName.length != 1) { + if (typeof(shortName) !== "string" || shortName.length !== 1) { throw new Error("Short option must be a string of length 1"); } longName = longName || ""; @@ -81,9 +153,8 @@ exports.Parser = function() { * @returns {String} a string explaining the parser's options */ this.help = function() { - var lines = []; - for each (var opt in options) { - var flags; + const lines = options.reduce((lines, opt) => { + let flags; if (opt.shortName !== undefined && opt.shortName !== null) { flags = " -" + opt.shortName; } else { @@ -96,11 +167,12 @@ exports.Parser = function() { flags += " " + opt.argument; } lines.push({flags: flags, helpText: opt.helpText}); - } - var maxlength = lines.reduce(function(prev, val) Math.max(val.flags.length, prev), 0); - return lines.map( - function(s) strings.pad(s.flags, " ", 2 + maxlength) + s.helpText - ).join("\n"); + return lines; + }, []); + const maxlength = lines.reduce((prev, val) => Math.max(val.flags.length, prev), 0); + return lines.map(s => { + return strings.pad(s.flags, " ", 2 + maxlength) + s.helpText; + }).join("\n"); }; /** @@ -117,97 +189,20 @@ exports.Parser = function() { * @example parser.parse(system.args.slice(1), {myOption: "defaultValue"}); */ this.parse = function(args, result) { - result = result || {}; + result || (result = {}); while (args.length > 0) { - var option = args[0]; + let option = args[0]; if (!strings.startsWith(option, "-")) { break; } if (strings.startsWith(option, "--")) { - parseLongOption(option.substring(2), args, result); + parseLongOption(options, option.substring(2), args, result); } else { - parseShortOption(option.substring(1), args, result); + parseShortOption(options, option.substring(1), args, result); } } return result; }; - function parseShortOption(opt, args, result) { - var length = opt.length; - var consumedNext = false; - for (var i = 0; i < length; i++) { - var def = null; - var c = opt.charAt(i); - for each (var d in options) { - if (d.shortName == c) { - def = d; - break; - } - } - if (def == null) { - unknownOptionError("-" + c); - } - var optarg = null; - if (def.argument) { - if (i == length - 1) { - if (args.length <= 1) { - missingValueError("-" + def.shortName); - } - optarg = args[1]; - consumedNext = true; - } else { - optarg = opt.substring(i + 1); - if (optarg.length == 0) { - missingValueError("-" + def.shortName); - } - } - i = length; - } - var propertyName = def.longName || def.shortName; - result[strings.toCamelCase(propertyName)] = optarg || true; - } - args.splice(0, consumedNext ? 2 : 1); - } - - function parseLongOption(opt, args, result) { - var def = null; - for each (var d in options) { - if (opt == d.longName || (strings.startsWith(opt, d.longName) - && opt.charAt(d.longName.length) == '=')) { - def = d; - break; - } - } - if (def == null) { - unknownOptionError("--" + opt); - } - var optarg = null; - var consumedNext = false; - if (def.argument) { - if (opt == def.longName) { - if (args.length <= 1) { - missingValueError("--" + def.longName); - } - optarg = args[1]; - consumedNext = true; - } else { - var length = def.longName.length; - if (opt.charAt(length) != '=') { - missingValueError("--" + def.longName); - } - optarg = opt.substring(length + 1); - } - } - result[strings.toCamelCase(def.longName)] = optarg || true; - args.splice(0, consumedNext ? 2 : 1); - } + return this; }; - -function missingValueError(option) { - throw new Error(option + " option requires a value."); -} - - -function unknownOptionError(option) { - throw new Error("Unknown option: " + option); -} diff --git a/test/ringo/args_test.js b/test/ringo/args_test.js index d742a2e68..46b43b70d 100644 --- a/test/ringo/args_test.js +++ b/test/ringo/args_test.js @@ -1,30 +1,33 @@ -var assert = require("assert"); -var Parser = require('ringo/args').Parser; +const assert = require("assert"); +const Parser = require('ringo/args').Parser; exports.setUp = exports.tearDown = function() {} exports.testBasic = function () { - var p = new Parser(); + const p = new Parser(); p.addOption("q", null, null, "Be quiet about errors and warnings"); p.addOption("s", "silent", null, "Ignore errors and warnings"); p.addOption("c", "counter", "NUMBER", "Init counter with NUMBER"); - assert.deepEqual({silent: true}, p.parse(['-s'])); - assert.deepEqual({silent: true}, p.parse(['--silent'])); - assert.deepEqual({q: true}, p.parse(['-q'])); - assert.deepEqual({counter: "42"}, p.parse(['-c', '42'])); - assert.deepEqual({counter: "42"}, p.parse(['-c42'])); - assert.deepEqual({counter: "42"}, p.parse(['--counter=42'])); - assert.deepEqual({counter: "42"}, p.parse(['--counter', '42'])); - assert.deepEqual({counter: "42", silent: true, q: true}, p.parse(['-sqc42'])); - assert.deepEqual({counter: "42", silent: true, q: true}, p.parse(['-sqc', '42'])); + assert.strictEqual(p.help(), " -q Be quiet about errors and warnings\n" + + " -s --silent Ignore errors and warnings\n" + + " -c --counter NUMBER Init counter with NUMBER"); + assert.deepEqual(p.parse(['-s']), {silent: true}); + assert.deepEqual(p.parse(['--silent']), {silent: true}); + assert.deepEqual(p.parse(['-q']), {q: true}); + assert.deepEqual(p.parse(['-c', '42']), {counter: "42"}); + assert.deepEqual(p.parse(['-c42']), {counter: "42"}); + assert.deepEqual(p.parse(['--counter=42']), {counter: "42"}); + assert.deepEqual(p.parse(['--counter', '42']), {counter: "42"}); + assert.deepEqual(p.parse(['-sqc42']), {counter: "42", silent: true, q: true}); + assert.deepEqual(p.parse(['-sqc', '42']), {counter: "42", silent: true, q: true}); // missing option argument - assert.throws(function() {p.parse(['--counter']);}); - assert.throws(function() {p.parse(['-c']);}); - assert.throws(function() {p.parse(['-sqc']);}); + assert.throws(() => p.parse(['--counter'])); + assert.throws(() => p.parse(['-c'])); + assert.throws(() => p.parse(['-sqc'])); // unknown option - assert.throws(function() {p.parse(['--unknown']);}); - assert.throws(function() {p.parse(['-u']);}); - assert.throws(function() {p.parse(['-squ']);}); + assert.throws(() => p.parse(['--unknown'])); + assert.throws(() => p.parse(['-u'])); + assert.throws(() => p.parse(['-squ'])); }; if (require.main === module) { From 26207a8dede592cedc3750ee8986e66858e699c2 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Sat, 31 Oct 2020 11:27:59 +0100 Subject: [PATCH 09/52] code modernization --- modules/ringo/base64.js | 63 ++++++++++++++++++++------------------- test/ringo/base64_test.js | 18 +++++------ 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/modules/ringo/base64.js b/modules/ringo/base64.js index 5a2e40888..39841a721 100644 --- a/modules/ringo/base64.js +++ b/modules/ringo/base64.js @@ -14,22 +14,22 @@ /** * @fileOverview Base64 encoding and decoding for binary data and strings. - * @example >> var base64 = require('ringo/base64'); - * >> var enc = base64.encode('Hello World!', 'ISO-8859-15'); + * @example >> const base64 = require('ringo/base64'); + * >> const enc = base64.encode('Hello World!', 'ISO-8859-15'); * >> print(enc); * 'SGVsbG8gV29ybGQh' * >> print(base64.decode(enc, 'ISO-8859-15')); * Hello World! */ -var encodeChars = [ +const encodeChars = [ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47]; -var decodeChars = [ +const decodeChars = [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, @@ -40,9 +40,9 @@ var decodeChars = [ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 ]; -var padding = "=".charCodeAt(0); +const padding = "=".charCodeAt(0); -var {Binary, ByteString, ByteArray} = require('binary'); +const {Binary, toByteString, ByteArray} = require('binary'); /** * Encode a string or binary to a Base64 encoded string @@ -52,16 +52,16 @@ var {Binary, ByteString, ByteArray} = require('binary'); * @returns {String} the Base64 encoded string */ exports.encode = function(str, encoding) { - var c1, c2, c3; - encoding = encoding || 'utf8'; - var input = str instanceof Binary ? str : String(str).toByteString(encoding); - var length = input.length; - var output = new ByteArray(4 * (length + (3 - length % 3) % 3) / 3); + const input = str instanceof Binary ? str : toByteString(str, encoding || 'utf8'); + const length = input.length; + const output = new ByteArray(4 * (length + (3 - length % 3) % 3) / 3); - var i = 0, j = 0; + let i = 0; + let j = 0; + let c1, c2, c3; while(i < length) { c1 = input[i++]; - if(i == length) { + if (i === length) { output[j++] = encodeChars[c1 >> 2]; output[j++] = encodeChars[(c1 & 0x3) << 4]; output[j++] = padding; @@ -69,7 +69,7 @@ exports.encode = function(str, encoding) { break; } c2 = input[i++]; - if(i == length) { + if (i === length) { output[j++] = encodeChars[c1 >> 2]; output[j++] = encodeChars[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)]; output[j++] = encodeChars[(c2 & 0xF) << 2]; @@ -95,28 +95,29 @@ exports.encode = function(str, encoding) { * @returns {String|ByteArray} the decoded string or ByteArray */ exports.decode = function (str, encoding) { - var c1, c2, c3, c4; - var input = str instanceof Binary ? str : String(str).toByteString('ascii'); - var length = input.length; - var output = new ByteArray(length * 3 / 4); - var i = 0, j = 0; + const input = str instanceof Binary ? str : toByteString(str, 'ascii'); + const length = input.length; + const output = new ByteArray(length * 3 / 4); + let i = 0; + let j = 0; + let c1, c2, c3, c4; outer: while(i < length) { /* c1 */ do { c1 = decodeChars[input[i++]]; - } while(i < length && c1 == -1); + } while (i < length && c1 === -1); - if(c1 == -1) { + if (c1 === -1) { break; } /* c2 */ do { c2 = decodeChars[input[i++]] - } while(i < length && c2 == -1); + } while (i < length && c2 === -1); - if(c2 == -1) { + if (c2 === -1) { break; } @@ -125,13 +126,13 @@ exports.decode = function (str, encoding) { /* c3 */ do { c3 = input[i++]; - if(c3 == padding) { + if (c3 === padding) { break outer; } c3 = decodeChars[c3]; - } while(i < length && c3 == -1); + } while (i < length && c3 === -1); - if(c3 == -1) { + if (c3 === -1) { break; } @@ -140,13 +141,13 @@ exports.decode = function (str, encoding) { /* c4 */ do { c4 = input[i++]; - if(c4 == padding) { + if (c4 === padding) { break outer; } c4 = decodeChars[c4]; - } while(i < length && c4 == -1); + } while (i < length && c4 === -1); - if(c4 == -1) { + if (c4 === -1) { break; } @@ -154,8 +155,8 @@ exports.decode = function (str, encoding) { } output.length = j; - encoding = encoding || 'utf8'; - return encoding == 'raw' ? output : output.decodeToString(encoding); + encoding || (encoding = 'utf8'); + return (encoding === 'raw') ? output : output.decodeToString(encoding); }; diff --git a/test/ringo/base64_test.js b/test/ringo/base64_test.js index b26057bd1..69d0af1c7 100644 --- a/test/ringo/base64_test.js +++ b/test/ringo/base64_test.js @@ -1,8 +1,8 @@ -var assert = require("assert"); -var base64 = require('ringo/base64'); -var {ByteString} = require('binary'); +const assert = require("assert"); +const base64 = require('ringo/base64'); +const {toByteString} = require('binary'); -var data = [ +const data = [ ["pleasure", "cGxlYXN1cmU="], ["leasure", "bGVhc3VyZQ=="], ["easure", "ZWFzdXJl"], @@ -12,15 +12,15 @@ var data = [ ]; exports.testEncodeDecode = function () { - for each (var test in data) { + data.forEach(test => { assert.strictEqual(base64.encode(test[0]), test[1]); assert.strictEqual(base64.decode(base64.encode(test[0])), test[0]); assert.deepEqual(base64.decode( - base64.encode(test[0]), 'raw').toArray(), - new ByteString(test[0], 'utf8').toArray()); - } + base64.encode(test[0]), 'raw').toArray(), + toByteString(test[0], 'utf8').toArray()); + }); }; if (require.main === module) { require('system').exit(require("test").run(module.id)); -} \ No newline at end of file +} From b0bac7e3af1b048ef1b593fae2b65c26d1e42794 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Sat, 31 Oct 2020 11:32:47 +0100 Subject: [PATCH 10/52] code modernization --- modules/ringo/buffer.js | 26 +++++++++++++------------- test/ringo/buffer_test.js | 22 +++++++++++----------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/modules/ringo/buffer.js b/modules/ringo/buffer.js index d17f8ef29..635af62e3 100644 --- a/modules/ringo/buffer.js +++ b/modules/ringo/buffer.js @@ -2,8 +2,8 @@ * @fileOverview A simple text Buffer class for composing strings. */ -var {ByteString} = require('binary'); -var strings = require('ringo/utils/strings'); +const binary = require('binary'); +const strings = require('ringo/utils/strings'); /** * A Buffer class for composing strings. This is implemented @@ -12,15 +12,15 @@ var strings = require('ringo/utils/strings'); */ module.exports.Buffer = function Buffer() { - var content = [], - length = 0; + const content = []; + let length = 0; /** * Reset the buffer discarding all its content. * @returns {Buffer} this buffer object */ this.reset = function() { - content = []; + content.length = 0; length = 0; return this; }; @@ -31,8 +31,8 @@ module.exports.Buffer = function Buffer() { * @returns {Buffer} this buffer object */ this.write = function() { - for (var i = 0; i < arguments.length; i++) { - var str = String(arguments[i]); + for (let i = 0; i < arguments.length; i++) { + let str = String(arguments[i]); content.push(str); length += str.length; } @@ -72,7 +72,7 @@ module.exports.Buffer = function Buffer() { * contained by this buffer. */ Object.defineProperty(this, "length", { - get: function() { return length; } + get: () => length }); /** @@ -81,11 +81,11 @@ module.exports.Buffer = function Buffer() { * @returns {String} a Base16 encoded digest */ this.digest = function(algorithm) { - var md = java.security.MessageDigest.getInstance(algorithm || "MD5"); - content.forEach(function(part) { - md.update(String(part).toByteString()); + const md = java.security.MessageDigest.getInstance(algorithm || "MD5"); + content.forEach(part => { + md.update(binary.toByteString(String(part))); }); - var b = ByteString.wrap(md.digest()); + const b = binary.ByteString.wrap(md.digest()); return strings.b16encode(b); }; @@ -94,4 +94,4 @@ module.exports.Buffer = function Buffer() { } return this; -} +}; diff --git a/test/ringo/buffer_test.js b/test/ringo/buffer_test.js index 5558c4829..436210055 100644 --- a/test/ringo/buffer_test.js +++ b/test/ringo/buffer_test.js @@ -1,12 +1,12 @@ -var assert = require("assert"); -include('ringo/buffer'); -var digest = require('ringo/utils/strings').digest; +const assert = require("assert"); +const {Buffer} = require('ringo/buffer'); +const digest = require('ringo/utils/strings').digest; -var buffer = new Buffer(); -var STRING1 = 'foo'; -var STRING2 = 'bar'; -var STRING3 = 'baz'; -var EOL = '\r\n'; +const buffer = new Buffer(); +const STRING1 = 'foo'; +const STRING2 = 'bar'; +const STRING3 = 'baz'; +const EOL = '\r\n'; exports.setUp = function () { buffer.reset(); @@ -27,9 +27,9 @@ exports.testWriteln = function () { }; exports.testForEach = function () { - var content = ''; // To concatenate buffer content. + let content = ''; // To concatenate buffer content. buffer.write(STRING1, STRING2); - buffer.forEach(function (it) content += it); + buffer.forEach(it => content += it); assert.strictEqual(STRING1 + STRING2, content); }; @@ -39,7 +39,7 @@ exports.testDigest = function () { }; exports.testLength = function() { - var expectedLength = 0; + let expectedLength = 0; assert.strictEqual(expectedLength, buffer.length); buffer.write(STRING1, STRING2); expectedLength = STRING1.length + STRING2.length; From dca404628676e586e395a1e77e9578280c03cf82 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 09:16:39 +0100 Subject: [PATCH 11/52] use require instead of include in code example to make things explicit --- modules/ringo/args.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/ringo/args.js b/modules/ringo/args.js index b9109f8d6..f69911f66 100644 --- a/modules/ringo/args.js +++ b/modules/ringo/args.js @@ -13,7 +13,7 @@ * * @example // ringo parserExample.js -v --size 123 -p 45678 * - * include('ringo/term'); + * const term = require('ringo/term'); * const system = require('system'); * const {Parser} = require('ringo/args'); * @@ -25,23 +25,23 @@ * * const options = parser.parse(system.args.slice(1)); * if (options.help) { - * writeln(parser.help()); + * term.writeln(parser.help()); *} else { * if (options.size) { - * writeln('Set size to ' + parseInt(options.size)); + * term.writeln('Set size to ' + parseInt(options.size)); * } * * if (options.pid) { - * writeln('Kill process ' + options.pid); + * term.writeln('Kill process ' + options.pid); * } * * if (options.verbose) { - * writeln('Verbose!'); + * term.writeln('Verbose!'); * } *} * * if (!Object.keys(options).length) { - * writeln("Run with -h/--help to see available options"); + * term.writeln("Run with -h/--help to see available options"); * } */ From cc17fbd463b2ece9fe9d22bb5b9d3aaa871f1f05 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 09:19:04 +0100 Subject: [PATCH 12/52] avoid redeclaration of consts binary module uses defineClass to modify the global scope, so we can't (re)declare ie. const Binary --- modules/ringo/base64.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/modules/ringo/base64.js b/modules/ringo/base64.js index 39841a721..c06bb9fbb 100644 --- a/modules/ringo/base64.js +++ b/modules/ringo/base64.js @@ -41,8 +41,7 @@ const decodeChars = [ ]; const padding = "=".charCodeAt(0); - -const {Binary, toByteString, ByteArray} = require('binary'); +const binary = require('binary'); /** * Encode a string or binary to a Base64 encoded string @@ -52,9 +51,9 @@ const {Binary, toByteString, ByteArray} = require('binary'); * @returns {String} the Base64 encoded string */ exports.encode = function(str, encoding) { - const input = str instanceof Binary ? str : toByteString(str, encoding || 'utf8'); + const input = str instanceof binary.Binary ? str : binary.toByteString(str, encoding || 'utf8'); const length = input.length; - const output = new ByteArray(4 * (length + (3 - length % 3) % 3) / 3); + const output = new binary.ByteArray(4 * (length + (3 - length % 3) % 3) / 3); let i = 0; let j = 0; @@ -95,9 +94,9 @@ exports.encode = function(str, encoding) { * @returns {String|ByteArray} the decoded string or ByteArray */ exports.decode = function (str, encoding) { - const input = str instanceof Binary ? str : toByteString(str, 'ascii'); + const input = str instanceof binary.Binary ? str : binary.toByteString(str, 'ascii'); const length = input.length; - const output = new ByteArray(length * 3 / 4); + const output = new binary.ByteArray(length * 3 / 4); let i = 0; let j = 0; let c1, c2, c3, c4; From 5ca27dbd23ceb2b19bdb251fea91457769c0f2ef Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 09:21:04 +0100 Subject: [PATCH 13/52] modernized/simplified code, added test for Semaphore --- modules/ringo/concurrent.js | 17 +++++++---------- test/all.js | 1 + test/ringo/concurrent_test.js | 12 ++++++++++++ 3 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 test/ringo/concurrent_test.js diff --git a/modules/ringo/concurrent.js b/modules/ringo/concurrent.js index e21cce379..d1e6b2968 100644 --- a/modules/ringo/concurrent.js +++ b/modules/ringo/concurrent.js @@ -2,7 +2,7 @@ * @fileoverview Utilities for working with multiple concurrently running threads. */ -var {Semaphore: JavaSemaphore, TimeUnit} = java.util.concurrent; +const {Semaphore: JavaSemaphore, TimeUnit} = java.util.concurrent; /** * A counting semaphore that can be used to coordinate and synchronize @@ -28,21 +28,19 @@ var {Semaphore: JavaSemaphore, TimeUnit} = java.util.concurrent; * * @param {Number} permits the number of initial permits, defaults to 0 */ -module.exports.Semaphore = function Semaphore(permits) { +exports.Semaphore = function Semaphore(permits) { if (!(this instanceof Semaphore)) { return new Semaphore(permits); } - if (typeof permits === "undefined") permits = 0; - var s = new JavaSemaphore(permits); + const semaphore = new JavaSemaphore(permits === undefined ? 0 : permits); /** * Wait for one or more permits. * @param {Number} permits the number of permits to wait for, defaults to 1 */ this.wait = function(permits) { - if (typeof permits === "undefined") permits = 1; - s.acquire(permits); + semaphore.acquire(permits === undefined ? 1 : permits); }; /** @@ -54,8 +52,8 @@ module.exports.Semaphore = function Semaphore(permits) { * timeout elapsed */ this.tryWait = function(timeout, permits) { - if (typeof permits === "undefined") permits = 1; - return s.tryAcquire(permits, timeout, TimeUnit.MILLISECONDS); + return semaphore.tryAcquire(permits === undefined ? 1 : permits, + timeout, TimeUnit.MILLISECONDS); }; /** @@ -63,7 +61,6 @@ module.exports.Semaphore = function Semaphore(permits) { * @param {Number} permits the number of permits to give, defaults to 1 */ this.signal = function(permits) { - if (typeof permits === "undefined") permits = 1; - s.release(permits); + semaphore.release(permits === undefined ? 1 : permits); }; } diff --git a/test/all.js b/test/all.js index b3ec43b34..e4b0b9409 100644 --- a/test/all.js +++ b/test/all.js @@ -4,6 +4,7 @@ exports.testAssertCommonJs = require('./assert_commonjs'); exports.testArgs = require('./ringo/args_test'); exports.testBase64 = require('./ringo/base64_test'); exports.testBuffer = require('./ringo/buffer_test'); +exports.testConcurrent = require('./ringo/concurrent_test'); exports.testEncoding = require('./ringo/encoding_test'); exports.testEvents = require('./ringo/events_test'); exports.testHttpClient = require('./ringo/httpclient_test'); diff --git a/test/ringo/concurrent_test.js b/test/ringo/concurrent_test.js new file mode 100644 index 000000000..05b2a2601 --- /dev/null +++ b/test/ringo/concurrent_test.js @@ -0,0 +1,12 @@ +const assert = require("assert"); +const {Semaphore} = require("ringo/concurrent"); + +exports.testSemaphore = () => { + let semaphore = new Semaphore(1); + semaphore.wait(); + spawn(() => { + java.lang.Thread.sleep(50); + semaphore.signal(2); + }); + assert.isTrue(semaphore.tryWait(55, 2)); +}; From 3fc56f20eedcd10433a02c64839c007043a5cda6 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 09:24:19 +0100 Subject: [PATCH 14/52] code modernization --- modules/ringo/daemon.js | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/modules/ringo/daemon.js b/modules/ringo/daemon.js index e82e4d673..311b1d08e 100644 --- a/modules/ringo/daemon.js +++ b/modules/ringo/daemon.js @@ -9,10 +9,10 @@ * as argument to the application life cycle functions. */ -var system = require('system'); -var log = require('ringo/logging').getLogger(module.id); +const system = require('system'); +const log = require('ringo/logging').getLogger(module.id); -var app; +let app; /** * Called when the daemon instance is created. @@ -20,12 +20,12 @@ var app; * This function can be run with superuser id to perform privileged actions * before the daemon is started. */ -function init() { +exports.init = () => { log.info("init", system.args); // Remove our own script name from args system.args.shift(); if (system.args.length) { - var appId = system.args[0]; + const appId = system.args[0]; try { app = require(appId); } catch (error) { @@ -38,39 +38,34 @@ function init() { if (app && typeof app.init === "function") { app.init(); } -} +}; /** * Called when the daemon instance is started. */ -function start() { +exports.start = () => { log.info("start"); if (app && typeof app.start === "function") { app.start(); } -} +}; /** * Called when the daemon is stopped. */ -function stop() { +exports.stop = () => { log.info("stop"); if (app && typeof app.stop === "function") { app.stop(); } -} +}; /** * Called when the daemon is destroyed. */ -function destroy() { +exports.destroy = () => { log.info("destroy"); if (app && typeof app.destroy === "function") { app.destroy(); } -} - -module.exports.init = init; -module.exports.start = start; -module.exports.stop = stop; -module.exports.destroy = destroy; +}; From f7dabd35e8843c86118f1bc6b8ba38b050b0f1c4 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 09:37:30 +0100 Subject: [PATCH 15/52] code modernization (ie. var -> const/let) --- modules/ringo/encoding.js | 120 +++++++++++++++++------------------- test/ringo/encoding_test.js | 44 ++++++------- 2 files changed, 79 insertions(+), 85 deletions(-) diff --git a/modules/ringo/encoding.js b/modules/ringo/encoding.js index e92165ab1..6b6ea7d83 100644 --- a/modules/ringo/encoding.js +++ b/modules/ringo/encoding.js @@ -2,28 +2,27 @@ * @fileOverview Low-level support for character encoding and decoding. * It uses the packages java.nio and java.nio.charset for the underlying operations. * - * @example var enc = new Encoder('utf-8'); + * @example const enc = new Encoder('utf-8'); * enc.encode('I \u2665 JS').encode('I \u2665 JS'); - * var bs = enc.toByteString(); + * const bs = enc.toByteString(); * * // prints 'I ♥ JSI ♥ JS' * console.log(bs.decodeToString('utf-8')); * - * var dec = new Decoder('ISO-8859-1'); - * var ba = new ByteArray([246, 228, 252]); + * const dec = new Decoder('ISO-8859-1'); + * const ba = new ByteArray([246, 228, 252]); * * // prints öäü * console.log(dec.decode(ba)); */ -var log = require("ringo/logging").getLogger(module.id); +const {Charset, CodingErrorAction} = java.nio.charset; +const {ByteBuffer, CharBuffer} = java.nio; +const StringUtils = org.ringojs.util.StringUtils; +const {String: JavaString} = java.lang; +const binary = require("binary"); -var {Charset, CharsetEncoder, CharsetDecoder, CodingErrorAction} = java.nio.charset; -var {ByteBuffer, CharBuffer} = java.nio; -var StringUtils = org.ringojs.util.StringUtils; -var JavaString = java.lang.String; - -var DEFAULTSIZE = 8192; +const DEFAULTSIZE = 8192; /** * Creates a new Decoder to transform a ByteString or ByteArray to a string. @@ -34,33 +33,32 @@ var DEFAULTSIZE = 8192; * @param {Number} capacity initial capacity for the input byte buffer and output character buffer. The output buffer's * size depends on the average bytes used per character by the charset. * @example // throws an Error: MALFORMED[1] - * var dec = new Decoder('ASCII', true); + * const dec = new Decoder('ASCII', true); * dec.decode(new ByteArray([246, 228, 252, 999999])); * * // replaces 999999 with a substitutions character ��� - * var dec = new Decoder('ASCII'); + * const dec = new Decoder('ASCII'); * dec.decode(new ByteArray([246, 228, 252, 999999])); */ -module.exports.Decoder = function Decoder(charset, strict, capacity) { +exports.Decoder = function Decoder(charset, strict, capacity) { if (!(this instanceof Decoder)) { return new Decoder(charset, strict, capacity); } - var decoder = Charset.forName(charset).newDecoder(); + const decoder = Charset.forName(charset).newDecoder(); // input buffer must be able to contain any character capacity = Math.max(capacity, 8) || DEFAULTSIZE; - var input = ByteBuffer.allocate(capacity); - var output = CharBuffer.allocate(decoder.averageCharsPerByte() * capacity); - var stream; - var mark = 0; - - var errorAction = strict ? + const input = ByteBuffer.allocate(capacity); + let output = CharBuffer.allocate(decoder.averageCharsPerByte() * capacity); + const errorAction = strict ? CodingErrorAction.REPORT : CodingErrorAction.REPLACE; decoder.onMalformedInput(errorAction); decoder.onUnmappableCharacter(errorAction); - var decoded; + let stream; + let mark = 0; + let decoded; /** * Decode bytes from the given buffer. @@ -72,7 +70,7 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { start = start || 0; end = end || bytes.length; while (end > start) { - var count = Math.min(end - start, input.capacity() - input.position()); + let count = Math.min(end - start, input.capacity() - input.position()); input.put(bytes, start, count); decodeInput(end - start); start += count; @@ -84,11 +82,11 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { // Internal function function decodeInput(remaining) { input.flip(); - var result = decoder.decode(input, output, false); + let result = decoder.decode(input, output, false); while (result.isOverflow()) { // grow output buffer capacity += Math.max(capacity, remaining); - var newOutput = CharBuffer.allocate(1.2 * capacity * decoder.averageCharsPerByte()); + let newOutput = CharBuffer.allocate(1.2 * capacity * decoder.averageCharsPerByte()); output.flip(); newOutput.append(output); output = newOutput; @@ -109,7 +107,7 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { */ this.close = function() { input.flip(); - var result = decoder.decode(input, output, true); + const result = decoder.decode(input, output, true); if (result.isError()) { decoder.reset(); input.clear(); @@ -125,7 +123,7 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { * @see readFrom */ this.read = function() { - var eof = false; + let eof = false; while (stream && !eof) { if (mark > 0) { output.limit(output.position()); @@ -133,8 +131,8 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { output.compact(); mark = 0; } - var position = input.position(); - var read = stream.readInto(ByteArray.wrap(input.array()), position, input.capacity()); + let position = input.position(); + let read = stream.readInto(ByteArray.wrap(input.array()), position, input.capacity()); if (read < 0) { // end of stream has been reached eof = true; @@ -145,7 +143,7 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { } output.flip(); decoded = null; // invalidate - return mark == output.limit() ? + return (mark === output.limit()) ? null : String(output.subSequence(mark, output.limit())); }; @@ -157,8 +155,8 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { * @see readFrom */ this.readLine = function(includeNewline) { - var eof = false; - var newline = StringUtils.searchNewline(output, mark); + let eof = false; + let newline = StringUtils.searchNewline(output, mark); while (stream && !eof && newline < 0) { if (mark > 0) { output.limit(output.position()); @@ -166,13 +164,13 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { output.compact(); mark = 0; } - var position = input.position(); - var read = stream.readInto(ByteArray.wrap(input.array()), position, input.capacity()); + let position = input.position(); + let read = stream.readInto(ByteArray.wrap(input.array()), position, input.capacity()); if (read < 0) { // end of stream has been reached eof = true; } else { - var from = output.position(); + let from = output.position(); input.position(position + read); decodeInput(0); newline = StringUtils.searchNewline(output, from); @@ -180,10 +178,10 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { } output.flip(); // get the raw underlying char[] output buffer - var array = output.array(); - var result; + const array = output.array(); + let result; if (newline > -1) { - var isCrlf = array[newline] == 13 && array[newline + 1] == 10; + const isCrlf = array[newline] === 13 && array[newline + 1] === 10; if (isCrlf && includeNewline) { // We want to add a single newline to the return value. To save us // from allocating a new buffer we temporarily mod the existing one. @@ -192,14 +190,14 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { array[newline] = 13; mark = newline + 2; } else { - var count = includeNewline ? newline + 1 - mark : newline - mark; + let count = includeNewline ? newline + 1 - mark : newline - mark; result = JavaString.valueOf(array, mark, count); mark = isCrlf ? newline + 2 : newline + 1; } output.position(output.limit()); output.limit(output.capacity()); } else if (eof) { - result = mark == output.limit() ? + result = (mark === output.limit()) ? null : JavaString.valueOf(array, mark, output.limit() - mark); this.clear(); } @@ -231,11 +229,11 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { * to reading from plain binary ByteArray or ByteString objects. * @param {io.Stream} source the source stream * @see io streams - * @example var stream = new MemoryStream(); + * @example const stream = new MemoryStream(); * stream.write(...); // write some bytes into the stream * stream.position = 0; // reset the pointer * - * var dec = new Decoder('ASCII'); + * const dec = new Decoder('ASCII'); * dec.readFrom(stream); // connect the stream with the decoder * dec.read(); // returns the stream's content as string */ @@ -263,10 +261,10 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { * Each character in the buffer is a 16-bit Unicode character. * @see java.nio.CharBuffer * @example // an emoji in 4 raw bytes - * var ba = new ByteArray([0xF0,0x9F,0x98,0x98]); + * const ba = new ByteArray([0xF0,0x9F,0x98,0x98]); * * // a UTF-8 based decoder - * var dec = new Decoder("UTF-8"); + * const dec = new Decoder("UTF-8"); * * // prints 😘 * console.log(dec.decode(ba)); @@ -275,9 +273,7 @@ module.exports.Decoder = function Decoder(charset, strict, capacity) { * console.log(dec.length + " chars vs. " + ba.length + " bytes"); */ Object.defineProperty(this, "length", { - get: function() { - return output.position() - mark; - } + get: () => output.position() - mark }); } @@ -296,16 +292,16 @@ module.exports.Encoder = function Encoder(charset, strict, capacity) { } capacity = capacity || DEFAULTSIZE; - var encoder = Charset.forName(charset).newEncoder(); - var encoded = new ByteArray(capacity); - var output = ByteBuffer.wrap(encoded); - var stream; - - var errorAction = strict ? - CodingErrorAction.REPORT : CodingErrorAction.REPLACE; + const encoder = Charset.forName(charset).newEncoder(); + const encoded = new ByteArray(capacity); + const errorAction = strict ? + CodingErrorAction.REPORT : CodingErrorAction.REPLACE; encoder.onMalformedInput(errorAction); encoder.onUnmappableCharacter(errorAction); + let output = ByteBuffer.wrap(encoded); + let stream; + /** * Encodes the given string into the encoder's binary buffer. * @param {String} string the string to encode @@ -317,13 +313,13 @@ module.exports.Encoder = function Encoder(charset, strict, capacity) { this.encode = function(string, start, end) { start = start || 0; end = end || string.length; - var input = CharBuffer.wrap(string, start, end); - var result = encoder.encode(input, output, false); + const input = CharBuffer.wrap(string, start, end); + let result = encoder.encode(input, output, false); while (result.isOverflow()) { // grow output buffer capacity += Math.max(capacity, Math.round(1.2 * (end - start) * encoder.averageBytesPerChar())); encoded.length = capacity; - var position = output.position(); + let position = output.position(); output = ByteBuffer.wrap(encoded); output.position(position); result = encoder.encode(input, output, false); @@ -345,8 +341,8 @@ module.exports.Encoder = function Encoder(charset, strict, capacity) { * @returns {Encoder} the now closed encoder */ this.close = function() { - var input = CharBuffer.wrap(""); - var result = encoder.encode(input, output, true); + const input = CharBuffer.wrap(""); + const result = encoder.encode(input, output, true); if (result.isError()) { encoder.reset(); throw new Error(result); @@ -368,7 +364,7 @@ module.exports.Encoder = function Encoder(charset, strict, capacity) { * @returns {ByteString} the resulting ByteString */ this.toByteString = function() { - return ByteString.wrap(encoded.slice(0, output.position())); + return binary.ByteString.wrap(encoded.slice(0, output.position())); }; /** @@ -403,8 +399,6 @@ module.exports.Encoder = function Encoder(charset, strict, capacity) { * The underlying byte buffer's length. */ Object.defineProperty(this, "length", { - get: function() { - return output.position(); - } + get: () => output.position() }); } diff --git a/test/ringo/encoding_test.js b/test/ringo/encoding_test.js index 5ef180adb..8c84b3141 100644 --- a/test/ringo/encoding_test.js +++ b/test/ringo/encoding_test.js @@ -1,13 +1,13 @@ -var assert = require("assert"); -include('ringo/encoding'); -include('binary'); -include('io'); +const assert = require("assert"); +const {Encoder, Decoder} = require('ringo/encoding'); +const binary = require('binary'); +const {MemoryStream, TextStream} = require('io'); -var str = "I \u2665 JS"; -var bytes = new ByteString([73,32,226,153,165,32,74,83]); +const str = "I \u2665 JS"; +const bytes = new binary.ByteString([73,32,226,153,165,32,74,83]); exports.testEncoder = function() { - var enc = new Encoder("utf-8"); + const enc = new Encoder("utf-8"); enc.encode(str).encode(str); assert.strictEqual(str + str, enc.toByteString().decodeToString("utf-8")); enc.encode(str); @@ -17,7 +17,7 @@ exports.testEncoder = function() { }; exports.testSmallEncoder = function() { - var enc = new Encoder("utf-8", false, 2); + const enc = new Encoder("utf-8", false, 2); enc.encode(str).encode(str); assert.strictEqual(str + str, enc.toByteString().decodeToString("utf-8")); enc.encode(str); @@ -27,8 +27,8 @@ exports.testSmallEncoder = function() { }; exports.testStreamEncoder = function() { - var enc = new Encoder("utf-8"); - var stream = new MemoryStream(); + const enc = new Encoder("utf-8"); + const stream = new MemoryStream(); enc.writeTo(stream); enc.encode(str).encode(str); assert.strictEqual(enc.length, 0); @@ -42,7 +42,7 @@ exports.testStreamEncoder = function() { }; exports.testDecoder = function() { - var dec = new Decoder("utf-8"); + const dec = new Decoder("utf-8"); dec.decode(bytes).decode(bytes); assert.strictEqual(str + str, dec.toString()); dec.decode(bytes); @@ -52,7 +52,7 @@ exports.testDecoder = function() { }; exports.testDecoderSmall = function() { - var dec = new Decoder("utf-8", false, 2); + const dec = new Decoder("utf-8", false, 2); dec.decode(bytes).decode(bytes); assert.strictEqual(str + str, dec.toString()); dec.decode(bytes); @@ -62,8 +62,8 @@ exports.testDecoderSmall = function() { }; exports.testStreamDecoder = function() { - var dec = new Decoder("utf-8"); - var stream = new MemoryStream(); + const dec = new Decoder("utf-8"); + const stream = new MemoryStream(); stream.write(bytes.concat(bytes).concat(bytes)); stream.position = 0; dec.readFrom(stream); @@ -73,9 +73,9 @@ exports.testStreamDecoder = function() { }; exports.testStreamDecoderReadLine = function() { - var dec = new Decoder("utf-8"); - var stream = new MemoryStream(); - new TextStream(stream, {charset: "utf-8"}).writeLine(str).writeLine(str).writeLine(str); + const dec = new Decoder("utf-8"); + const stream = new MemoryStream(); + (new TextStream(stream, {charset: "utf-8"})).writeLine(str).writeLine(str).writeLine(str); stream.position = 0; dec.readFrom(stream); assert.strictEqual(str, dec.readLine()); @@ -86,10 +86,10 @@ exports.testStreamDecoderReadLine = function() { }; exports.testStreamDecoderReadLineShort = function() { - var line = "The quick brown fox jumps over the lazy dog"; - var dec = new Decoder("utf-8", false, 2); - var stream = new MemoryStream(); - new TextStream(stream, {charset: "utf-8"}).writeLine(line).writeLine(line).writeLine(line); + const line = "The quick brown fox jumps over the lazy dog"; + const dec = new Decoder("utf-8", false, 2); + const stream = new MemoryStream(); + (new TextStream(stream, {charset: "utf-8"})).writeLine(line).writeLine(line).writeLine(line); stream.position = 0; dec.readFrom(stream); assert.strictEqual(line, dec.readLine()); @@ -101,4 +101,4 @@ exports.testStreamDecoderReadLineShort = function() { if (require.main === module) { require('system').exit(require("test").run(module.id)); -} \ No newline at end of file +} From ae0def50853907b6bc4263f7c9b4666e5a9f58ce Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 10:04:14 +0100 Subject: [PATCH 16/52] code modernization (ie. var -> const/let) --- modules/ringo/engine.js | 107 +++++++++++++--------------------------- 1 file changed, 35 insertions(+), 72 deletions(-) diff --git a/modules/ringo/engine.js b/modules/ringo/engine.js index 246b3fdc8..650793e54 100644 --- a/modules/ringo/engine.js +++ b/modules/ringo/engine.js @@ -2,32 +2,34 @@ * @fileOverview Provides access to the Rhino JavaScript engine. */ -var {Context, ClassShutter} = org.mozilla.javascript; -var {RhinoEngine, RingoConfig} = org.ringojs.engine; -var engine = RhinoEngine.getEngine(global); +const {Context, ClassShutter} = org.mozilla.javascript; +const {RhinoEngine, RingoConfig} = org.ringojs.engine; +const engine = RhinoEngine.getEngine(global); /** * An object reflecting the Java system properties. */ -try { - var properties = new ScriptableMap(java.lang.System.getProperties()); -} catch (error) { - properties = {}; -} +exports.properties = (() => { + try { + return new ScriptableMap(java.lang.System.getProperties()); + } catch (error) { + return {}; + } +})(); /** * The RingoJS version as an array-like object with the major and minor version * number as first and second element. */ -var version = new ScriptableList(RhinoEngine.VERSION); +exports.version = new ScriptableList(RhinoEngine.VERSION); /** * Define a class as Rhino host object. * @param {JavaClass} javaClass the class to define as host object */ -function addHostObject(javaClass) { +exports.addHostObject = (javaClass) => { engine.defineHostClass(javaClass); -} +}; /** * Register a callback to be invoked when the current RingoJS instance is @@ -39,9 +41,9 @@ function addHostObject(javaClass) { * synchronously (on the main shutdown thread) or asynchronously (on the * worker's event loop thread) */ -function addShutdownHook(funcOrObject, sync) { +exports.addShutdownHook = (funcOrObject, sync) => { engine.addShutdownHook(funcOrObject, Boolean(sync)); -} +}; /** * Create a sandboxed scripting engine with the same install directory as this and the @@ -56,36 +58,31 @@ function addShutdownHook(funcOrObject, sync) { * @returns {RhinoEngine} a sandboxed RhinoEngine instance * @throws {FileNotFoundException} if any part of the module paths does not exist */ -function createSandbox(modulePath, globals, options) { - options = options || {}; - var systemModules = options.systemModules || null; - var config = new RingoConfig( - getRingoHome(), modulePath, systemModules); +exports.createSandbox = (modulePath, globals, options) => { + options || (options = {}); + const systemModules = options.systemModules || null; + const config = new RingoConfig(engine.getRingoHome(), modulePath, systemModules); if (options.classShutter) { - var shutter = options.shutter; + const shutter = options.shutter; config.setClassShutter(shutter instanceof ClassShutter ? shutter : new ClassShutter(shutter)); } config.setSealed(Boolean(options.sealed)); return engine.createSandbox(config, globals); -} +}; /** * Get the RingoJS installation directory. * @returns {Repository} a Repository representing the Ringo installation directory */ -function getRingoHome() { - return engine.getRingoHome(); -} +exports.getRingoHome = () => engine.getRingoHome(); /** * Get a wrapper for an object that exposes it as Java object to JavaScript. * @param {Object} object an object * @returns {Object} the object wrapped as native java object */ -function asJavaObject(object) { - return engine.asJavaObject(object); -} +exports.asJavaObject = (object) => engine.asJavaObject(object); /** * Get a wrapper for a string that exposes the java.lang.String methods to JavaScript @@ -94,9 +91,7 @@ function asJavaObject(object) { * @param {Object} object an object * @returns {Object} the object converted to a string and wrapped as native java object */ -function asJavaString(object) { - return engine.asJavaString(object); -} +exports.asJavaString = (object) => engine.asJavaString(object); /** * Get the Rhino optimization level for the current thread and context. @@ -105,9 +100,7 @@ function asJavaString(object) { * is 0. * @returns {Number} level an integer between -1 and 9 */ -function getOptimizationLevel() { - return engine.getOptimizationLevel(); -} +exports.getOptimizationLevel = () => engine.getOptimizationLevel(); /** * Set the Rhino optimization level for the current thread and context. @@ -116,87 +109,57 @@ function getOptimizationLevel() { * is 0. * @param {Number} level an integer between -1 and 9 */ -function setOptimizationLevel(level) { +exports.setOptimizationLevel = (level) => { engine.setOptimizationLevel(level); } /** * Get the org.mozilla.javascript.Context associated with the current thread. */ -function getRhinoContext() { - return Context.getCurrentContext(); -} +exports.getRhinoContext = () => Context.getCurrentContext(); /** * Get the org.ringojs.engine.RhinoEngine associated with this application. * @returns {org.ringojs.engine.RhinoEngine} the current RhinoEngine instance */ -function getRhinoEngine() { - return engine; -} +exports.getRhinoEngine = () => engine; /** * Get a new worker instance. * @return {org.ringojs.engine.RingoWorker} a new RingoWorker instance */ -function getWorker() { - return engine.getWorker(); -} +exports.getWorker = () => engine.getWorker(); /** * Get the worker instance associated with the current thread or the given scope or function object. * @param {Object} obj optional scope or function to get the worker from. * @return {org.ringojs.engine.RingoWorker} the current worker */ -function getCurrentWorker(obj) { - return engine.getCurrentWorker(obj || null); -} +exports.getCurrentWorker = (obj) => engine.getCurrentWorker(obj || null); /** * Get a list containing the syntax errors encountered in the current worker. * @returns {ScriptableList} a list containing the errors encountered in the * current worker */ -function getErrors() { - return new ScriptableList(getCurrentWorker().getErrors()); -} +exports.getErrors = () => new ScriptableList(getCurrentWorker().getErrors()); /** * Get the app's module search path as list of repositories. * @returns {ScriptableList} a list containing the module search path repositories */ -function getRepositories() { - return new ScriptableList(engine.getRepositories()); -} +exports.getRepositories = () => new ScriptableList(engine.getRepositories()); /** * Add a repository to the module search path * @param {Repository} repo a repository */ -function addRepository(repo) { +exports.addRepository = (repo) => { if (typeof repo == "string") { repo = new org.ringojs.repository.FileRepository(repo); } - var path = getRepositories(); + const path = getRepositories(); if (repo.exists() && !path.contains(repo)) { path.add(Math.max(0, path.length) - 1, repo); } -} - -module.exports.properties = properties; -module.exports.addHostObject = addHostObject; -module.exports.addRepository = addRepository; -module.exports.addShutdownHook = addShutdownHook; -module.exports.asJavaString = asJavaString; -module.exports.asJavaObject = asJavaObject; -module.exports.createSandbox = createSandbox; -module.exports.getErrors = getErrors; -module.exports.getRingoHome = getRingoHome; -module.exports.getRepositories = getRepositories; -module.exports.getRhinoContext = getRhinoContext; -module.exports.getRhinoEngine = getRhinoEngine; -module.exports.getOptimizationLevel = getOptimizationLevel; -module.exports.setOptimizationLevel = setOptimizationLevel; -module.exports.getCurrentWorker = getCurrentWorker; -module.exports.getWorker = getWorker; -module.exports.version = version; +}; From 8a54199cb7cefce1b72e58e640a412993d647899 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 10:15:58 +0100 Subject: [PATCH 17/52] code modernization (ie. var -> const/let) --- modules/ringo/events.js | 60 +++++++++++++++++++-------------------- test/ringo/events_test.js | 20 ++++++------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/modules/ringo/events.js b/modules/ringo/events.js index 49cbbb888..e58c96a09 100644 --- a/modules/ringo/events.js +++ b/modules/ringo/events.js @@ -11,14 +11,14 @@ defineClass(org.ringojs.wrappers.EventAdapter); * The `EventEmitter` function can be used as constructor or as mix-in. Use the * `new` keyword to construct a new EventEmitter: * - * var emitter = new EventEmitter(); + * const emitter = new EventEmitter(); * * To add event handling methods to an existing object, call or apply the * `EventEmitter` function with the object as `this`: * * EventEmitter.call(object); */ -var EventEmitter = exports.EventEmitter = function() { +const EventEmitter = exports.EventEmitter = function() { // if called on an object other than EventEmitter define properties if (!(this instanceof EventEmitter)) { Object.defineProperties(this, emitterImpl); @@ -35,7 +35,7 @@ var EventEmitter = exports.EventEmitter = function() { * constructor or as mix-in. Use the `new` keyword to construct a new * JavaEventEmitter: * - * var emitter = new JavaEventEmitter(JavaClassOrInterface); + * const emitter = new JavaEventEmitter(JavaClassOrInterface); * * To add event handling methods to an existing object, call or apply the * `JavaEventEmitter` function with the object as `this`: @@ -56,9 +56,9 @@ var EventEmitter = exports.EventEmitter = function() { * set to the property value instead of the method name. */ exports.JavaEventEmitter = function(classOrInterface, eventMapping) { - var classArg = Array.isArray(classOrInterface) ? + const classArg = Array.isArray(classOrInterface) ? classOrInterface : [classOrInterface]; - var e = new EventAdapter(classArg, eventMapping); + const e = new EventAdapter(classArg, eventMapping); Object.defineProperties(this, { /** * The generated Java object. This implements the Java interface @@ -97,7 +97,9 @@ exports.JavaEventEmitter = function(classOrInterface, eventMapping) { * @function */ on: { - get: function() this.addListener + get: function() { + return this.addListener; + } }, /** * Add a synchronous listener function for the given event. A @@ -132,9 +134,7 @@ exports.JavaEventEmitter = function(classOrInterface, eventMapping) { return this; }; -var isArray = Array.isArray; - -var emitterImpl = { +const emitterImpl = { /** * Emit an event to all listeners registered for this event type * @param {String} type type the event type @@ -146,20 +146,18 @@ var emitterImpl = { */ emit: { value: function(type) { - var args; - var listeners = this._events ? this._events[type] : null; - if (isArray(listeners) && !listeners.length) { + let listeners = this._events ? this._events[type] : null; + if (Array.isArray(listeners) && !listeners.length) { listeners = null; // normalize empty listener array } + let args; if (typeof listeners === "function") { args = Array.prototype.slice.call(arguments, 1); listeners.apply(this, args); return true; - } else if (isArray(listeners)) { + } else if (Array.isArray(listeners)) { args = Array.prototype.slice.call(arguments, 1); - for (var i = 0; i < listeners.length; i++) { - listeners[i].apply(this, args); - } + listeners.forEach(func => func.apply(this, args)); return true; } else { return false; @@ -176,7 +174,9 @@ var emitterImpl = { * @function */ on: { - get: function() this.addListener + get: function() { + return this.addListener; + } }, /** * Add a listener function for the given event. This is a shortcut for @@ -193,13 +193,13 @@ var emitterImpl = { throw new Error ("Event listener must be a function"); } - if (!this._events) this._events = {}; + this._events || (this._events = {}); this.emit("newListener", type, listener); if (!this._events[type]) { // store as single function this._events[type] = listener; - } else if (isArray(this._events[type])) { + } else if (Array.isArray(this._events[type])) { this._events[type].push(listener); } else { // convert to array @@ -223,17 +223,17 @@ var emitterImpl = { throw new Error ("Event listener must be a function"); } - if (this._events && this._events[type]) { - var listeners = this._events[type]; + if (this._events && this._events.hasOwnProperty(type)) { + const listeners = this._events[type]; if (listeners === listener) { delete this._events[type]; - } else if (isArray(listeners)) { - var i = listeners.indexOf(listener); - if (i > -1) { + } else if (Array.isArray(listeners)) { + const idx = listeners.indexOf(listener); + if (idx > -1) { if (listeners.length === 1) { this._events = null; } else { - listeners.splice(i, 1); + listeners.splice(idx, 1); } } } @@ -250,7 +250,9 @@ var emitterImpl = { */ removeAllListeners: { value: function(type) { - if (type && this._events) this._events[type] = undefined; + if (type && this._events.hasOwnProperty(type)) { + delete this._events[type]; + } return this; } }, @@ -265,12 +267,10 @@ var emitterImpl = { */ listeners: { value: function(type) { - if (!this._events) { - this._events = {}; - } + this._events || (this._events = {}); if (!this._events[type]) { this._events[type] = []; - } else if (!isArray(this._events[type])) { + } else if (!Array.isArray(this._events[type])) { this._events[type] = [this._events[type]]; } return this._events[type]; diff --git a/test/ringo/events_test.js b/test/ringo/events_test.js index b70e66a76..f62c69a0a 100644 --- a/test/ringo/events_test.js +++ b/test/ringo/events_test.js @@ -1,24 +1,24 @@ -var assert = require("assert"); -var {EventEmitter} = require("ringo/events"); +const assert = require("assert"); +const {EventEmitter} = require("ringo/events"); exports.testConstructor = function() { - var e = new EventEmitter(); + const e = new EventEmitter(); assert.isTrue(e instanceof EventEmitter); testEmitter(e); }; exports.testMixin = function() { - var e = {}; + const e = {}; EventEmitter.call(e); assert.isFalse(e instanceof EventEmitter); testEmitter(e); }; -function testEmitter(e) { - var count = 0; - var add = function(amount) { count += amount }; - var subtract = function(amount) { count -= amount }; - var result; +const testEmitter = (e) => { + let count = 0; + const add = (amount) => count += amount; + const subtract = (amount) => count -= amount; + let result; assert.equal(e.on, e.addListener, "on and addListener are different"); e.addListener("add", add); e.addListener("addTwice", add).addListener("addTwice", add); @@ -55,4 +55,4 @@ function testEmitter(e) { if (require.main === module) { require('system').exit(require("test").run(module.id)); -} \ No newline at end of file +} From 52eb27a4d8c459512c3acbda19b9401358c42059 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 11:09:56 +0100 Subject: [PATCH 18/52] code modernization (ie. var -> const/let) --- modules/ringo/httpclient.js | 251 ++++++++++----------- test/ringo/httpclient_test.js | 395 ++++++++++++++++------------------ 2 files changed, 306 insertions(+), 340 deletions(-) diff --git a/modules/ringo/httpclient.js b/modules/ringo/httpclient.js index b05e36e8e..62782494f 100644 --- a/modules/ringo/httpclient.js +++ b/modules/ringo/httpclient.js @@ -1,8 +1,8 @@ /** * @fileoverview A module for sending HTTP requests and receiving HTTP responses. * - * @example var {request} = require('ringo/httpclient'); - * var exchange = request({ + * @example const {request} = require('ringo/httpclient'); + * const exchange = request({ * method: 'GET', * url: 'http://ringojs.org/', * headers: { @@ -15,19 +15,19 @@ * } */ -var {URL, URLConnection, HttpCookie, Proxy, InetSocketAddress} = java.net; -var {InputStream, BufferedOutputStream, OutputStreamWriter, BufferedWriter, - ByteArrayOutputStream, PrintWriter, OutputStreamWriter} = java.io; -var {GZIPInputStream, InflaterInputStream} = java.util.zip; -var {TextStream, MemoryStream} = require("io"); -var {mimeType} = require("ringo/mime"); -var {getMimeParameter, Headers, urlEncode} = require('ringo/utils/http'); -var {ByteArray} = require("binary"); -var objects = require("ringo/utils/objects"); -var base64 = require("ringo/base64"); -var {Buffer} = require("ringo/buffer"); -var {Random} = java.util; -var log = require("ringo/logging").getLogger(module.id); +const {URL, HttpCookie, Proxy, InetSocketAddress} = java.net; +const {InputStream, OutputStreamWriter, BufferedWriter, + ByteArrayOutputStream, PrintWriter} = java.io; +const {GZIPInputStream, InflaterInputStream} = java.util.zip; +const io = require("io"); +const {mimeType} = require("ringo/mime"); +const {getMimeParameter, Headers, urlEncode} = require('ringo/utils/http'); +const binary = require("binary"); +const objects = require("ringo/utils/objects"); +const base64 = require("ringo/base64"); +const {Buffer} = require("ringo/buffer"); +const {Random} = java.util; +const log = require("ringo/logging").getLogger(module.id); const VERSION = require("ringo/engine").version.join("."); const CRLF = "\r\n"; @@ -36,8 +36,8 @@ const BOUNDARY_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR /** * Defaults for options passable to to request() */ -var prepareOptions = function(options) { - var defaultValues = { +const prepareOptions = (options) => { + const defaultValues = { "data": {}, "headers": {}, "method": "GET", @@ -49,7 +49,7 @@ var prepareOptions = function(options) { "binary": false, "beforeSend": null }; - var opts = options ? objects.merge(options, defaultValues) : defaultValues; + const opts = options ? objects.merge(options, defaultValues) : defaultValues; Headers(opts.headers); opts.contentType = opts.contentType || opts.headers.get("Content-Type") @@ -63,67 +63,53 @@ var prepareOptions = function(options) { * @returns {Cookie} A newly created Cookie instance * @constructor */ -var Cookie = function(httpCookie) { +const Cookie = function(httpCookie) { Object.defineProperties(this, { /** * @returns {String} the cookie's name */ "name": { - "get": function() { - return httpCookie.getName(); - } + "value": httpCookie.getName() }, /** * @returns {String} the cookie value */ "value": { - "get": function() { - return httpCookie.getValue(); - } + "value": httpCookie.getValue() }, /** * @returns {String} the cookie domain */ "domain": { - "get": function() { - return httpCookie.getDomain(); - } + "value": httpCookie.getDomain() }, /** * @returns {String} the cookie path */ "path": { - "get": function() { - return httpCookie.getPath(); - } + "value": httpCookie.getPath() }, /** * @returns {Number} the max age of this cookie in seconds */ "maxAge": { - "get": function() { - return httpCookie.getMaxAge(); - } + "value": httpCookie.getMaxAge() }, /** * @returns {String} true if this cookie is restricted to a secure protocol */ "isSecure": { - "get": function() { - return httpCookie.getSecure(); - } + "value": httpCookie.getSecure() }, /** * @returns {String} the cookie version */ "version": { - "get": function() { - return httpCookie.getVersion(); - } + "value": httpCookie.getVersion() } }); @@ -137,25 +123,25 @@ var Cookie = function(httpCookie) { * @param {String} charset The character set name * @param {String} contentType The content type */ -var writeData = function(data, connection, charset, contentType) { +const writeData = (data, connection, charset, contentType) => { connection.setRequestProperty("Content-Type", contentType); - var outStream; + let outStream; try { - outStream = new Stream(connection.getOutputStream()); + outStream = new io.Stream(connection.getOutputStream()); if (data instanceof InputStream) { - (new Stream(data)).copy(outStream).close(); - } else if (data instanceof Binary) { - (new MemoryStream(data)).copy(outStream).close(); - } else if (data instanceof Stream) { + (new io.Stream(data)).copy(outStream).close(); + } else if (data instanceof binary.Binary) { + (new io.MemoryStream(data)).copy(outStream).close(); + } else if (data instanceof io.Stream) { data.copy(outStream).close(); } else { - if (data instanceof TextStream) { + if (data instanceof io.TextStream) { data = data.read(); } else if (data instanceof Object) { data = urlEncode(data); } if (typeof(data) === "string" && data.length > 0) { - var writer = new BufferedWriter(OutputStreamWriter(outStream, charset)); + const writer = new BufferedWriter(OutputStreamWriter(outStream, charset)); writer.write(data); writer.close(); } @@ -169,11 +155,11 @@ var writeData = function(data, connection, charset, contentType) { * Generates a multipart boundary. * @returns {String} A multipart boundary */ -var generateBoundary = function() { +const generateBoundary = () => { // taken from apache httpclient - var buffer = new Buffer(); - var random = new Random(); - var count = random.nextInt(11) + 30; // a random size from 30 to 40 + const buffer = new Buffer(); + const random = new Random(); + const count = random.nextInt(11) + 30; // a random size from 30 to 40 for (let i=0; i { connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); - var outStream, writer; + let outStream, writer; try { - outStream = new Stream(connection.getOutputStream()); + outStream = new io.Stream(connection.getOutputStream()); writer = new PrintWriter(new OutputStreamWriter(outStream, charset), true); - for (let [name, part] in Iterator(data)) { + Object.keys(data).forEach(key => { writer.append("--" + boundary).append(CRLF); - part.write(name, writer, outStream); - } + data[key].write(key, writer, outStream); + }) writer.append("--").append(boundary).append("--").append(CRLF); } finally { writer && writer.close(); @@ -209,9 +195,9 @@ var writeMultipartData = function(data, connection, charset, boundary) { * @param {java.net.HttpURLConnection} connection The connection * @returns {ByteArray} The response as ByteArray */ -var readResponse = function(connection) { - var status = connection.getResponseCode(); - var inStream; +const readResponse = (connection) => { + const status = connection.getResponseCode(); + let inStream; try { inStream = connection[(status >= 200 && status < 400) ? "getInputStream" : "getErrorStream"](); @@ -219,7 +205,7 @@ var readResponse = function(connection) { if (inStream === null) { return null; } - var encoding = connection.getContentEncoding(); + const encoding = connection.getContentEncoding(); if (encoding != null) { if (encoding.equalsIgnoreCase("gzip")) { inStream = new GZIPInputStream(inStream); @@ -227,10 +213,10 @@ var readResponse = function(connection) { inStream = new InflaterInputStream(inStream); } } - inStream = new Stream(inStream); - var outStream = new ByteArrayOutputStream(8192); + inStream = new io.Stream(inStream); + const outStream = new ByteArrayOutputStream(8192); inStream.copy(outStream); - return new ByteArray(outStream.toByteArray()); + return new binary.ByteArray(outStream.toByteArray()); } finally { inStream && inStream.close(); } @@ -243,12 +229,11 @@ var readResponse = function(connection) { * @returns {Exchange} A newly constructed Exchange instance * @constructor */ -var Exchange = function(url, options) { - var reqData = options.data; - var connection = null; - var responseContent; - var responseContentBytes; - var thrownException; +const Exchange = function(url, options) { + let reqData = options.data; + let connection = null; + let responseContent; + let responseContentBytes; Object.defineProperties(this, { /** @@ -256,30 +241,30 @@ var Exchange = function(url, options) { * @name Exchange.prototype.connection */ "connection": { - "get": function() { - return connection; - }, "enumerable": true + "get": () => connection, + "enumerable": true }, /** * The response body as String. * @name Exchange.prototype.content */ "content": { - "get": function() { + "get": () => { if (responseContent !== undefined) { return responseContent; } - return responseContent = this.contentBytes==null?null:this.contentBytes.decodeToString(this.encoding); - }, "enumerable": true + return responseContent = (!this.contentBytes) ? + null : this.contentBytes.decodeToString(this.encoding); + }, + "enumerable": true }, /** * The response body as ByteArray. * @name Exchange.prototype.contentBytes */ "contentBytes": { - "get": function() { - return responseContentBytes; - }, "enumerable": true + "get": () => responseContentBytes, + "enumerable": true } }); @@ -290,9 +275,9 @@ var Exchange = function(url, options) { url += "?" + reqData; } } - var url = new URL(url); + url = new URL(url); if (options.proxy) { - var host, port; + let host, port; if (typeof(options.proxy) == "string") { [host, port] = options.proxy.split(":"); } else { @@ -314,36 +299,36 @@ var Exchange = function(url, options) { connection.setRequestProperty("Accept-Encoding", "gzip,deflate"); // deal with username:password in url - var userInfo = connection.getURL().getUserInfo(); + const userInfo = connection.getURL().getUserInfo(); if (userInfo) { - var [username, password] = userInfo.split(":"); + const [username, password] = userInfo.split(":"); options.username = options.username || username; options.password = options.password || password; } // set authentication header if (typeof(options.username) === "string" && typeof(options.password) === "string") { - var authKey = base64.encode(options.username + ':' + options.password); - connection.setRequestProperty("Authorization", "Basic " + authKey); + connection.setRequestProperty("Authorization", + "Basic " + base64.encode(options.username + ':' + options.password)); } // set header keys specified in options - for (let key in options.headers) { + Object.keys(options.headers).forEach(key => { connection.setRequestProperty(key, options.headers[key]); - } + }); if (typeof(options.beforeSend) === "function") { options.beforeSend(this); } if (options.method === "POST" || options.method === "PUT") { connection.setDoOutput(true); - var charset = getMimeParameter(options.contentType, "charset") || "utf-8"; + const charset = getMimeParameter(options.contentType, "charset") || "utf-8"; if (options.method === "POST" && options.contentType === "multipart/form-data") { // all parts must be instances of text or binary parts - for (let [name, part] in Iterator(reqData)) { + Object.keys(reqData).forEach(key => { + const part = reqData[key]; if (!(part instanceof TextPart) && !(part instanceof BinaryPart)) { throw new Error("Multipart form data parts must be either TextPart or BinaryPart, but " + name + "isn't."); } - } - + }) writeMultipartData(reqData, connection, charset, generateBoundary()); } else { writeData(reqData, connection, charset, options.contentType); @@ -366,7 +351,8 @@ Object.defineProperties(Exchange.prototype, { "url": { "get": function() { return this.connection.getURL(); - }, "enumerable": true + }, + "enumerable": true }, /** * The response status code. @@ -376,7 +362,8 @@ Object.defineProperties(Exchange.prototype, { "status": { "get": function() { return this.connection.getResponseCode(); - }, "enumerable": true + }, + "enumerable": true }, /** * The response status message. @@ -386,7 +373,8 @@ Object.defineProperties(Exchange.prototype, { "message": { "get": function() { return this.connection.getResponseMessage(); - }, "enumerable": true + }, + "enumerable": true }, /** * The response headers. @@ -396,7 +384,7 @@ Object.defineProperties(Exchange.prototype, { "get": function() { // This is required since getHeaderFields() returns an unmodifiable Map // http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java#l2919 - var headerFields = new java.util.HashMap(this.connection.getHeaderFields()); + const headerFields = new java.util.HashMap(this.connection.getHeaderFields()); // drops the HTTP Status-Line with the key null // null => HTTP/1.1 200 OK @@ -404,7 +392,8 @@ Object.defineProperties(Exchange.prototype, { headerFields.remove(null); return new ScriptableMap(headerFields); - }, enumerable: true + }, + "enumerable": true }, /** * The cookies set by the server. @@ -412,17 +401,18 @@ Object.defineProperties(Exchange.prototype, { */ "cookies": { "get": function() { - var cookies = {}; - var cookieHeaders = this.connection.getHeaderField("Set-Cookie"); + const cookies = {}; + const cookieHeaders = this.connection.getHeaderField("Set-Cookie"); if (cookieHeaders !== null) { - var list = new ScriptableList(HttpCookie.parse(cookieHeaders)); - for each (let httpCookie in list) { - let cookie = new Cookie(httpCookie); + const list = new ScriptableList(HttpCookie.parse(cookieHeaders)); + list.forEach(httpCookie => { + const cookie = new Cookie(httpCookie); cookies[cookie.name] = cookie; - } + }); } return cookies; - }, enumerable: true + }, + "enumerable": true }, /** * The response encoding. @@ -432,7 +422,8 @@ Object.defineProperties(Exchange.prototype, { "encoding": { "get": function() { return getMimeParameter(this.contentType, "charset") || "utf-8"; - }, "enumerable": true + }, + "enumerable": true }, /** * The response content type. @@ -442,7 +433,8 @@ Object.defineProperties(Exchange.prototype, { "contentType": { "get": function() { return this.connection.getContentType(); - }, "enumerable": true + }, + "enumerable": true }, /** * The response content length. @@ -452,7 +444,8 @@ Object.defineProperties(Exchange.prototype, { "contentLength": { "get": function() { return this.connection.getContentLength(); - }, "enumerable": true + }, + "enumerable": true } }); @@ -494,12 +487,12 @@ Object.defineProperties(Exchange.prototype, { * @see #put * @see #del */ -var request = function(options) { +const request = exports.request = (options) => { if (options.complete != null || options.success != null || options.error != null) { log.warn("ringo/httpclient does not support callbacks anymore!"); } - var opts = prepareOptions(options); + const opts = prepareOptions(options); return new Exchange(opts.url, { "method": opts.method, "data": opts.data, @@ -524,11 +517,11 @@ var request = function(options) { * @returns An options object * @type Object */ -var createOptions = function(method, url, data) { +const createOptions = (method, url, data) => { return { - method: method, - url: url, - data: data + "method": method, + "url": url, + "data": data }; }; @@ -538,7 +531,7 @@ var createOptions = function(method, url, data) { * @param {Object|String} data The data to append as GET parameters to the URL * @returns {Exchange} The Exchange instance representing the request and response */ -var get = function(url, data) { +exports.get = (url, data) => { return request(createOptions("GET", url, data)); }; @@ -548,7 +541,7 @@ var get = function(url, data) { * @param {Object|String|Stream|Binary} data The data to send to the server * @returns {Exchange} The Exchange instance representing the request and response */ -var post = function(url, data) { +exports.post = (url, data) => { return request(createOptions("POST", url, data)); }; @@ -558,7 +551,7 @@ var post = function(url, data) { * @param {Object|String} data The data to append as GET parameters to the URL * @returns {Exchange} The Exchange instance representing the request and response */ -var del = function(url, data) { +exports.del = (url, data) => { return request(createOptions("DELETE", url, data)); }; @@ -568,7 +561,7 @@ var del = function(url, data) { * @param {Object|String|Stream|Binary} data The data send to the server * @returns {Exchange} The Exchange instance representing the request and response */ -var put = function(url, data) { +exports.put = (url, data) => { return request(createOptions("PUT", url, data)); }; @@ -590,7 +583,7 @@ var put = function(url, data) { * } * }); */ -var TextPart = function(data, charset, fileName) { +const TextPart = exports.TextPart = function(data, charset, fileName) { /** * Writes this TextPart's data. @@ -609,8 +602,8 @@ var TextPart = function(data, charset, fileName) { writer.append("Content-Type: text/plain; charset=") .append(charset || "utf-8").append(CRLF); writer.append(CRLF).flush(); - if (data instanceof TextStream) { - data.copy(new TextStream(outStream, { + if (data instanceof io.TextStream) { + data.copy(new io.TextStream(outStream, { "charset": charset || "utf-8" })).close(); outStream.flush(); @@ -640,7 +633,7 @@ var TextPart = function(data, charset, fileName) { * } * }); */ -var BinaryPart = function(data, fileName, contentType) { +const BinaryPart = exports.BinaryPart = function(data, fileName, contentType) { /** * Writes this BinaryPart's data @@ -662,10 +655,10 @@ var BinaryPart = function(data, fileName, contentType) { writer.append("Content-Transfer-Encoding: binary").append(CRLF); writer.append(CRLF).flush(); if (data instanceof InputStream) { - (new Stream(data)).copy(outStream).close(); + (new io.Stream(data)).copy(outStream).close(); } else if (data instanceof Binary) { - (new MemoryStream(data)).copy(outStream).close(); - } else if (data instanceof Stream) { + (new io.MemoryStream(data)).copy(outStream).close(); + } else if (data instanceof io.Stream) { data.copy(outStream).close(); } writer.append(CRLF).flush(); @@ -673,11 +666,3 @@ var BinaryPart = function(data, fileName, contentType) { return this; }; - -module.exports.request = request; -module.exports.get = get; -module.exports.post = post; -module.exports.put = put; -module.exports.del = del; -module.exports.TextPart = TextPart; -module.exports.BinaryPart = BinaryPart; diff --git a/test/ringo/httpclient_test.js b/test/ringo/httpclient_test.js index 79baeba25..2e1a0a706 100644 --- a/test/ringo/httpclient_test.js +++ b/test/ringo/httpclient_test.js @@ -1,55 +1,51 @@ -var assert = require("assert"); -var objects = require("ringo/utils/objects"); -var {HttpServer} = require("ringo/httpserver"); -var response = require("ringo/jsgi/response"); -var {request, post, get, put, del, TextPart, BinaryPart} = require("ringo/httpclient"); -var {parseParameters, parseFileUpload, setCookie, Headers} = require("ringo/utils/http"); -var {MemoryStream, TextStream} = require("io"); -var fs = require("fs"); -var base64 = require("ringo/base64"); -var {ByteArray, ByteString} = require("binary"); -var {ByteArrayOutputStream} = java.io; -var {GZIPOutputStream, DeflaterOutputStream} = java.util.zip; - -var server; -var host = "127.0.0.1"; -var port = "8282"; -var baseUri = "http://" + host + ":" + port + "/"; +const assert = require("assert"); +const objects = require("ringo/utils/objects"); +const system = require("system"); +const {HttpServer} = require("ringo/httpserver"); +const response = require("ringo/jsgi/response"); +const {request, post, get, put, del, TextPart, BinaryPart} = require("ringo/httpclient"); +const {parseParameters, parseFileUpload, setCookie, Headers} = require("ringo/utils/http"); +const {MemoryStream, TextStream} = require("io"); +const fs = require("fs"); +const base64 = require("ringo/base64"); +const binary = require("binary"); +const {ByteArrayOutputStream, StringWriter} = java.io; +const {GZIPOutputStream, DeflaterOutputStream} = java.util.zip; +const {HttpServlet} = javax.servlet.http; + +const host = "127.0.0.1"; +const port = "8282"; +const baseUri = "http://" + host + ":" + port + "/"; +let server; require('ringo/logging').setConfig(getResource('./httptest_log4j2.properties')); /** * tests overwrite getResponse() to control the response they expect back */ -var getResponse; +let getResponse; /** * setUp pre every test */ -exports.setUp = function() { - var handleRequest = function(req) { +exports.setUp = () => { + server = new HttpServer(); + server.serveApplication("/", (req) => { req.charset = 'utf8'; req.pathInfo = decodeURI(req.pathInfo); return getResponse(req); - }; - - var config = { + }); + server.createHttpListener({ host: host, port: port - }; - - server = new HttpServer(); - server.serveApplication("/", handleRequest); - server.createHttpListener(config); + }); server.start(); - // test used to hang without this, but seems no longer the case - // java.lang.Thread.currentThread().sleep(1000); }; /** * tearDown after each test */ -exports.tearDown = function() { +exports.tearDown = () => { server.stop(); server.destroy(); server = null; @@ -58,26 +54,26 @@ exports.tearDown = function() { /** * test basic get */ -exports.testBasic = function() { +exports.testBasic = () => { const text = "This is the Response Text"; - getResponse = function(req) { + getResponse = (req) => { return response.html(text + " - " + req.headers["user-agent"]); }; - var exchange = request({ + const exchange = request({ url: baseUri }); assert.strictEqual(exchange.content, text + " - " + "RingoJS HttpClient " + require("ringo/engine").version.join(".")); }; -exports.testNullContent = function() { - getResponse = function(req) { +exports.testNullContent = () => { + getResponse = () => { return response.notFound(); }; - var exchange = request({ + const exchange = request({ url: baseUri }); @@ -87,16 +83,15 @@ exports.testNullContent = function() { /** * test user info in url */ -exports.testUserInfo = function() { +exports.testUserInfo = () => { - var log; - getResponse = function(req) { + getResponse = (req) => { log.push(req.headers["authorization"]); return response.html("response text"); }; // username and password in url - log = []; + let log = []; request({url: "http://user:pass@" + host + ":" + port + "/"}); assert.equal(log.length, 1, "user:pass - one request"); assert.equal(typeof log[0], "string", "user:pass - one Authorization header"); @@ -120,34 +115,34 @@ exports.testUserInfo = function() { /** * test servlet on request env (this is not httpclient specific, but uses same setUp tearDown) */ -exports.testServlet = function() { - var servlet; - getResponse = function(req) { +exports.testServlet = () => { + let servlet; + getResponse = (req) => { servlet = req.env.servlet; return response.html("servlet set"); }; - var exchange = request({ + const exchange = request({ url: baseUri }); assert.strictEqual(exchange.content, "servlet set"); - assert.ok(servlet instanceof javax.servlet.http.HttpServlet, "servlet instance"); + assert.ok(servlet instanceof HttpServlet, "servlet instance"); }; /** * convenience wrappers */ -exports.testConvenience = function() { - getResponse = function(req) { - var params = {}; - var input = req.method == "POST" ? req.input.read() : req.queryString; +exports.testConvenience = () => { + getResponse = (req) => { + const params = {}; + const input = (req.method === "POST") ? req.input.read() : req.queryString; parseParameters(input, params); if (params.foo) { return response.html(req.method + " with param"); } return response.html(req.method); }; - var x = post(baseUri); + let x = post(baseUri); assert.strictEqual(x.status, 200); assert.strictEqual(x.content, "POST"); @@ -171,20 +166,19 @@ exports.testConvenience = function() { /** * GET, POST params */ -exports.testParams = function() { - getResponse = function(req) { - var params = {}; - var input = req.method == "POST" ? req.input.read() : req.queryString; - parseParameters(input, params); +exports.testParams = () => { + getResponse = (req) => { + const input = (req.method === "POST") ? req.input.read() : req.queryString; + const params = parseParameters(input, {}); return response.json(params); }; - var data = { + const data = { a: "fääßß", b: "fööööbääzz", c: "08083", d: "0x0004" }; - var getExchange = request({ + const getExchange = request({ url: baseUri, method: 'GET', data: data @@ -192,7 +186,7 @@ exports.testParams = function() { assert.strictEqual(getExchange.status, 200); assert.deepEqual(JSON.parse(getExchange.content), data); - var postExchange = request({ + const postExchange = request({ url: baseUri, method: 'POST', data: data @@ -204,24 +198,27 @@ exports.testParams = function() { /** * Status Codes */ -exports.testStatusCodes = function() { - getResponse = function(req) { - if (req.pathInfo == '/notfound') { - return response.notFound().text("not found"); - } else if (req.pathInfo == '/success') { - return response.json('success'); - } else if (req.pathInfo == '/redirect') { - return { - status: 302, - headers: {Location: '/redirectlocation'}, - body: ["Found: " + '/redirectlocation'] - }; - } else if (req.pathInfo == '/redirectlocation') { - return response.html('redirect success'); +exports.testStatusCodes = () => { + getResponse = (req) => { + switch (req.pathInfo) { + case "/notfound": + return response.notFound().text("not found"); + case "/success": + return response.json('success'); + case "/redirect": + return { + status: 302, + headers: {Location: '/redirectlocation'}, + body: ["Found: " + '/redirectlocation'] + }; + case "/redirectlocation": + return response.html('redirect success'); + default: + throw new Error("Unknown req.pathInfo '" + req.pathInfo + "'"); } }; - var exchange = request({ + let exchange = request({ url: baseUri + 'notfound', method: 'GET' }); @@ -249,15 +246,14 @@ exports.testStatusCodes = function() { * Cookie set and read */ exports.testCookie = function() { - var COOKIE_NAME = "testcookie"; - var COOKIE_VALUE = "cookie value with s p a c es"; - var COOKIE_DAYS = 5; + const COOKIE_NAME = "testcookie"; + const COOKIE_VALUE = "cookie value with s p a c es"; + const COOKIE_DAYS = 5; - getResponse = function(req) { - var params = {}; - parseParameters(req.queryString, params); + getResponse = (req) => { + const params = parseParameters(req.queryString, {}); // set cookie - var res = response.html("cookie set"); + const res = response.html("cookie set"); res.headers["Set-Cookie"] = setCookie(COOKIE_NAME, params.cookievalue, COOKIE_DAYS, { "domain": "localhost", @@ -267,7 +263,7 @@ exports.testCookie = function() { }; // receive cookie - var exchange = request({ + const exchange = request({ url: baseUri, method: "GET", data: { @@ -275,7 +271,7 @@ exports.testCookie = function() { } }); assert.strictEqual(exchange.status, 200); - var cookie = exchange.cookies[COOKIE_NAME]; + const cookie = exchange.cookies[COOKIE_NAME]; assert.strictEqual(cookie.value, COOKIE_VALUE); // FIXME: why is -1 necessary? assert.strictEqual(cookie.maxAge, (5 * 24 * 60 * 60) - 1); @@ -286,45 +282,41 @@ exports.testCookie = function() { /** * send stream and get the same stream back */ -exports.testStreamRequest = function() { +exports.testStreamRequest = () => { - getResponse = function(req) { - var input; + getResponse = (req) => { return { status: 200, headers: { 'Content-Type': 'image/png' }, body: { - forEach: function(fn) { - var read, bufsize = 8192; - var buffer = new ByteArray(bufsize); - input = req.input; - while ((read = input.readInto(buffer)) > -1) { + forEach: (fn) => { + const bufsize = 8192; + const buffer = new binary.ByteArray(bufsize); + let read; + while ((read = req.input.readInto(buffer)) > -1) { buffer.length = read; fn(buffer); buffer.length = bufsize; } }, - close: function() { - if (input) { - input.close(); - } + close: () => { + req.input && req.input.close(); } } }; }; - var resource = getResource('./upload_test.png'); - var ByteArray = require('binary').ByteArray; - var inputStream = resource.getInputStream(); + const resource = getResource('./upload_test.png'); + const inputStream = resource.getInputStream(); // small <1k file, just read it all in - var size = resource.getLength(); - var inputByteArray = new ByteArray(size); + const size = resource.getLength(); + const inputByteArray = new binary.ByteArray(size); inputStream.read(inputByteArray, 0, size); - var sendInputStream = resource.getInputStream(); + const sendInputStream = resource.getInputStream(); - var exchange = request({ + const exchange = request({ url: baseUri, method: 'POST', data: sendInputStream @@ -335,20 +327,20 @@ exports.testStreamRequest = function() { assert.strictEqual(exchange.contentType, "image/png"); }; -exports.testContentDecoding = function() { - var unzipped = "abcdefghijklmnop"; +exports.testContentDecoding = () => { + const unzipped = "abcdefghijklmnop"; - var compress = function(CompressorOutputStream) { - var bos = new ByteArrayOutputStream(); - var cos = new CompressorOutputStream(bos, true); + const compress = (CompressorOutputStream) => { + const bos = new ByteArrayOutputStream(); + const cos = new CompressorOutputStream(bos, true); cos.write(unzipped.toByteArray()); cos.finish(); - var bytes = ByteArray.wrap(bos.toByteArray()); + const bytes = binary.ByteArray.wrap(bos.toByteArray()); cos.close(); return bytes; }; - var compressions = [ + const compressions = [ { encodings: ['deflate', 'dEfLaTe'], CompressorOutputStream: DeflaterOutputStream @@ -359,10 +351,11 @@ exports.testContentDecoding = function() { } ]; - for each (let {encodings, CompressorOutputStream} in compressions) { + compressions.forEach(compression => { + const {encodings, CompressorOutputStream} = compression; let compressed = compress(CompressorOutputStream); - for each (let encoding in encodings) { - getResponse = function(req) { + encodings.forEach(encoding => { + getResponse = (req) => { return { status: 200, headers: { @@ -370,58 +363,53 @@ exports.testContentDecoding = function() { 'Content-Encoding': encoding }, body: { - forEach: function(fn) { - return fn(compressed); - } + forEach: (fn) => fn(compressed) } }; }; - let exchange = request({ + const exchange = request({ url: baseUri, method: 'GET' }); assert.isNotNull(exchange, 'Content-Encoding: ' + encoding); assert.strictEqual(exchange.content, unzipped, 'Content-Encoding: ' + encoding); - } - } + }); + }) }; -exports.testPost = function() { +exports.testPost = () => { - getResponse = function(req) { - var input; + getResponse = (req) => { return { "status": 200, "headers": { "Content-Type": "application/octet-stream" }, "body": { - forEach: function(fn) { - var read, bufsize = 8192; - var buffer = new ByteArray(bufsize); - input = req.input; - while ((read = input.readInto(buffer)) > -1) { + forEach: (fn) => { + const bufsize = 8192; + const buffer = new binary.ByteArray(bufsize); + let read; + while ((read = req.input.readInto(buffer)) > -1) { buffer.length = read; fn(buffer); buffer.length = bufsize; } }, - close: function() { - if (input) { - input.close(); - } + close: () => { + req.input && req.input.close(); } } }; }; // use this module's source as test data - var data = fs.read(module.path); - var inputByteArray = data.toByteArray(); + const data = fs.read(module.path); + let inputByteArray = data.toByteArray(); // POSTing byte array - var exchange = request({ + let exchange = request({ url: baseUri, method: "POST", data: inputByteArray @@ -460,11 +448,11 @@ exports.testPost = function() { assert.strictEqual(exchange.contentBytes.length, inputByteArray.length); assert.deepEqual(exchange.contentBytes.toArray(), inputByteArray.toArray()); - var resource = getResource('./upload_test.png'); - var inputStream = resource.getInputStream(); + const resource = getResource('./upload_test.png'); + const inputStream = resource.getInputStream(); // small <1k file, just read it all in - var size = resource.getLength(); - inputByteArray = new ByteArray(size); + const size = resource.getLength(); + inputByteArray = new binary.ByteArray(size); inputStream.read(inputByteArray, 0, size); exchange = request({ url: baseUri, @@ -475,33 +463,33 @@ exports.testPost = function() { assert.deepEqual(inputByteArray.toArray(), exchange.contentBytes.toArray()); }; -exports.testPostMultipart = function() { +exports.testPostMultipart = () => { - var textFile = module.resolve("text_test.txt"); - var imageFile = module.resolve("upload_test.png"); - var received = {}; + const textFile = module.resolve("text_test.txt"); + const imageFile = module.resolve("upload_test.png"); + const received = {}; - getResponse = function(req) { - var encoding = req.env.servletRequest.getCharacterEncoding() || "utf8"; - var params = parseFileUpload(req, {}, encoding); - for (let [key, value] in Iterator(params)) { - received[key] = value; - } + getResponse = (req) => { + const encoding = req.env.servletRequest.getCharacterEncoding() || "utf8"; + const params = parseFileUpload(req, {}, encoding); + Object.keys(params).forEach(key => { + received[key] = params[key]; + }); return response.html("OK"); }; - var title = "testing multipart post"; - var textStream = fs.open(textFile, {"read": true, "charset": "utf-8"}); - var textFileStream = fs.open(textFile, {"read": true, "charset": "utf-8"}); - var binaryStream = fs.open(imageFile, {"read": true, "binary": true}); + const title = "testing multipart post"; + const textStream = fs.open(textFile, {"read": true, "charset": "utf-8"}); + const textFileStream = fs.open(textFile, {"read": true, "charset": "utf-8"}); + const binaryStream = fs.open(imageFile, {"read": true, "binary": true}); - var inputStream = fs.open(imageFile, {"read": true, "binary": true}); + const inputStream = fs.open(imageFile, {"read": true, "binary": true}); // small <1k file, just read it all in - var size = fs.size(imageFile); - var imageByteArray = new ByteArray(size); + const size = fs.size(imageFile); + const imageByteArray = new binary.ByteArray(size); inputStream.readInto(imageByteArray, 0, size); - var exchange = request({ + const exchange = request({ url: baseUri, method: "POST", contentType: "multipart/form-data", @@ -515,7 +503,7 @@ exports.testPostMultipart = function() { assert.strictEqual(exchange.status, 200); assert.strictEqual(received.title, title); // normalize line feeds, otherwise test fails on windows - var expectedText = fs.read(textFile).replace(/\r\n/g, "\n"); + const expectedText = fs.read(textFile).replace(/\r\n/g, "\n"); assert.strictEqual(received.text, expectedText); assert.isNotUndefined(received.textfile); assert.strictEqual(received.textfile.filename, fs.base(textFile)); @@ -537,14 +525,14 @@ exports.testPostMultipart = function() { }, Error); }; -exports.testProxiedRequest = function() { - var text = "

This is the Response Text

"; +exports.testProxiedRequest = () => { + const text = "

This is the Response Text

"; - getResponse = function(req) { + getResponse = () => { return response.html(text); }; - var exchange = request({ + let exchange = request({ url: "http://idontexistandifigetcalledwithoutproxyshouldraiseerror.com", proxy: [host, ":", port].join(""), }); @@ -557,29 +545,28 @@ exports.testProxiedRequest = function() { assert.strictEqual(exchange.content, text); }; -exports.testIterateExchange_Issue287 = function() { +exports.testIterateExchange_Issue287 = () => { //exchange.headers - var text = "

This is the Response Text

"; + const text = "

This is the Response Text

"; - getResponse = function(req) { + getResponse = () => { return response.html(text); }; - var errorCalled, myData; - var exchange = request({ + const exchange = request({ url: baseUri }); assert.strictEqual(exchange.content, text); - var clone = objects.clone(exchange.headers, false, 0); + const clone = objects.clone(exchange.headers, false, 0); assert.deepEqual(exchange.headers, clone); assert.isUndefined(exchange.headers[null]); }; -exports.testTimeoutResponse_Issue267 = function() { - getResponse = function(req) { - var loops = 0; - var started = Date.now(); +exports.testTimeoutResponse_Issue267 = () => { + getResponse = () => { + const started = Date.now(); + let loops = 0; while (Date.now() - started < 100) { loops++; } @@ -587,7 +574,7 @@ exports.testTimeoutResponse_Issue267 = function() { }; assert.throws(function() { - var exchange = request({ + request({ readTimeout: 1, url: baseUri }); @@ -595,13 +582,11 @@ exports.testTimeoutResponse_Issue267 = function() { }, java.net.SocketTimeoutException, "A timeout request should throw an exception!"); }; -exports.testNoCallbacks = function() { - getResponse = function(req) { - return response.text("foo"); - }; +exports.testNoCallbacks = () => { + getResponse = () => response.text("foo"); - var anyCallbackCalled = false; - var exchange = request({ + let anyCallbackCalled = false; + const exchange = request({ "url": baseUri, "success": function() { anyCallbackCalled = true; @@ -618,45 +603,45 @@ exports.testNoCallbacks = function() { assert.strictEqual(exchange.status, 200); }; -exports.testMultipleHeaders_Issue225 = function() { - getResponse = function(req) { +exports.testMultipleHeaders_Issue225 = () => { + getResponse = (req) => { assert.equal(req.env.servletRequest.getHeader("single-header"), "one", "Header not present"); assert.equal(req.env.servletRequest.getHeader("multiple-header"), "one,two", "Multiple headers not merged into one"); return response.text("done"); }; - let preparedHeaders = Headers({}); + const preparedHeaders = Headers({}); preparedHeaders.set("single-header", "one"); preparedHeaders.add("multiple-header", "one"); preparedHeaders.add("multiple-header", "two"); - var exchange = request({ + request({ url: baseUri, headers: preparedHeaders }); }; -exports.testStreamResponse = function() { - getResponse = function(req) { - var bs = new MemoryStream(3); - bs.write(new ByteString("\t\r\n", "ASCII")); +exports.testStreamResponse = () => { + getResponse = () => { + const bs = new MemoryStream(3); + bs.write(new binary.ByteString("\t\r\n", "ASCII")); bs.position = 0; return response.stream(bs); }; - var exchange = request({ + const exchange = request({ url: baseUri }); assert.strictEqual(exchange.content, "\t\r\n"); }; -exports.testBinaryResponse = function() { - getResponse = function(req) { - return response.binary(new ByteArray([35, 114, 105, 110, 103, 111, 106, 115])); +exports.testBinaryResponse = () => { + getResponse = () => { + return response.binary(new binary.ByteArray([35, 114, 105, 110, 103, 111, 106, 115])); }; - var exchange = request({ + const exchange = request({ url: baseUri, binary: true }); @@ -664,10 +649,10 @@ exports.testBinaryResponse = function() { assert.strictEqual(exchange.contentBytes.toArray().join(""), [35, 114, 105, 110, 103, 111, 106, 115].join("")); }; -exports.testBinaryPart = function() { +exports.testBinaryPart = () => { let bin, result; - let sw = new java.io.StringWriter(); - let bos = new java.io.ByteArrayOutputStream(); + let sw = new StringWriter(); + let bos = new ByteArrayOutputStream(); try { bin = new BinaryPart(fs.openRaw(module.resolve("./text_test.txt"), "r"), "foo.txt", "text/superplain"); @@ -684,8 +669,8 @@ exports.testBinaryPart = function() { try { bin = new BinaryPart(fs.openRaw(module.resolve("./text_test.txt"), "r"), "bar.txt"); - sw = new java.io.StringWriter(); - bos = new java.io.ByteArrayOutputStream(); + sw = new StringWriter(); + bos = new ByteArrayOutputStream(); bin.write("paramname", sw, bos); result = sw.toString().split("\r\n"); @@ -698,10 +683,10 @@ exports.testBinaryPart = function() { } }; -exports.testTextPart = function() { +exports.testTextPart = () => { let tp, result; - let sw = new java.io.StringWriter(); - let bos = new java.io.ByteArrayOutputStream(); + let sw = new StringWriter(); + let bos = new ByteArrayOutputStream(); try { tp = new TextPart("asdfasdfasdf", "ISO-8859-15", "foo.txt"); @@ -717,7 +702,7 @@ exports.testTextPart = function() { let stream = fs.open(module.resolve("./text_test.txt")); let mem = new MemoryStream(1000); - sw = new java.io.StringWriter(); + sw = new StringWriter(); try { tp = new TextPart(stream, "ISO-8859-15", "foo.txt"); @@ -734,7 +719,7 @@ exports.testTextPart = function() { stream = fs.open(module.resolve("./text_test.txt")); mem = new MemoryStream(1000); - sw = new java.io.StringWriter(); + sw = new StringWriter(); try { tp = new TextPart(stream); @@ -751,11 +736,7 @@ exports.testTextPart = function() { }; // start the test runner if we're called directly from command line -if (require.main === module) { - var {run} = require("test"); - var system = require("system"); - if (system.args.length > 1) { - system.exit(run(exports, system.args.pop())); - } - system.exit(run(exports)); +if (require.main == module.id) { + system.exit(require("test").run.apply(null, + [exports].concat(system.args.slice(1)))); } From da34dbda4b8492210e741e765bc40facd625db5e Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 11:34:27 +0100 Subject: [PATCH 19/52] code modernization --- modules/ringo/logging.js | 241 +++++++++++++++------------------------ 1 file changed, 89 insertions(+), 152 deletions(-) diff --git a/modules/ringo/logging.js b/modules/ringo/logging.js index 034a17d07..d2f54d956 100644 --- a/modules/ringo/logging.js +++ b/modules/ringo/logging.js @@ -15,7 +15,7 @@ * interface and emits logged messages using the log level name as event type. * * @example // Get a Logger for the current module - * var log = require('ringo/logging').getLogger(module.id); + * const log = require('ringo/logging').getLogger(module.id); * * log.debug('Connected to ', url, ' [GET]'); * log.error('This should not occur'); @@ -25,15 +25,13 @@ * */ -var strings = require('ringo/utils/strings'); -var {EventEmitter} = require('ringo/events'); +const strings = require('ringo/utils/strings'); +const {EventEmitter} = require('ringo/events'); // Use singleton to share flag across workers to avoid unwanted reconfiguration -var configured = module.singleton("configured"); -// interval id for configuration watcher -var configWatcher; +let configured = module.singleton("configured"); -var verbose = require('ringo/engine').getRhinoEngine().getConfig().isVerbose(); +const isVerbose = require('ringo/engine').getRhinoEngine().getConfig().isVerbose(); // Make exports object emit log events EventEmitter.call(exports); @@ -49,41 +47,41 @@ EventEmitter.call(exports); */ function Logger(name, impl) { - this.trace = function() { + this.trace = () => { if (impl.isTraceEnabled()) { - var msg = formatMessage(arguments); + const msg = formatMessage(arguments); impl.trace(msg); exports.emit("trace", name, msg); } }; - this.debug = function() { + this.debug = () => { if (impl.isDebugEnabled()) { - var msg = formatMessage(arguments); + const msg = formatMessage(arguments); impl.debug(msg); exports.emit("debug", name, msg); } }; - this.info = function() { + this.info = () => { if (impl.isInfoEnabled()) { - var msg = formatMessage(arguments); + const msg = formatMessage(arguments); impl.info(msg); exports.emit("info", name, msg); } }; - this.warn = function() { + this.warn = () => { if (impl.isWarnEnabled()) { - var msg = formatMessage(arguments); + const msg = formatMessage(arguments); impl.warn(msg); exports.emit("warn", name, msg); } }; - this.error = function() { + this.error = () => { if (impl.isErrorEnabled()) { - var msg = formatMessage(arguments); + const msg = formatMessage(arguments); impl.error(msg); exports.emit("error", name, msg); } @@ -92,27 +90,27 @@ function Logger(name, impl) { /** * @function */ - this.isTraceEnabled = impl.isTraceEnabled.bind(impl); + this.isTraceEnabled = () => impl.isTraceEnabled; /** * @function */ - this.isDebugEnabled = impl.isDebugEnabled.bind(impl); + this.isDebugEnabled = () => impl.isDebugEnabled; /** * @function */ - this.isInfoEnabled = impl.isInfoEnabled.bind(impl); + this.isInfoEnabled = () => impl.isInfoEnabled; /** * @function */ - this.isWarnEnabled = impl.isWarnEnabled.bind(impl); + this.isWarnEnabled = () => impl.isWarnEnabled; /** * @function */ - this.isErrorEnabled = impl.isErrorEnabled.bind(impl); + this.isErrorEnabled = () => impl.isErrorEnabled; } /** @@ -125,38 +123,36 @@ function Logger(name, impl) { * @param {Boolean} watchForUpdates if true a scheduler thread is started that * repeatedly checks the resource for updates. */ -function setConfig(resource) { - var {path, url} = resource; +const setConfig = exports.setConfig = function(resource) { var logContext = org.apache.logging.log4j.LogManager.getContext(false); - logContext.setConfigLocation(new java.net.URI(url)); + logContext.setConfigLocation(new java.net.URI(resource.url)); logContext.updateLoggers(); - configured = module.singleton("configured", function() { return true; }); -} + configured = module.singleton("configured", () => true); +}; /** * Get a logger for the given name. * @param {String} name the name of the logger * @returns {Logger} a logger instance for the given name */ -function getLogger(name) { +const getLogger = exports.getLogger = (name) => { name = name.replace(/\//g, '.'); - var impl = new LoggerImpl(name); - return new Logger(name, impl); -} + return new Logger(name, new LoggerImpl(name)); +}; -function formatMessage(args) { - var message = strings.format.apply(null, args); - for each (var arg in args) { +const formatMessage = (args) => { + let message = strings.format.apply(null, args); + Array.prototype.forEach.call(args, (arg) => { if (arg instanceof Error || arg instanceof java.lang.Throwable) { message = [ message, getScriptStack(arg, "\nScript stack:\n"), - verbose ? getJavaStack(arg, "Java stack:\n") : null + isVerbose ? getJavaStack(arg, "Java stack:\n") : null ].join(''); } - } + }); return message; -} +}; /** * Get a rendered JavaScript stack trace from a caught error. @@ -164,12 +160,13 @@ function formatMessage(args) { * @param {String} prefix to prepend to result if available * @return {String} the rendered JavaScript stack trace */ -function getScriptStack(error, prefix) { +const getScriptStack = exports.getScriptStack = (error, prefix) => { prefix = prefix || ""; - if (error && error.stack) + if (error && error.stack) { return prefix + error.stack; + } return ""; -} +}; /** * Get a rendered JavaScript stack trace from a caught error. @@ -177,175 +174,120 @@ function getScriptStack(error, prefix) { * @param {String} prefix to prepend to result if available * @return {String} the rendered JavaScript stack trace */ -function getJavaStack(error, prefix) { +const getJavaStack = exports.getJavaStack = (error, prefix) => { prefix = prefix || ""; - var exception = error && error.rhinoException ? + const exception = (error && error.rhinoException) ? error.rhinoException : error; if (exception instanceof java.lang.Throwable) { - var writer = new java.io.StringWriter(); - var printer = new java.io.PrintWriter(writer); + const writer = new java.io.StringWriter(); + const printer = new java.io.PrintWriter(writer); exception.printStackTrace(printer); return prefix + writer.toString(); } return ""; -} +}; /** * Logger implementation based on java.util.logging * @param {String} name the logger name */ -function JdkLogger(name) { +const JdkLogger = function(name) { - var log = java.util.logging.Logger.getLogger(name); - var Level = java.util.logging.Level; + const log = java.util.logging.Logger.getLogger(name); + const Level = java.util.logging.Level; - this.trace = function(msg) { - log.logp(Level.FINEST, null, null, msg); - }; + this.trace = (msg) => log.logp(Level.FINEST, null, null, msg); - this.debug = function(msg) { - log.logp(Level.FINE, null, null, msg); - }; + this.debug = (msg) => log.logp(Level.FINE, null, null, msg); - this.info = function(msg) { - log.logp(Level.INFO, null, null, msg); - }; + this.info = (msg) => log.logp(Level.INFO, null, null, msg); - this.warn = function(msg) { - log.logp(Level.WARNING, null, null, msg); - }; + this.warn = (msg) => log.logp(Level.WARNING, null, null, msg); - this.error = function(msg) { - log.logp(Level.SEVERE, null, null, msg); - }; + this.error = (msg) => log.logp(Level.SEVERE, null, null, msg); - this.isTraceEnabled = function() { - return log.isLoggable(Level.FINEST); - }; + this.isTraceEnabled = () => log.isLoggable(Level.FINEST); - this.isDebugEnabled = function() { - return log.isLoggable(Level.FINE); - }; + this.isDebugEnabled = () => log.isLoggable(Level.FINE); - this.isInfoEnabled = function() { - return log.isLoggable(Level.INFO); - }; + this.isInfoEnabled = () => log.isLoggable(Level.INFO); - this.isWarnEnabled = function() { - return log.isLoggable(Level.WARNING); - }; + this.isWarnEnabled = () => log.isLoggable(Level.WARNING); - this.isErrorEnabled = function() { - return log.isLoggable(Level.SEVERE); - }; -} + this.isErrorEnabled = () => log.isLoggable(Level.SEVERE); + + return this; +}; /** * Logger implementation based on log4j * @param {String} name the logger name */ -function Log4jLogger(name) { +const Log4jLogger = function(name) { if (!configured) { setConfig(getResource('config/log4j2.properties')); } - var log = org.apache.logging.log4j.LogManager.getLogger(name); - this.trace = function(msg) { - // TODO: older versions of log4j don't support trace - log.trace(msg); - }; + const log = org.apache.logging.log4j.LogManager.getLogger(name); - this.debug = function(msg) { - log.debug(msg); - }; + this.trace = (msg) => log.trace(msg); - this.info = function(msg) { - log.info(msg); - }; + this.debug = (msg) => log.debug(msg); - this.warn = function(msg) { - log.warn(msg); - }; + this.info = (msg) => log.info(msg); - this.error = function(msg) { - log.error(msg); - }; + this.warn = (msg) => log.warn(msg); - this.isTraceEnabled = function() { - return log.isTraceEnabled(); - }; + this.error = (msg) =>log.error(msg); - this.isDebugEnabled = function() { - return log.isDebugEnabled(); - }; + this.isTraceEnabled = () => log.isTraceEnabled(); - this.isInfoEnabled = function() { - return log.isInfoEnabled(); - }; + this.isDebugEnabled = () => log.isDebugEnabled(); - this.isWarnEnabled = function() { - return log.isWarnEnabled(); - }; + this.isInfoEnabled = () => log.isInfoEnabled(); - this.isErrorEnabled = function() { - return log.isErrorEnabled(); - }; -} + this.isWarnEnabled = () => log.isWarnEnabled(); + + this.isErrorEnabled = () => log.isErrorEnabled(); + + return this; +}; /** * Logger implementation based on SLF4J * @param {String} name the logger name */ -function Slf4jLogger(name) { +const Slf4jLogger = function(name) { if (!configured) { setConfig(getResource('config/log4j2.properties')); } - var log = org.slf4j.LoggerFactory.getLogger(name); + const log = org.slf4j.LoggerFactory.getLogger(name); - this.trace = function(msg) { - log.trace(msg); - }; + this.trace = (msg) => log.trace(msg); - this.debug = function(msg) { - log.debug(msg); - }; + this.debug = (msg) => log.debug(msg); - this.info = function(msg) { - log.info(msg); - }; + this.info = (msg) => log.info(msg); - this.warn = function(msg) { - log.warn(msg); - }; + this.warn = (msg) => log.warn(msg); - this.error = function(msg) { - log.error(msg); - }; + this.error = (msg) => log.error(msg); - this.isTraceEnabled = function() { - return log.isTraceEnabled(); - }; + this.isTraceEnabled = () => log.isTraceEnabled(); - this.isDebugEnabled = function() { - return log.isDebugEnabled(); - }; + this.isDebugEnabled = () => log.isDebugEnabled(); - this.isInfoEnabled = function() { - return log.isInfoEnabled(); - }; + this.isInfoEnabled = () => log.isInfoEnabled(); - this.isWarnEnabled = function() { - return log.isWarnEnabled(); - }; + this.isWarnEnabled = () => log.isWarnEnabled(); - this.isErrorEnabled = function() { - return log.isErrorEnabled(); - }; -} + this.isErrorEnabled = () => log.isErrorEnabled(); -var LoggerImpl; + return this; +}; +let LoggerImpl; if (typeof org.slf4j.LoggerFactory.getLogger === "function") { LoggerImpl = Slf4jLogger; } else if (typeof org.apache.logging.log4j.LogManager.getLogger === "function") { @@ -353,8 +295,3 @@ if (typeof org.slf4j.LoggerFactory.getLogger === "function") { } else { LoggerImpl = JdkLogger; } - -module.exports.getLogger = getLogger; -module.exports.setConfig = setConfig; -module.exports.getScriptStack = getScriptStack; -module.exports.getJavaStack = getJavaStack; From 8f4f2c3c7d807981a994028805563fadd2cebffc Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 11:36:00 +0100 Subject: [PATCH 20/52] code modernization (ie. var -> const/let) --- modules/ringo/mime.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/ringo/mime.js b/modules/ringo/mime.js index 348490ff1..75a34607a 100644 --- a/modules/ringo/mime.js +++ b/modules/ringo/mime.js @@ -2,7 +2,7 @@ * @fileOverview This module provides functionality for determining the MIME type for a * given file extension. * - * @example >> var mime = require('ringo/mime'); + * @example >> const mime = require('ringo/mime'); * >> mime.mimeType('photo.jpg'); * 'image/jpeg' * >> mime.mimeType('video.m4v'); @@ -21,8 +21,8 @@ * @param {String} fallback MIME type to return if file extension is unknown * @returns {String} the MIME type for the file name */ -exports.mimeType = function(fileName, fallback) { - var ext = fileName.slice(fileName.lastIndexOf('.')).toLowerCase(); +exports.mimeType = (fileName, fallback) => { + const ext = fileName.slice(fileName.lastIndexOf('.')).toLowerCase(); return exports.MIME_TYPES[ext] || fallback || 'application/octet-stream'; }; @@ -133,11 +133,8 @@ exports.MIME_TYPES = { ".odi" : "application/vnd.oasis.opendocument.image", ".odm" : "application/vnd.oasis.opendocument.text-master", ".odp" : "application/vnd.oasis.opendocument.presentation", - ".odp" : "application/vnd.oasis.opendocument.presentation", - ".ods" : "application/vnd.oasis.opendocument.spreadsheet", ".ods" : "application/vnd.oasis.opendocument.spreadsheet", ".odt" : "application/vnd.oasis.opendocument.text", - ".odt" : "application/vnd.oasis.opendocument.text", ".ogg" : "application/ogg", ".ogx" : "application/ogg", ".otg" : "application/vnd.oasis.opendocument.graphics-template", From 27640b5e93c829ff4d389493c1086806648dbf50 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 11:56:11 +0100 Subject: [PATCH 21/52] bugfix: arrow functions have no arguments object --- modules/ringo/logging.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ringo/logging.js b/modules/ringo/logging.js index d2f54d956..0879133b4 100644 --- a/modules/ringo/logging.js +++ b/modules/ringo/logging.js @@ -47,7 +47,7 @@ EventEmitter.call(exports); */ function Logger(name, impl) { - this.trace = () => { + this.trace = function() { if (impl.isTraceEnabled()) { const msg = formatMessage(arguments); impl.trace(msg); @@ -55,7 +55,7 @@ function Logger(name, impl) { } }; - this.debug = () => { + this.debug = function() { if (impl.isDebugEnabled()) { const msg = formatMessage(arguments); impl.debug(msg); @@ -63,7 +63,7 @@ function Logger(name, impl) { } }; - this.info = () => { + this.info = function() { if (impl.isInfoEnabled()) { const msg = formatMessage(arguments); impl.info(msg); @@ -71,7 +71,7 @@ function Logger(name, impl) { } }; - this.warn = () => { + this.warn = function() { if (impl.isWarnEnabled()) { const msg = formatMessage(arguments); impl.warn(msg); @@ -79,7 +79,7 @@ function Logger(name, impl) { } }; - this.error = () => { + this.error = function() { if (impl.isErrorEnabled()) { const msg = formatMessage(arguments); impl.error(msg); From 6399f0720008793809dddfed4ced70fa4ad24241 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 11:59:55 +0100 Subject: [PATCH 22/52] code modernization disentangled Frame and Profiler constructors: moved Frame constructor out of Profiler constructor, and pass the stack it needs as argument --- modules/ringo/profiler.js | 269 +++++++++++++++++++------------------- 1 file changed, 131 insertions(+), 138 deletions(-) diff --git a/modules/ringo/profiler.js b/modules/ringo/profiler.js index 02319440e..03391e9fd 100644 --- a/modules/ringo/profiler.js +++ b/modules/ringo/profiler.js @@ -4,9 +4,25 @@ * the profiler on optimized code will produce no data. */ -var strings = require('ringo/utils/strings'); -var log = require('ringo/logging').getLogger(module.id); -var Buffer = require('ringo/buffer').Buffer; +const strings = require('ringo/utils/strings'); +const log = require('ringo/logging').getLogger(module.id); +const Buffer = require('ringo/buffer').Buffer; +const {nanoTime} = java.lang.System; +const engine = require("ringo/engine"); + +/** + * @param {Function} script + */ +const getScriptName = (script) => { + if (script.isFunction()) { + const name = [script.sourceName, " #", script.lineNumbers[0]]; + if (script.functionName) { + name.push(": ", script.functionName); + } + return name.join(""); + } + return script.sourceName; +}; /** * Convenience function for profiling the invocation of a function. @@ -17,15 +33,14 @@ var Buffer = require('ringo/buffer').Buffer; *
  • error: the error thrown by the function, if any
  • *
  • profiler: the Profiler instance used to profile the invocation
  • */ -module.exports.profile = function profile(func, maxFrames) { - var engine = require("ringo/engine"); +exports.profile = (func, maxFrames) => { if (engine.getOptimizationLevel() > -1) { log.warn("Profiling with optimization enabled will not produce any results.", "Please set the optimization level to -1 when using the profiler."); } - var profiler = new Profiler(); - var result, error; + const profiler = new Profiler(); profiler.attach(); + let result, error; try { result = func(); } catch (e) { @@ -37,16 +52,105 @@ module.exports.profile = function profile(func, maxFrames) { result: result, error: error, profiler: profiler - } -} + }; +}; + +/** + * @param {String} name + * @param {Array} stack + */ +const Frame = function(name, stack) { + + // The timer for the current invocation of this frame. + // This is an object containing start and end timestamp properties and + // a subTimers array property containing timers for functions directly + // invoked from this frame. + let currentTimer; + const timerStack = []; // Timer stack for other currently active invocations of this frame + const finishedTimers = []; // Timer list of finished invocations of this frame + + Object.defineProperty(this, "name", { + "value": name, + "enumerable": true + }); + + /** + * @param {Object} cx + * @param {Object} activation + * @param {Object} thisObj + * @param {*...} args... + */ + this.onEnter = function(cx, activation, thisObj, args) { + if (currentTimer) { + timerStack.push(currentTimer); + } + const now = nanoTime(); + currentTimer = { + name: name, + start: now, + subTimers: [] + // invoker: stack.length ? stack[stack.length - 1].name : null + }; + stack.push(this); + }; + + /** + * @param {Object} cx + * @param {Object} ex + */ + this.onExceptionThrown = function(cx, ex) {}; + + this.onExit = function(cx, byThrow, resultOrException) { + currentTimer.end = nanoTime(); + stack.pop(); + if (stack.length > 0) { + stack[stack.length - 1].addSubTimer(currentTimer); + } + finishedTimers.push(currentTimer); + currentTimer = timerStack.pop(); + }; + + this.addSubTimer = function(subTimer) { + currentTimer.subTimers.push(subTimer); + }; + + this.getSelftime = function() { + return finishedTimers.reduce((prev, e) => { + // add this timer's runtime minus the accumulated sub-timers + return (prev + e.end - e.start) - e.subTimers.reduce((prev, e) => { + return prev + e.end - e.start; + }, 0); + }, 0); + }; + + this.getRuntime = function() { + return finishedTimers.reduce((prev, e) => { + return prev + (e.end - e.start); + }, 0); + }; + + this.countInvocations = function() { + return finishedTimers.length; + }; + + this.renderLine = function(prefixLength) { + const runtime = this.getSelftime() / 1000000; + const count = this.countInvocations(); + const formatter = new java.util.Formatter(); + formatter.format("%1$7.0f ms %2$5.0f ms %3$6.0f %4$s", + runtime, Math.round(runtime / count), count, name.slice(prefixLength)); + return formatter.toString(); + }; + + return new org.mozilla.javascript.debug.DebugFrame(this); +}; /** * A class for measuring the frequency and runtime of function invocations. */ -module.exports.Profiler = function Profiler() { - var stack = []; - var frames = {}; - var nanoTime = java.lang.System.nanoTime; +const Profiler = exports.Profiler = function() { + const stack = []; + const frames = {}; /** * @param {Object} cx @@ -56,66 +160,45 @@ module.exports.Profiler = function Profiler() { if (!script.isFunction()) { return null; } - var name = getScriptName(script); - var frame = frames[name]; + const name = getScriptName(script); + let frame = frames[name]; if (!frame) { - frame = new Frame(name); + frame = new Frame(name, stack); frames[name] = frame; } return frame; }; - /** - * @param {Function} script - */ - var getScriptName = function(script) { - if (script.isFunction()) { - var name = [script.sourceName, " #", script.lineNumbers[0]]; - if (script.functionName) { - name.push(": ", script.functionName); - } - return name.join(""); - } else { - return script.sourceName; - } - }; - this.getFrames = function() { - var list = []; - for each (var frame in frames) { - list.push(frame); - } // sort list according to total runtime - list = list.sort(function(a, b) { - return b.getSelftime() - a.getSelftime(); - }); - return list; + return Object.keys(frames) + .map(key => frames[key]) + .sort((a, b) => b.getSelftime() - a.getSelftime()); }; /** * @param {Number} maxFrames optional maximal number of frames to include */ this.formatResult = function(maxFrames) { - var list = this.getFrames(); + const list = this.getFrames(); // cut list to maxFrames elements if (typeof maxFrames == "number") { list.length = maxFrames; } - var count = 0; - var maxLength = 0; // find common prefix in path names - var commonPrefix = list.reduce(function(previous, current) { + const commonPrefix = list.reduce((previous, current) => { return strings.getCommonPrefix(previous, current.name); }, ""); var lines = []; - for each (var item in list) { - var str = item.renderLine(commonPrefix.length); + let maxLength = 0; + list.forEach(item => { + const str = item.renderLine(commonPrefix.length); maxLength = Math.max(maxLength, str.length); lines.push(str); - } - var buffer = new Buffer(); + }) + const buffer = new Buffer(); buffer.writeln(" total average calls path"); - for (var i = 1; i < maxLength; i++) { + for (let i = 1; i < maxLength; i++) { buffer.write("-"); } buffer.writeln(); @@ -127,96 +210,6 @@ module.exports.Profiler = function Profiler() { return this.formatResult(null); }; - /** - * @param {String} name - */ - function Frame(name) { - - // The timer for the current invocation of this frame. - // This is an object containing start and end timestamp properties and - // a subTimers array property containing timers for functions directly - // invoked from this frame. - var currentTimer; - var timerStack = []; // Timer stack for other currently active invocations of this frame - var finishedTimers = []; // Timer list of finished invocations of this frame - this.name = name; - - /** - * @param {Object} cx - * @param {Object} activation - * @param {Object} thisObj - * @param {*...} args... - */ - this.onEnter = function(cx, activation, thisObj, args) { - if (currentTimer) { - timerStack.push(currentTimer); - } - var now = nanoTime(); - currentTimer = { - name: name, - start: now, - subTimers: [] - // invoker: stack.length ? stack[stack.length - 1].name : null - }; - stack.push(this); - }; - - /** - * @param {Object} cx - * @param {Object} ex - */ - this.onExceptionThrown = function(cx, ex) { - }; - - this.onExit = function(cx, byThrow, resultOrException) { - currentTimer.end = nanoTime(); - stack.pop(); - if (stack.length > 0) { - stack[stack.length - 1].addSubTimer(currentTimer); - } - finishedTimers.push(currentTimer); - currentTimer = timerStack.pop(); - }; - - this.addSubTimer = function(subTimer) { - currentTimer.subTimers.push(subTimer); - }; - - this.getSelftime = function() { - return finishedTimers.reduce( - function(prev, e) { - // add this timer's runtime minus the accumulated sub-timers - return (prev + e.end - e.start) - e.subTimers.reduce(function(prev, e) { - return prev + e.end - e.start; - }, 0); - }, 0 - ); - }; - - this.getRuntime = function() { - return finishedTimers.reduce( - function(prev, e) { - return prev + (e.end - e.start); - }, 0 - ); - }; - - this.countInvocations = function() { - return finishedTimers.length; - }; - - this.renderLine = function(prefixLength) { - var runtime = this.getSelftime() / 1000000; - var count = this.countInvocations(); - var formatter = new java.util.Formatter(); - formatter.format("%1$7.0f ms %2$5.0f ms %3$6.0f %4$s", - runtime, Math.round(runtime / count), count, name.slice(prefixLength)); - return formatter.toString(); - }; - - return new org.mozilla.javascript.debug.DebugFrame(this); - } - var profiler = new org.ringojs.util.DebuggerBase(this); profiler.debuggerScript = module.id + ".js"; return profiler; From 3630d6f3bf70a42befeb099cb96e6ec858565a14 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 12:32:56 +0100 Subject: [PATCH 23/52] code modernization (ie. var -> const/let) --- modules/ringo/promise.js | 64 ++++++++++++++++++-------------------- modules/ringo/worker.js | 55 ++++++++++++++++---------------- test/ringo/promise_test.js | 48 ++++++++++++++-------------- 3 files changed, 84 insertions(+), 83 deletions(-) diff --git a/modules/ringo/promise.js b/modules/ringo/promise.js index ff0ed5340..48b9a3d39 100644 --- a/modules/ringo/promise.js +++ b/modules/ringo/promise.js @@ -2,9 +2,9 @@ * @fileOverview Allows to work with deferred values that will be resolved in the future. */ -var NEW = 0; -var FULFILLED = 1; -var FAILED = 2; +const NEW = 0; +const FULFILLED = 1; +const FAILED = 2; /** * Creates an object representing a deferred value. @@ -47,10 +47,10 @@ var FAILED = 2; * }); */ const Deferred = exports.Deferred = function Deferred() { - var value; - var listeners = []; - var state = NEW; - var lock = new java.lang.Object(); + const lock = new java.lang.Object(); + let value; + let listeners = []; + let state = NEW; /** * Resolve the promise. @@ -59,7 +59,7 @@ const Deferred = exports.Deferred = function Deferred() { * @param {Boolean} isError if true the promise is resolved as failed * @type Function */ - var resolve = sync(function(result, isError) { + const resolve = sync((result, isError) => { if (state !== NEW) { throw new Error("Promise has already been resolved."); } @@ -70,10 +70,10 @@ const Deferred = exports.Deferred = function Deferred() { lock.notifyAll(); }, lock); - var notify = function(listener) { - var isError = (state === FAILED); - var callback = isError ? listener.errback : listener.callback; - var result = value; + const notify = listener => { + let isError = (state === FAILED); + let result = value; + const callback = isError ? listener.errback : listener.callback; if (callback) { try { @@ -85,9 +85,9 @@ const Deferred = exports.Deferred = function Deferred() { } // If result is a promise, chain its result to our existing promise. Else resolve directly. if (result != null && typeof result.then === 'function') { - result.then(function(val) { + result.then(val => { listener.tail.resolve(val, isError); - }, function(err) { + }, err => { listener.tail.resolve(err, true); }); } else { @@ -100,7 +100,7 @@ const Deferred = exports.Deferred = function Deferred() { * to be invoked when the promise is eventually resolved. * @name Deferred.prototype.promise */ - var promise = { + const promise = { /** * Register callback and errback functions to be invoked when * the promise is resolved. @@ -110,12 +110,12 @@ const Deferred = exports.Deferred = function Deferred() { * @return {Object} a new promise that resolves to the return value of the * callback or errback when it is called. */ - then: sync(function(callback, errback) { + then: sync((callback, errback) => { if (typeof callback !== "function") { throw new Error("First argument to then() must be a function."); } - var tail = new Deferred(); - var listener = { + const tail = new Deferred(); + const listener = { tail: tail, callback: callback, errback: errback @@ -136,7 +136,7 @@ const Deferred = exports.Deferred = function Deferred() { * @return {Object} the value if the promise is resolved as fulfilled * @throws Object the error value if the promise is resolved as failed */ - wait: sync(function(timeout) { + wait: sync(timeout => { if (state === NEW) { if (typeof timeout === "undefined") { lock.wait(); @@ -156,7 +156,7 @@ const Deferred = exports.Deferred = function Deferred() { resolve: resolve, promise: promise }; -} +}; /** * The PromiseList class allows to combine several promises into one. @@ -195,35 +195,33 @@ const Deferred = exports.Deferred = function Deferred() { * d3.resolve("some error", true); * d1.resolve("i am ok"); */ -const PromiseList = exports.PromiseList = function PromiseList(args) { - var promises = Array.isArray(args) ? args : Array.prototype.slice.call(arguments); - var count = new java.util.concurrent.atomic.AtomicInteger(promises.length); - var results = []; - var i = 0; - var deferred = new Deferred(); +exports.PromiseList = function PromiseList(args) { + const promises = Array.isArray(args) ? args : Array.prototype.slice.call(arguments); + const count = new java.util.concurrent.atomic.AtomicInteger(promises.length); + const results = []; + const deferred = new Deferred(); - promises.forEach(function(promise) { + promises.forEach((promise, index) => { if (typeof promise.then !== "function" && promise.promise) { promise = promise.promise; } - var index = i++; promise.then( - sync(function(value) { + sync(value => { results[index] = {value: value}; - if (count.decrementAndGet() == 0) { + if (count.decrementAndGet() === 0) { deferred.resolve(results); } }, count), - sync(function(error) { + sync(error => { results[index] = {error: error}; - if (count.decrementAndGet() == 0) { + if (count.decrementAndGet() === 0) { deferred.resolve(results); } }, count) ); }); return deferred.promise; -} +}; /** * A promise object. This class is not exported, create a diff --git a/modules/ringo/worker.js b/modules/ringo/worker.js index 156143d74..ec7049ed2 100644 --- a/modules/ringo/worker.js +++ b/modules/ringo/worker.js @@ -10,11 +10,8 @@ * @see Simple worker example * @see RingoJS: Workers and Multithreading */ -var engine = require("ringo/engine"); -var Deferred = require("ringo/promise").Deferred; - -exports.Worker = Worker; -exports.WorkerPromise = WorkerPromise; +const engine = require("ringo/engine"); +const {Deferred} = require("ringo/promise"); /** * A Worker thread loosely modeled after the @@ -41,31 +38,31 @@ exports.WorkerPromise = WorkerPromise; * @constructor * @see RingoJS: Workers and Multithreading */ -function Worker(moduleId) { +const Worker = exports.Worker = function(moduleId) { if (!(this instanceof Worker)) { return new Worker(moduleId); } - var self = this; - var worker = engine.getWorker(); + const self = this; + let worker = engine.getWorker(); // Load module immediately and wait till done. This will // throw an error if module can't be loaded. worker.loadModuleInWorkerThread(moduleId).get(); - function onmessage(e) { + const onmessage = (e) => { if (typeof self.onmessage === "function") { self.onmessage(e); } } - function onerror(e) { + const onerror = (e) => { if (typeof self.onerror === "function") { self.onerror(e); } } - worker.setErrorListener(function(t) { + worker.setErrorListener(t => { onerror({data: t}); }); @@ -97,21 +94,27 @@ function Worker(moduleId) { if (!worker) { throw new Error("Worker has been terminated"); } - var invokeCallback = function(callback, arg) { - if (syncCallbacks) callback(arg); - else currentWorker.submit(self, callback, arg); + const invokeCallback = function(callback, arg) { + if (syncCallbacks) { + callback(arg); + } else { + currentWorker.submit(self, callback, arg); + } }; - var source = { - postMessage: function(data) { + const source = { + postMessage: (data) => { invokeCallback(onmessage, {data: data, source: self}); }, - postError: function(error) { + postError: (error) => { invokeCallback(onerror, {data: error, source: self}) } }; - var currentWorker = engine.getCurrentWorker(); - var event = {data: data, source: source}; - worker.submit(self, function() { + const currentWorker = engine.getCurrentWorker(); + const event = { + data: data, + source: source + }; + worker.submit(self, () => { try { worker.invoke(moduleId, "onmessage", event); } catch (error) { @@ -160,10 +163,10 @@ function Worker(moduleId) { * @constructor * @see ringo/promise#Promise */ -function WorkerPromise(moduleId, message, syncCallbacks) { - var deferred = new Deferred(); - var worker = new Worker(moduleId); - var resolved = false; +exports.WorkerPromise = function(moduleId, message, syncCallbacks) { + const deferred = new Deferred(); + const worker = new Worker(moduleId); + let resolved = false; worker.onmessage = function(e) { resolve(e.data, false); @@ -173,7 +176,7 @@ function WorkerPromise(moduleId, message, syncCallbacks) { resolve(e.data, true); }; - function resolve(message, isError) { + const resolve = (message, isError) => { if (!resolved) { resolved = true; deferred.resolve(message, isError); @@ -204,4 +207,4 @@ function WorkerPromise(moduleId, message, syncCallbacks) { * @return {Object} the value if the promise is resolved as fulfilled * @throws Object the error value if the promise is resolved as failed */ -} \ No newline at end of file +}; diff --git a/test/ringo/promise_test.js b/test/ringo/promise_test.js index f58bd27c9..46610ab67 100644 --- a/test/ringo/promise_test.js +++ b/test/ringo/promise_test.js @@ -1,11 +1,11 @@ -var assert = require("assert"); -var {Deferred, PromiseList} = require("ringo/promise"); -var {WorkerPromise} = require("ringo/worker"); -var system = require("system"); +const assert = require("assert"); +const {Deferred, PromiseList} = require("ringo/promise"); +const {WorkerPromise} = require("ringo/worker"); +const system = require("system"); exports.testPromise = function() { - var d1 = new Deferred(), d2 = new Deferred(); - var v1, v2, e2; + const d1 = new Deferred(), d2 = new Deferred(); + let v1, v2, e2; d1.promise.then(function(value) { v1 = value; }); @@ -25,9 +25,9 @@ exports.testPromise = function() { }; exports.testPromiseList = function() { - var d1 = Deferred(), d2 = Deferred(), d3 = Deferred(), done = Deferred(); - var l = PromiseList(d1.promise, d2.promise, d3); // PromiseList should convert d3 to promise - var result; + const d1 = Deferred(), d2 = Deferred(), d3 = Deferred(), done = Deferred(); + const l = PromiseList(d1.promise, d2.promise, d3); // PromiseList should convert d3 to promise + let result; l.then(function(value) { done.resolve(value); }, function(error) { @@ -44,13 +44,13 @@ exports.testPromiseList = function() { }; exports.testPromiseListWait = function() { - var w1 = new WorkerPromise( module.resolve('./promise_worker'), { delay: 100 }, true ); - var w2 = new WorkerPromise( module.resolve('./promise_worker'), { delay: 100 }, true ); - var l = PromiseList(w1, w2); + const w1 = new WorkerPromise( module.resolve('./promise_worker'), { delay: 100 }, true ); + const w2 = new WorkerPromise( module.resolve('./promise_worker'), { delay: 100 }, true ); + const l = PromiseList(w1, w2); - var then = new Date().getTime(); - var result = l.wait(1000); - var elapsed = new Date().getTime() - then; + const then = Date.now(); + const result = l.wait(1000); + const elapsed = Date.now() - then; // The workers should finish in 100ms, therefore the PromiseList should end at // about the same time. If a second has passed, the PromiseList is not properly @@ -60,9 +60,9 @@ exports.testPromiseListWait = function() { }; exports.testPromiseListAsArray = function() { - var d1 = Deferred(), d2 = Deferred(), d3 = Deferred(), done = Deferred(); - var l = PromiseList([d1.promise, d2.promise, d3]); // PromiseList should convert d3 to promise - var result; + const d1 = Deferred(), d2 = Deferred(), d3 = Deferred(), done = Deferred(); + const l = PromiseList([d1.promise, d2.promise, d3]); // PromiseList should convert d3 to promise + let result; l.then(function(value) { done.resolve(value); }, function(error) { @@ -79,8 +79,8 @@ exports.testPromiseListAsArray = function() { }; exports.testPromiseMultipleCallbacks = function() { - var d = new Deferred(); - var v1, v2; + const d = new Deferred(); + let v1, v2; d.promise.then(function(value) { return value + 2; }).then(function(value) { @@ -97,8 +97,8 @@ exports.testPromiseMultipleCallbacks = function() { }; exports.testPromiseChain = function() { - var d1 = new Deferred(), d2 = new Deferred(); - var v1, v2, v3; + const d1 = new Deferred(), d2 = new Deferred(); + let v1, v2, v3; d1.promise.then(function(value) { v1 = value; return v1; @@ -116,8 +116,8 @@ exports.testPromiseChain = function() { }; exports.testPromiseChainFail = function() { - var d = new Deferred(); - var v1, v2, v3, err; + const d = new Deferred(); + let v1, v2, v3, err; d.promise.then(function(value) { v1 = value; throw 'error'; From 305f511370968e473f95ce68495357bce7eaba47 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 12:52:52 +0100 Subject: [PATCH 24/52] code modernization (ie. var -> const/let) --- modules/ringo/shell.js | 143 ++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 75 deletions(-) diff --git a/modules/ringo/shell.js b/modules/ringo/shell.js index 82e4abd77..8d1681d26 100644 --- a/modules/ringo/shell.js +++ b/modules/ringo/shell.js @@ -7,21 +7,34 @@ * * @example #!/usr/bin/env ringo * if (require.main == module) { - * var obj = { 'foo': 'bar' }; + * const obj = { 'foo': 'bar' }; * require('ringo/shell').start(); * } * * // running the script opens a new shell * // with the prepared object available - * >> console.log(obj); + * >> console.dir(obj); * { foo: 'bar' } */ -var system = require('system'); -var term = require('ringo/term'); +const system = require('system'); +const term = require('ringo/term'); +const {Character} = java.lang; +const styles = { + 'number': term.BLUE, + 'string': term.GREEN, + 'function': term.CYAN, + 'boolean': term.YELLOW, + 'null': term.BOLD, + 'date': term.MAGENTA, + 'java': term.MAGENTA, + 'custom': term.RED +}; + +let input = null; try { - var input = new Packages.jline.console.ConsoleReader(); + input = new Packages.jline.console.ConsoleReader(); } catch (x) { // fall back to plain standard input } @@ -30,34 +43,35 @@ try { * Write 0..n arguments to standard output. * @param {*...} args... */ -function write() { - var length = arguments.length; - var out = system.stdout; - for (var i = 0; i < length; i++) { +const write = exports.write = function() { + const length = arguments.length; + const out = system.stdout; + for (let i = 0; i < length; i++) { out.write(String(arguments[i])); - if (i < length - 1) + if (i < length - 1) { out.write(' '); + } } -} +}; /** * Write 0..n arguments to standard output, followed by a newline. * @param {*...} args... */ -function writeln() { +exports.writeln = function() { write.apply(this, arguments); system.stdout.writeLine(''); -} +}; /** * Read a single character from the standard input. */ -function read() { +exports.read = () => { if (!input) { throw new Error('jline not installed'); } return String.fromCharCode(input.readVirtualKey()); -} +}; /** * Read a single line from the standard input. @@ -65,13 +79,11 @@ function read() { * @param {String} echoChar character to use as echo, * e.g. '*' for passwords or '' for no echo. */ -function readln(prompt, echoChar) { - prompt = prompt || ''; +exports.readln = (prompt, echoChar) => { + prompt || (prompt = ''); if (input) { - if (typeof echoChar == 'string') { - var echo = echoChar == '' ? - new java.lang.Character(0) : - new java.lang.Character(echoChar.charCodeAt(0)); + if (typeof echoChar === 'string') { + const echo = new Character((echoChar === '') ? 0 : echoChar.charCodeAt(0)); return input.readLine(prompt, echo); } return input.readLine(prompt); @@ -79,7 +91,7 @@ function readln(prompt, echoChar) { system.stdout.write(prompt); return system.stdin.readLine().trim(); } -} +}; /** * Start the shell programmatically. This uses the current thread and thus will not @@ -88,33 +100,23 @@ function readln(prompt, echoChar) { * @since 0.5 * @param {RhinoEngine} engine */ -function start(engine) { +exports.start = (engine) => { engine = engine || require('ringo/engine').getRhinoEngine(); - new org.ringojs.tools.RingoShell(engine).run(); -} + (new org.ringojs.tools.RingoShell(engine)).run(); +}; /** * Quit the shell and exit the JVM. * @param {Number} status optional integer exit status code (default is 0) */ -function quit(status) { +exports.quit = (status) => { java.lang.System.exit(status || 0); -} +}; -var styles = { - 'number': term.BLUE, - 'string': term.GREEN, - 'function': term.CYAN, - 'boolean': term.YELLOW, - 'null': term.BOLD, - 'date': term.MAGENTA, - 'java': term.MAGENTA, - 'custom': term.RED -} - -function convert(value, nesting, visited) { - var type = typeof value; - var retval = {type: type}; +const convert = (value, nesting, visited) => { + const type = typeof value; + let retval = {type: type}; + let count = 0; switch (type) { case 'number': retval.string = String(value); @@ -152,9 +154,8 @@ function convert(value, nesting, visited) { } else { retval.type = "array"; retval.items = []; - var count = 0; - for (var i = 0; i < value.length; i++) { - var part = convert(value[i], nesting + 1, visited); + for (let i = 0; i < value.length; i++) { + let part = convert(value[i], nesting + 1, visited); count += (part.string && part.string.length || part.count || 0) + 2; retval.items.push(part); } @@ -170,9 +171,9 @@ function convert(value, nesting, visited) { retval.string = "{...}"; } else { retval.items = []; - var keys = Object.keys(value); + let keys = Object.keys(value); count = 0; - for (i = 0; i < keys.length; i++) { + for (let i = 0; i < keys.length; i++) { part = convert(value[keys[i]], nesting + 1, visited); count += String(keys[i]).length + 4; count += part.string && part.string.length || part.count || 0; @@ -193,48 +194,50 @@ function convert(value, nesting, visited) { break; } return retval; -} +}; /** * @param {Object} value * @param {Stream} writer */ -function printResult(value, writer) { +exports.printResult = (value, writer) => { if (typeof value !== "undefined") { writer = writer || term; printValue(convert(value, 0, []), writer, 0); writer.writeln(); } -} +}; -function printValue(value, writer, nesting) { +const printValue = (value, writer, nesting) => { if (value.string) { - var style = styles[value.type] || ""; + const style = styles[value.type] || ""; writer.write(style + value.string + term.RESET); } else if (value && value.items) { - var multiline = value.count > 60; - var isArray = value.type === "array"; - var length = value.items.length; + const multiline = value.count > 60; + const isArray = value.type === "array"; + const length = value.items.length; if (length === 0) { writer.write(isArray ? "[]" : "{}"); return; } - var opener = isArray ? "[" : "{"; + const opener = isArray ? "[" : "{"; if (multiline && nesting > 0) { writer.write(opener + "\n "); - for (j = 0; j < nesting; j++) + for (let j = 0; j < nesting; j++) { writer.write(" "); + } } else { writer.write(opener + " "); } if (isArray) { - for (var i = 0; i < length; i++) { + for (let i = 0; i < length; i++) { printValue(value.items[i], writer, nesting + 1); if (i < length - 1) { if (multiline) { writer.write(",\n "); - for (var j = 0; j < nesting; j++) + for (let j = 0; j < nesting; j++) { writer.write(" "); + } } else { writer.write(", "); } @@ -242,14 +245,15 @@ function printValue(value, writer, nesting) { } writer.write(term.RESET + " ]"); } else { - for (i = 0; i < length; i++) { + for (let i = 0; i < length; i++) { writer.write(value.items[i].key); printValue(value.items[i].value, writer, nesting + 1); if (i < length - 1) { if (multiline) { writer.write(",\n "); - for (j = 0; j < nesting; j++) + for (let j = 0; j < nesting; j++) { writer.write(" "); + } } else { writer.write(", "); } @@ -258,22 +262,20 @@ function printValue(value, writer, nesting) { writer.write(term.RESET + " }"); } } -} +}; /** * @param {Exception} xcept * @param {Array} errors * @param {Boolean} verbose */ -function printError(xcept, errors, verbose) { +exports.printError = (xcept, errors, verbose) => { if (xcept instanceof org.mozilla.javascript.RhinoException) { term.writeln(term.BOLD, term.RED, xcept.details()); } else { term.writeln(term.BOLD, term.RED, xcept.toString()); } - for (var i = 0, l = errors.length; i < l; i++) { - term.writeln(term.GREEN, errors[i]); - } + errors.forEach(error => term.writeln(term.GREEN, error)); if (typeof xcept.getScriptStackTrace === "function") { term.write(xcept.getScriptStackTrace()); } @@ -284,13 +286,4 @@ function printError(xcept, errors, verbose) { term.writeln(term.BOLD, "Java Exception:") xcept.printStackTrace(system.stdout.raw || System.out); } -} - -module.exports.write = write; -module.exports.writeln = writeln; -module.exports.read = read; -module.exports.readln = readln; -module.exports.start = start; -module.exports.quit = quit; -module.exports.printResult = printResult; -module.exports.printError = printError; +}; From 24ff785f424bb12ea19247c1915bebab12566862 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 13:08:05 +0100 Subject: [PATCH 25/52] code modernization (ie. var -> const/let) --- modules/ringo/subprocess.js | 99 +++++++++++++++++------------------ test/ringo/subprocess_test.js | 82 ++++++++++++++--------------- 2 files changed, 85 insertions(+), 96 deletions(-) diff --git a/modules/ringo/subprocess.js b/modules/ringo/subprocess.js index d267a9411..ca0c4cf20 100644 --- a/modules/ringo/subprocess.js +++ b/modules/ringo/subprocess.js @@ -6,19 +6,19 @@ * The exact behavior of this module is highly system-dependent. */ -var {Stream, MemoryStream, TextStream} = require('io'); -var fs = require('fs'); -var arrays = require('ringo/utils/arrays'); -var sys = require("system"); +const io = require('io'); +const fs = require('fs'); +const arrays = require('ringo/utils/arrays'); +const system = require("system"); -function parseArguments(args) { +const parseArguments = function(args) { // arguments may end with a {dir: "", env: {}} object - var opts = (args.length > 1 && arrays.peek(args) instanceof Object) ? - Array.pop(args) : {}; + const opts = (args.length > 1 && arrays.peek(args) instanceof Object) ? + Array.prototype.pop.call(args) : {}; // make command either a single string or an array of strings - opts.command = args.length == 1 ? String(args[0]) : Array.prototype.map.call(args, String); + opts.command = (args.length === 1) ? String(args[0]) : Array.prototype.map.call(args, String); return opts; -} +}; /** * Low-level function to spawn a new process. The function takes an object @@ -38,24 +38,24 @@ function parseArguments(args) { * @returns {Process} a Process object * @see #Process */ -var createProcess = exports.createProcess = function(args) { +const createProcess = exports.createProcess = function(args) { // convert arguments - var {command, env, dir, binary, encoding} = args; + let {command, env, dir, binary, encoding} = args; dir = new java.io.File(dir || fs.workingDirectory()); if (env && !Array.isArray(env)) { // convert env to an array of the form ["key=value", ...] - env = [key + "=" + env[key] for (key in env)]; + Object.keys(env).map(key => key + "=" + env[key]); } else if (!env) { env = null; } - var process = java.lang.Runtime.getRuntime().exec(command, env, dir); - var stdin = new Stream(process.getOutputStream()); - var stdout = new Stream(process.getInputStream()); - var stderr = new Stream(process.getErrorStream()); + const process = java.lang.Runtime.getRuntime().exec(command, env, dir); + let stdin = new io.Stream(process.getOutputStream()); + let stdout = new io.Stream(process.getInputStream()); + let stderr = new io.Stream(process.getErrorStream()); if (!binary) { - stdin = new TextStream(stdin, {charset: encoding}); - stdout = new TextStream(stdout, {charset: encoding}); - stderr = new TextStream(stderr, {charset: encoding}); + stdin = new io.TextStream(stdin, {charset: encoding}); + stdout = new io.TextStream(stdout, {charset: encoding}); + stderr = new io.TextStream(stderr, {charset: encoding}); } /** * The Process object can be used to control and obtain information about a @@ -85,17 +85,13 @@ var createProcess = exports.createProcess = function(args) { * @name Process.prototype.wait * @function */ - wait: function() { - return process.waitFor(); - }, + wait: () => process.waitFor(), /** * Kills the subprocess. * @name Process.prototype.kill * @function */ - kill: function() { - process.destroy(); - }, + kill: () => process.destroy(), /** * Connects the process's steams to the argument streams and starts threads to * copy the data asynchronously. @@ -104,7 +100,7 @@ var createProcess = exports.createProcess = function(args) { * @param {Stream} errput input stream to connect to the process's error stream * @name Process.prototype.connect */ - connect: function(input, output, errput) { + connect: (input, output, errput) => { if (input) { spawn(function() { input.copy(stdin); @@ -140,17 +136,17 @@ var createProcess = exports.createProcess = function(args) { * @returns {String} the standard output of the command */ exports.command = function() { - var args = parseArguments(arguments); - var process = createProcess(args); - var output= new MemoryStream(), - errput = new MemoryStream(); + const args = parseArguments(arguments); + const process = createProcess(args); + let output= new io.MemoryStream(); + let errput = new io.MemoryStream(); if (!args.binary) { - output = new TextStream(output, {charset: args.encoding}); - errput = new TextStream(errput, {charset: args.encoding}); + output = new io.TextStream(output, {charset: args.encoding}); + errput = new io.TextStream(errput, {charset: args.encoding}); } process.connect(null, output, errput); - var status = process.wait(); - if (status != 0) { + const status = process.wait(); + if (status !== 0) { throw new Error("(" + status + ") " + errput.content); } return output.content; @@ -169,10 +165,10 @@ exports.command = function() { * @returns {Number} exit status */ exports.system = function() { - var args = parseArguments(arguments); - var process = createProcess(args); - var output = sys.stdout, - errput = sys.stderr; + const args = parseArguments(arguments); + const process = createProcess(args); + let output = system.stdout; + let errput = system.stderr; if (args.binary) { output = output.raw; errput = errput.raw; @@ -193,20 +189,19 @@ exports.system = function() { * @name status */ exports.status = function() { - var process = createProcess(parseArguments(arguments)); - process.connect(null, dummyStream(), dummyStream()); + const process = createProcess(parseArguments(arguments)); + process.connect(null, new DummyStream(), new DummyStream()); return process.wait(); }; -function dummyStream() { - return { - writable: function() true, - readable: function() false, - seekable: function() false, - write: function() this, - flush: function() this, - close: function() this - } -} - - +const DummyStream = function() { + Object.defineProperties(this, { + "writable": {"value": () => true}, + "readable": {"value": () => false}, + "seekable": {"value": () => false}, + "write": {"value": () => this}, + "flush": {"value": () => this}, + "close": {"value": () => this}, + }); + return this; +}; diff --git a/test/ringo/subprocess_test.js b/test/ringo/subprocess_test.js index 3fe107535..4461ab27e 100644 --- a/test/ringo/subprocess_test.js +++ b/test/ringo/subprocess_test.js @@ -1,91 +1,85 @@ -var assert = require("assert"); -var subprocess = require("ringo/subprocess"); +const assert = require("assert"); +const subprocess = require("ringo/subprocess"); -var OS_NAME = java.lang.System.getProperty("os.name").toLowerCase(); -var BASH = (function() { - return ["linux", "mac os", "solaris", "hp-ux"].some(function(candidate) { +const OS_NAME = java.lang.System.getProperty("os.name").toLowerCase(); +const BASH = (() => { + return ["linux", "mac os", "solaris", "hp-ux"].some((candidate) => { return OS_NAME.indexOf(candidate) >= 0; }); })(); -var CMD = (function() { - return OS_NAME.indexOf("windows") >= 0; -})(); +const CMD = (() => OS_NAME.indexOf("windows") >= 0)(); -if (CMD === BASH === true) { +if (CMD === BASH) { throw new Error("Windows and Linux / Unix detected at the same time!"); } -var bashTests = { - testCommand: function() { - var path = subprocess.command("/bin/bash", "-c", "echo $PATH"); +const bashTests = { + testCommand: () => { + const path = subprocess.command("/bin/bash", "-c", "echo $PATH"); assert.isTrue(path.indexOf("/bin") >= 0); }, - testStatus: function() { - var status = subprocess.status("/bin/bash", "-c", "echo $PATH"); - assert.isTrue(status == 0); + testStatus: () => { + const status = subprocess.status("/bin/bash", "-c", "echo $PATH"); + assert.isTrue(status === 0); }, - testSystem: function() { - var oldOut = java.lang.System.out; - var baos = new java.io.ByteArrayOutputStream(1024); - var ps = new java.io.PrintStream(baos); + testSystem: () => { + const oldOut = java.lang.System.out; + const baos = new java.io.ByteArrayOutputStream(1024); + const ps = new java.io.PrintStream(baos); java.lang.System.setOut(ps); - var status = -1; + let status = -1; try { status = subprocess.system("/bin/bash", "-c", "echo $PATH"); } finally { java.lang.System.setOut(oldOut); } - var cs = java.nio.charset.Charset.defaultCharset(); - var path = baos.toString(cs.name()); + const cs = java.nio.charset.Charset.defaultCharset(); + const path = baos.toString(cs.name()); assert.isTrue(path.indexOf("/bin") >= 0); - assert.isTrue(status == 0); + assert.isTrue(status === 0); } }; -var cmdTests = { - testCommand: function() { - var path = subprocess.command("cmd", "/C", "ver"); +const cmdTests = { + testCommand: () => { + const path = subprocess.command("cmd", "/C", "ver"); assert.isTrue(path.indexOf("Microsoft Windows") >= 0); }, - testStatus: function() { - var status = subprocess.status("cmd", "/C", "ver"); - assert.isTrue(status == 0); + testStatus: () => { + const status = subprocess.status("cmd", "/C", "ver"); + assert.isTrue(status === 0); }, - testSystem: function() { - var oldOut = java.lang.System.out; - var baos = new java.io.ByteArrayOutputStream(1024); - var ps = new java.io.PrintStream(baos); + testSystem: () => { + const oldOut = java.lang.System.out; + const baos = new java.io.ByteArrayOutputStream(1024); + const ps = new java.io.PrintStream(baos); java.lang.System.setOut(ps); - var status = -1; + let status = -1; try { status = subprocess.system("cmd", "/C", "ver"); } finally { java.lang.System.setOut(oldOut); } - var cs = java.nio.charset.Charset.defaultCharset(); - var path = baos.toString(cs.name()); + const cs = java.nio.charset.Charset.defaultCharset(); + const path = baos.toString(cs.name()); assert.isTrue(path.indexOf("Microsoft Windows") >= 0); - assert.isTrue(status == 0); + assert.isTrue(status === 0); } }; if (BASH === true) { - for (var testName in bashTests) { - exports[testName] = bashTests[testName]; - } + Object.keys(bashTests).forEach(key => exports[key] = bashTests[key]); } else if (CMD === true) { - for (var testName in cmdTests) { - exports[testName] = cmdTests[testName]; - } + Object.keys(cmdTests).forEach(key => exports[key] = cmdTests[key]); } if (require.main === module) { require('system').exit(require("test").run(module.id)); -} \ No newline at end of file +} From f9d3aa2efb84302d605642c2a6f69a85c0113dc3 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 13:09:07 +0100 Subject: [PATCH 26/52] replaced include() in code example with more explicit require --- modules/ringo/term.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ringo/term.js b/modules/ringo/term.js index ce3f56a8b..37c2fffa8 100644 --- a/modules/ringo/term.js +++ b/modules/ringo/term.js @@ -4,12 +4,12 @@ * and a replacement for the print function optimized for styled output. * * @example - * include('ringo/term') - * writeln(YELLOW, "foo", MAGENTA, "bar"); + * const term = require('ringo/term') + * term.writeln(YELLOW, "foo", MAGENTA, "bar"); * // foo bar - * writeln(YELLOW, ONBLUE, "IKEA"); + * term.writeln(YELLOW, ONBLUE, "IKEA"); * // IKEA - * writeln(RED, BOLD, INVERSE, "Red Alert!"); + * term.writeln(RED, BOLD, INVERSE, "Red Alert!"); * // Red Alert! * * @see http://en.wikipedia.org/wiki/ANSI_escape_code From 9800eb2091df2a124b0b35b242373e7ed1391b15 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 13:30:15 +0100 Subject: [PATCH 27/52] code modernization (ie. var -> const/let), ZipIterator is now a Generator function --- modules/ringo/zip.js | 76 ++++++++++++++++++++++-------------------- test/ringo/zip_test.js | 11 +++--- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/modules/ringo/zip.js b/modules/ringo/zip.js index d9e564e2b..30104331c 100644 --- a/modules/ringo/zip.js +++ b/modules/ringo/zip.js @@ -3,31 +3,32 @@ * @since 0.5 */ -var fs = require('fs'); -var {Stream} = require('io'); +const fs = require('fs'); +const io = require('io'); +const {ZipFile, ZipInputStream} = java.util.zip; /** * A class to read and unpack a local zip file. * @param {String} path the location of the zip file */ -module.exports.ZipFile = function ZipFile(path) { - var zipfile = new java.util.zip.ZipFile(path); - var entries = []; - var map = {}; - var e = zipfile.entries(); - while (e.hasMoreElements()) { - var entry = e.nextElement(); +exports.ZipFile = function(path) { + const zipfile = new ZipFile(path); + const entries = []; + const map = {}; + const enumerator = zipfile.entries(); + while (enumerator.hasMoreElements()) { + let entry = enumerator.nextElement(); map[entry.name] = entry; entries.push(entry.name); } - function getEntry(name) { - var entry = map[name]; + const getEntry = (name) => { + const entry = map[name]; if (!entry) { throw new Error("Invalid zip entry: " + name); } return entry; - } + }; /** * An array containing the names of all entries in this zip file. @@ -39,16 +40,16 @@ module.exports.ZipFile = function ZipFile(path) { * Get an input stream to read the entry with the given name. * @param {String} name the entry name */ - this.open = function(name) { - return new Stream(zipfile.getInputStream(getEntry(name))); + this.open = (name) => { + return new io.Stream(zipfile.getInputStream(getEntry(name))); }; /** * Returns true if the entry with the given name represents a directory. * @param {String} name the entry name */ - this.isDirectory = function(name) { - var entry = map[name]; + this.isDirectory = (name) => { + const entry = map[name]; return entry && entry.isDirectory(); }; @@ -56,8 +57,8 @@ module.exports.ZipFile = function ZipFile(path) { * Returns true if the entry with the given name represents a file. * @param {String} name the entry name */ - this.isFile = function(name) { - var entry = map[name]; + this.isFile = (name) => { + const entry = map[name]; return entry && !entry.isDirectory(); }; @@ -65,7 +66,7 @@ module.exports.ZipFile = function ZipFile(path) { * Returns the uncompressed size in bytes in the given entry, or -1 if not known. * @param {String} name the entry name */ - this.getSize = function(name) { + this.getSize = (name) => { return getEntry(name).getSize(); }; @@ -73,17 +74,19 @@ module.exports.ZipFile = function ZipFile(path) { * Returns the last modification timestamp of the given entry, or -1 if not available. * @param {String} name the entry name */ - this.getTime = function(name) { + this.getTime = (name) => { return getEntry(name).getTime(); }; /** * Close the zip file. */ - this.close = function() { + this.close = () => { zipfile.close(); }; -} + + return this; +}; /** * A streaming iterator over a zip file or stream. Each item yielded @@ -93,23 +96,22 @@ module.exports.ZipFile = function ZipFile(path) { * @param {Stream|String} resource an input stream or file name * @see #ZipFile */ -module.exports.ZipIterator = function ZipIterator(resource) { - var stream = typeof resource == "string" ? - fs.openRaw(resource) : resource; - var zipstream = new java.util.zip.ZipInputStream(stream); - stream = new Stream(zipstream); +module.exports.ZipIterator = function*(resource) { + const zipStream = new ZipInputStream((typeof resource == "string") ? + fs.openRaw(resource) : resource); + const stream = new io.Stream(zipStream); try { - var entry = zipstream.getNextEntry(); - while (entry) { - stream.name = entry.getName(); - stream.isDirectory = entry.isDirectory(); - stream.isFile = !stream.isDirectory; - stream.size = entry.getSize(); - stream.time = entry.getTime(); - yield stream; - entry = zipstream.getNextEntry(); + let entry; + while ((entry = zipStream.getNextEntry())) { + yield { + "name": entry.getName(), + "isDirectory": entry.isDirectory(), + "isFile": !entry.isDirectory(), + "size": entry.getSize(), + "time": entry.getTime() + }; } } finally { stream.close(); } -} +}; diff --git a/test/ringo/zip_test.js b/test/ringo/zip_test.js index 10d163afa..00acb8f66 100644 --- a/test/ringo/zip_test.js +++ b/test/ringo/zip_test.js @@ -17,18 +17,15 @@ exports.testZipIterator = function () { "05-folder/06-another-helloworld.txt", ]; - const result = []; try { - result.push(zipIterator.next().name); - result.push(zipIterator.next().name); - result.push(zipIterator.next().name); - result.push(zipIterator.next().name); - result.push(zipIterator.next().name); + const result = expectedResult.map(() => { + return zipIterator.next().value.name; + }); + assert.deepEqual(result, expectedResult); } catch (e) { assert.fail("Could not iterate over the zip file entries: " + e); } - assert.deepEqual(result.sort(), expectedResult); }; if (require.main === module) { From 917985144487e9d4b871289a647a0315de98f097 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 13:30:28 +0100 Subject: [PATCH 28/52] added missing tests --- test/all.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/all.js b/test/all.js index e4b0b9409..cc7bdf79f 100644 --- a/test/all.js +++ b/test/all.js @@ -12,7 +12,9 @@ exports.testJsgi = require('./ringo/jsgi/all'); exports.testNet = require('./net_test'); exports.testPromise = require('./ringo/promise_test'); exports.testScheduler = require('./ringo/scheduler_test'); +exports.testSubProcess = require('./ringo/subprocess_test'); exports.testWebSocket = require('./ringo/websocket_test'); +exports.testZip = require('./ringo/zip_test'); exports.testUtils = require('./ringo/utils/all'); exports.testFile = require('./file/all'); exports.testBinary = require('./binary/all'); From a278580f9689ab430490637ebafae5c4a4357ad4 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 13:57:39 +0100 Subject: [PATCH 29/52] code modernization (ie. var -> const/let) --- modules/ringo/jsgi/connector.js | 115 ++++++++++++------------- test/ringo/jsgi/all.js | 6 +- test/ringo/jsgi/asyncresponse_test.js | 26 +++--- test/ringo/jsgi/response_range_test.js | 15 ++-- test/ringo/jsgi/response_test.js | 114 ++++++++++++------------ 5 files changed, 130 insertions(+), 146 deletions(-) diff --git a/modules/ringo/jsgi/connector.js b/modules/ringo/jsgi/connector.js index a5e512a4a..43761b1a3 100644 --- a/modules/ringo/jsgi/connector.js +++ b/modules/ringo/jsgi/connector.js @@ -2,17 +2,16 @@ * @fileOverview Low-level JSGI adapter implementation. */ -var {Headers, getMimeParameter} = require('ringo/utils/http'); -var {Stream} = require('io'); -var {Binary} = require('binary'); -var system = require('system'); -var strings = require('ringo/utils/strings'); -var {WriteListener, AsyncListener} = javax.servlet; -var {ConcurrentLinkedQueue} = java.util.concurrent; -var {EofException} = org.eclipse.jetty.io; -var {AtomicBoolean} = java.util.concurrent.atomic; +const {Headers, getMimeParameter} = require('ringo/utils/http'); +const io = require('io'); +const binary = require('binary'); +const system = require('system'); +const {WriteListener, AsyncListener} = javax.servlet; +const {ConcurrentLinkedQueue} = java.util.concurrent; +const {EofException} = org.eclipse.jetty.io; +const {AtomicBoolean} = java.util.concurrent.atomic; -var log = require('ringo/logging').getLogger(module.id); +const log = require('ringo/logging').getLogger(module.id); const FLUSH = new ByteArray(0); @@ -24,9 +23,9 @@ const FLUSH = new ByteArray(0); * @param {Object} request the JSGI request object * @returns {Object} the JSGI response object */ -const handleRequest = exports.handleRequest = function handleRequest(moduleId, functionObj, request) { +const handleRequest = exports.handleRequest = (moduleId, functionObj, request) => { initRequest(request); - var app; + let app; if (typeof(functionObj) === 'function') { app = functionObj; } else { @@ -44,31 +43,32 @@ const handleRequest = exports.handleRequest = function handleRequest(moduleId, f if (typeof(app) !== 'function') { throw new Error('No valid JSGI app: ' + app); } - var result = app(request); + const result = app(request); if (!result) { throw new Error('No valid JSGI response: ' + result); } commitResponse(request, result); -} +}; /** * Set up the I/O related properties of a jsgi environment object. * @param {Object} request a jsgi request object */ -function initRequest(request) { - var input, errors; +const initRequest = (request) => { + let input; if (request.hasOwnProperty('input')) { // already set up, probably because the original request threw a retry return; } Object.defineProperty(request, "input", { - get: function() { - if (!input) - input = new Stream(request.env.servletRequest.getInputStream()); + get: () => { + if (!input) { + input = new io.Stream(request.env.servletRequest.getInputStream()); + } return input; }, - set: function(stream) { - if (!stream instanceof Stream) { + set: (stream) => { + if (!stream instanceof io.Stream) { throw new Error("Input must be a Stream!"); } input = stream; @@ -78,7 +78,7 @@ function initRequest(request) { Object.defineProperty(request.jsgi, "errors", { value: system.stderr }); -} +}; /** * Apply the return value of a JSGI application to a servlet response. @@ -89,13 +89,13 @@ function initRequest(request) { * @param {Object} req the JSGI request argument * @param {Object} result the object returned by a JSGI application */ -function commitResponse(req, result) { - var request = req.env.servletRequest; +const commitResponse = (req, result) => { + const request = req.env.servletRequest; if (typeof request.isAsyncStarted === "function" && request.isAsyncStarted()) { return; } - var response = req.env.servletResponse; - var {status, headers, body} = result; + const response = req.env.servletResponse; + const {status, headers, body} = result; if (!status || !headers || !body) { // Check if this is an asynchronous response. If not throw an Error throw new Error('No valid JSGI response: ' + result); @@ -104,41 +104,38 @@ function commitResponse(req, result) { if (!response.isCommitted() && !Headers(headers).contains("X-JSGI-Skip-Response")) { writeResponse(response, status, headers, body); } -} +}; -function writeResponse(servletResponse, status, headers, body) { +const writeResponse = (servletResponse, status, headers, body) => { servletResponse.setStatus(status); writeHeaders(servletResponse, headers); - var charset = getMimeParameter(headers.get("Content-Type"), "charset"); + const charset = getMimeParameter(headers.get("Content-Type"), "charset"); writeBody(servletResponse, body, charset); -} +}; -function writeHeaders(servletResponse, headers) { - for (var key in headers) { - var values = headers[key]; +const writeHeaders = (servletResponse, headers) => { + Object.keys(headers).forEach(key => { + let values = headers[key]; if (typeof values === "string") { values = values.split("\n"); - } else if (!Array.isArray(values)) { - continue; } - values.forEach(function(value) { - servletResponse.addHeader(key, value); - }); - } -} + if (Array.isArray(values)) { + values.forEach((value) => servletResponse.addHeader(key, value)); + } + }); +}; -function writeBody(response, body, charset) { +const writeBody = (response, body, charset) => { if (body && typeof body.forEach == "function") { - var output = response.getOutputStream(); - var writer = function(part) { - if (!(part instanceof Binary)) { + const output = response.getOutputStream(); + body.forEach(part => { + if (!(part instanceof binary.Binary)) { part = part.toByteString(charset); } output.write(part); - }; - body.forEach(writer); + }); if (typeof body.close == "function") { - body.close(writer); + body.close(); } } else { throw new Error("Response body doesn't implement forEach: " + body); @@ -188,12 +185,12 @@ function writeBody(response, body, charset) { * * return response; */ -const AsyncResponse = exports.AsyncResponse = function AsyncResponse(request, timeout) { +exports.AsyncResponse = function(request, timeout) { if (!request || !request.env) { throw new Error("Invalid request argument: " + request); } - var {servletRequest, servletResponse} = request.env; - var asyncContext = servletRequest.startAsync(); + const {servletRequest, servletResponse} = request.env; + const asyncContext = servletRequest.startAsync(); if (timeout != null && isFinite(timeout)) { asyncContext.setTimeout(timeout); } @@ -213,30 +210,30 @@ const AsyncResponse = exports.AsyncResponse = function AsyncResponse(request, ti } })); - var out = servletResponse.getOutputStream(); - var writeListener = new WriteListenerImpl(asyncContext); + const out = servletResponse.getOutputStream(); + const writeListener = new WriteListenerImpl(asyncContext); out.setWriteListener(writeListener); return { - "start": function(status, headers) { + "start": (status, headers) => { servletResponse.setStatus(status); writeHeaders(servletResponse, headers || {}); return this; }, - "write": function(data, encoding) { + "write": (data, encoding) => { if (asyncContext.getHttpChannelState().isResponseCompleted()) { throw new Error("AsyncResponse already closed"); } - if (!(data instanceof Binary)) { + if (!(data instanceof binary.Binary)) { data = String(data).toByteArray(encoding); } writeListener.queue.add(data); writeListener.onWritePossible(); return this; }, - "flush": function() { + "flush": () => { this.write(FLUSH); }, - "close": function() { + "close": () => { if (asyncContext.getHttpChannelState().isResponseCompleted()) { throw new Error("AsyncResponse already closed"); } @@ -252,7 +249,7 @@ const AsyncResponse = exports.AsyncResponse = function AsyncResponse(request, ti * @returns {javax.servlet.WriteListener} * @constructor */ -var WriteListenerImpl = function(asyncContext) { +const WriteListenerImpl = function(asyncContext) { this.isReady = new AtomicBoolean(true); this.isFinished = false; this.queue = new ConcurrentLinkedQueue(); @@ -265,7 +262,7 @@ var WriteListenerImpl = function(asyncContext) { * the internal queue and writes them to the response's output stream. */ WriteListenerImpl.prototype.onWritePossible = function() { - var outStream = this.asyncContext.getResponse().getOutputStream(); + const outStream = this.asyncContext.getResponse().getOutputStream(); if (this.isReady.compareAndSet(true, false)) { // Note: .isReady() schedules a call for onWritePossible // if it returns false diff --git a/test/ringo/jsgi/all.js b/test/ringo/jsgi/all.js index a105c993e..272fe4fe9 100644 --- a/test/ringo/jsgi/all.js +++ b/test/ringo/jsgi/all.js @@ -1,6 +1,6 @@ -exports.testAsyncResponse = require('./asyncresponse_test'); -exports.testResponse = require('./response_test'); -exports.testResponseRange = require('./response_range_test'); +exports.testAsyncResponse = require('./asyncresponse_test'); +exports.testResponse = require('./response_test'); +exports.testResponseRange = require('./response_range_test'); if (require.main === module) { require("system").exit(require("test").run(exports)); diff --git a/test/ringo/jsgi/asyncresponse_test.js b/test/ringo/jsgi/asyncresponse_test.js index 1d5e5d141..f3236954c 100644 --- a/test/ringo/jsgi/asyncresponse_test.js +++ b/test/ringo/jsgi/asyncresponse_test.js @@ -1,14 +1,12 @@ -var assert = require("assert"); -var {AsyncResponse} = require("ringo/jsgi/connector"); -var {HttpServer} = require("ringo/httpserver"); -var httpClient = require("ringo/httpclient"); -var strings = require("ringo/utils/strings"); - require('ringo/logging').setConfig(getResource('../httptest_log4j2.properties')); -var server = null; -exports.setUp = function() { -}; +const assert = require("assert"); +const {AsyncResponse} = require("ringo/jsgi/connector"); +const {HttpServer} = require("ringo/httpserver"); +const httpClient = require("ringo/httpclient"); +const strings = require("ringo/utils/strings"); + +let server = null; exports.tearDown = function() { server.stop(); @@ -16,15 +14,15 @@ exports.tearDown = function() { server = null; }; -exports.testAsync = function() { - var line = "test\n"; +exports.testAsync = () => { + const line = "test\n"; server = new HttpServer(); server.serveApplication("/", function(request) { - var response = new AsyncResponse(request, 2000); + const response = new AsyncResponse(request, 2000); response.start(200, {"Content-Type": "text/plain"}); spawn(function() { - var max = 5; + const max = 5; for (let cnt = 0; cnt < max; cnt += 1) { try { response.write(line); @@ -43,7 +41,7 @@ exports.testAsync = function() { }); server.start(); - var exchange = httpClient.get("http://localhost:8282"); + const exchange = httpClient.get("http://localhost:8282"); assert.strictEqual(exchange.status, 200); assert.strictEqual(exchange.content, strings.repeat(line, 5)); }; diff --git a/test/ringo/jsgi/response_range_test.js b/test/ringo/jsgi/response_range_test.js index 0eaf0f95e..025a51cf9 100644 --- a/test/ringo/jsgi/response_range_test.js +++ b/test/ringo/jsgi/response_range_test.js @@ -1,17 +1,14 @@ +require("ringo/logging").setConfig(getResource("../httptest_log4j2.properties")); + const assert = require("assert"); const {MemoryStream} = require("io"); const {HttpServer} = require("ringo/httpserver"); const httpClient = require("ringo/httpclient"); -const strings = require("ringo/utils/strings"); const response = require("ringo/jsgi/response"); const DATA = new ByteString("Hello World! I am a string. A long string.", "ASCII"); -require("ringo/logging").setConfig(getResource("../httptest_log4j2.properties")); -var server = null; - -exports.setUp = function() { -}; +let server = null; exports.tearDown = function() { server.stop(); @@ -73,8 +70,7 @@ exports.testSimpleRange = function() { exports.testCombinedRequests = function() { server = new HttpServer(); server.serveApplication("/", function(request) { - const res = response.range(request, new MemoryStream(DATA.concat(DATA, DATA, DATA)), 4 * DATA.length, "text/plain"); - return res; + return response.range(request, new MemoryStream(DATA.concat(DATA, DATA, DATA)), 4 * DATA.length, "text/plain"); }); server.createHttpListener({ "host": "localhost", @@ -130,8 +126,7 @@ exports.testCombinedRequests = function() { exports.testInvalidRanges = function() { server = new HttpServer(); server.serveApplication("/", function(request) { - const res = response.range(request, new MemoryStream(DATA), DATA.length, "text/plain"); - return res; + return response.range(request, new MemoryStream(DATA), DATA.length, "text/plain"); }); server.createHttpListener({ "host": "localhost", diff --git a/test/ringo/jsgi/response_test.js b/test/ringo/jsgi/response_test.js index 175d2f468..ea30ad7f4 100644 --- a/test/ringo/jsgi/response_test.js +++ b/test/ringo/jsgi/response_test.js @@ -1,15 +1,13 @@ -var io = require("io"); -var binary = require("binary"); -var assert = require("assert"); +const io = require("io"); +const binary = require("binary"); +const assert = require("assert"); -var {JsgiResponse} = require("ringo/jsgi/response"); +const {JsgiResponse} = require("ringo/jsgi/response"); -exports.setUp = exports.tearDown = function() {} +exports.testHttpStatus = () => { + const res = new JsgiResponse(); -exports.testHttpStatus = function () { - var res = new JsgiResponse(); - - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "text/plain; charset=utf-8" }, body: [""] @@ -74,10 +72,10 @@ exports.testHttpStatus = function () { assert.deepEqual(res, expected); }; -exports.testText = function () { - var res = new JsgiResponse(); +exports.testText = () => { + const res = new JsgiResponse(); - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "text/plain; charset=utf-8" }, body: ["Hello World!", "1234"] @@ -86,10 +84,10 @@ exports.testText = function () { assert.deepEqual(res.text("Hello World!", 1234), expected); }; -exports.testHtml = function () { - var res = new JsgiResponse(); +exports.testHtml = () => { + const res = new JsgiResponse(); - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "text/html; charset=utf-8" }, body: ["", "

    Hello World!

    ", "1234", ""] @@ -98,10 +96,10 @@ exports.testHtml = function () { assert.deepEqual(res.html("", "

    Hello World!

    ", 1234, ""), expected); }; -exports.testJson = function () { - var res = new JsgiResponse(); +exports.testJson = () => { + const res = new JsgiResponse(); - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "application/json; charset=utf-8" }, body: ["{\"foo\":\"bar\"}"] @@ -110,10 +108,10 @@ exports.testJson = function () { assert.deepEqual(res.json({foo: "bar"}), expected); }; -exports.testJsonp = function () { - var res = new JsgiResponse(); +exports.testJsonp = () => { + const res = new JsgiResponse(); - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "application/javascript; charset=utf-8" }, body: ["doSomething", "(", "{\"foo\":\"bar\"}",");"] @@ -122,10 +120,10 @@ exports.testJsonp = function () { assert.deepEqual(res.jsonp("doSomething", {foo: "bar"}), expected); }; -exports.testXml = function () { - var res = new JsgiResponse(); +exports.testXml = () => { + const res = new JsgiResponse(); - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "application/xml" }, body: ["this is xml"] @@ -135,17 +133,15 @@ exports.testXml = function () { assert.deepEqual(res.xml(new XML("this is xml")), expected); }; -exports.testStream = function () { - var source = [0, 1, 2, 3, 4, 5, 6, 7]; - var stream = new io.MemoryStream(new binary.ByteArray(source)); - var res = new JsgiResponse().stream(stream); - var readStream = function(body) { - var input = new io.MemoryStream(); - body.forEach(function(buffer) { - input.write(buffer); - }); +exports.testStream = () => { + const source = [0, 1, 2, 3, 4, 5, 6, 7]; + const readStream = (body) => { + const input = new io.MemoryStream(); + body.forEach(buffer => input.write(buffer)); return input.content.toArray(); }; + let stream = new io.MemoryStream(new binary.ByteArray(source)); + let res = new JsgiResponse().stream(stream); assert.equal(res.status, 200); assert.deepEqual(res.headers, { "content-type": "application/octet-stream" }); @@ -159,13 +155,13 @@ exports.testStream = function () { assert.deepEqual(readStream(res.body), source); }; -exports.testBinary = function () { - var res = new JsgiResponse().binary(new binary.ByteArray([0, 1, 2, 3, 4, 5, 6, 7])); +exports.testBinary = () => { + let res = new JsgiResponse().binary(new binary.ByteArray([0, 1, 2, 3, 4, 5, 6, 7])); assert.equal(res.status, 200); assert.deepEqual(res.headers, { "content-type": "application/octet-stream" }); assert.strictEqual(typeof res.body.forEach, "function"); - var arr = []; - res.body.forEach(function (ba) { + let arr = []; + res.body.forEach((ba) => { arr = arr.concat(ba.toArray()); }); assert.deepEqual(arr, [0, 1, 2, 3, 4, 5, 6, 7]); @@ -175,7 +171,7 @@ exports.testBinary = function () { assert.deepEqual(res.headers, { "content-type": "application/pdf" }); assert.strictEqual(typeof res.body.forEach, "function"); arr = []; - res.body.forEach(function (ba) { + res.body.forEach(ba => { arr = arr.concat(ba.toArray()); }); assert.deepEqual(arr, [0, 1, 2, 3, 4, 5, 6, 7]); @@ -188,20 +184,20 @@ exports.testBinary = function () { assert.deepEqual(res.headers, { "content-type": "application/asciistuff" }); assert.strictEqual(typeof res.body.forEach, "function"); arr = []; - res.body.forEach(function (ba) { + res.body.forEach(ba => { arr = arr.concat(ba.toArray()); }); assert.deepEqual(arr, [13,10]); - assert.throws(function() { + assert.throws(() => { new JsgiResponse().binary("i am not a binary object"); }, Error); }; -exports.testSetCharset = function () { - var res = new JsgiResponse(); +exports.testSetCharset = () => { + const res = new JsgiResponse(); - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "text/plain; charset=ISO-8859-1" }, body: ["Use ISO-8859-1"] @@ -211,10 +207,10 @@ exports.testSetCharset = function () { }; -exports.testAddHeaders = function () { - var res = new JsgiResponse(); +exports.testAddHeaders = () => { + let res = new JsgiResponse(); - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "text/plain; charset=utf-8", @@ -238,7 +234,7 @@ exports.testAddHeaders = function () { assert.isTrue(res.headers.foo.indexOf("bar") >= 0); assert.isTrue(res.headers.foo.indexOf("baz") >= 0); assert.isTrue(res.headers.foo.indexOf("12345") >= 0); - assert.isTrue(res.headers.foo.every(function(val) { + assert.isTrue(res.headers.foo.every(val => { return typeof val === "string"; })); @@ -253,7 +249,7 @@ exports.testAddHeaders = function () { assert.isTrue(res.headers.foo.indexOf("bar") >= 0); assert.isTrue(res.headers.foo.indexOf("baz") >= 0); assert.isTrue(res.headers.foo.indexOf("12345") >= 0); - assert.isTrue(res.headers.foo.every(function(val) { + assert.isTrue(res.headers.foo.every(val => { return typeof val === "string"; })); @@ -269,10 +265,10 @@ exports.testAddHeaders = function () { assert.isTrue(typeof res.headers.Foo === "string"); }; -exports.testSetHeaders = function () { - var res = new JsgiResponse(); +exports.testSetHeaders = () => { + let res = new JsgiResponse(); - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "text/plain; charset=utf-8", @@ -306,9 +302,7 @@ exports.testSetHeaders = function () { assert.isTrue(res.headers.foo.indexOf("bar") >= 0); assert.isTrue(res.headers.foo.indexOf("baz") >= 0); assert.isTrue(res.headers.foo.indexOf("12345") >= 0); - assert.isTrue(res.headers.foo.every(function(val) { - return typeof val === "string"; - })); + assert.isTrue(res.headers.foo.every(val => typeof val === "string")); res.setHeaders({ foo: ["moo", "maa", 67890] }); assert.deepEqual(res.headers, { @@ -328,10 +322,10 @@ exports.testSetHeaders = function () { assert.isTrue(typeof res.headers.Foo === "string"); }; -exports.testSetContentType = function () { - var res = new JsgiResponse(); +exports.testSetContentType = () => { + let res = new JsgiResponse(); - var expected = new JsgiResponse({ + const expected = new JsgiResponse({ status: 200, headers: { "content-type": "foo/bar; charset=utf-16" @@ -355,10 +349,10 @@ exports.testSetContentType = function () { }); }; -exports.testHelpers = function() { - var response = require("ringo/jsgi/response"); +exports.testHelpers = () => { + const response = require("ringo/jsgi/response"); - var expected = new JsgiResponse({ + let expected = new JsgiResponse({ status: 123, headers: { "content-type": "text/plain; charset=utf-8" }, body: ["Hello World!"] From 09184bc70065f40eabf4060adf85b8b2a21067d0 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 14:00:43 +0100 Subject: [PATCH 30/52] code modernization (ie. var -> const/let) --- modules/ringo/jsgi/eventsource.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/modules/ringo/jsgi/eventsource.js b/modules/ringo/jsgi/eventsource.js index d9429e3b9..469d92158 100644 --- a/modules/ringo/jsgi/eventsource.js +++ b/modules/ringo/jsgi/eventsource.js @@ -2,8 +2,8 @@ * @fileOverview This module provides the constructor for EventSource * response objects, which allow pushing messages to connected clients. */ -var {AsyncResponse} = require('ringo/jsgi/connector'); -var objects = require('ringo/utils/objects'); +const {AsyncResponse} = require('ringo/jsgi/connector'); +const objects = require('ringo/utils/objects'); const CRLF = "\r\n".toByteArray('utf-8'); const EVENT_FIELD = "event: ".toByteArray('utf-8'); @@ -24,7 +24,7 @@ const COMMENT_FIELD = ": ".toByteArray('utf-8'); * * @example * - * var eventSource = new EventSource(request); + * const eventSource = new EventSource(request); * // send headers and start heartbeat * eventSource.start({ * "X-Additional-Header": "Foo" @@ -48,7 +48,7 @@ const COMMENT_FIELD = ": ".toByteArray('utf-8'); * */ exports.EventSource = function(request) { - var heartBeat = null; + let heartBeat = null; this.response = null; /** @@ -58,7 +58,9 @@ exports.EventSource = function(request) { * @throws {Error} */ this.event = sync(function(name, data) { - if (this.response === null) throw new Error('Connection not open'); + if (this.response === null) { + throw new Error('Connection not open'); + } this.response.write(EVENT_FIELD); this.response.write(name); @@ -72,7 +74,9 @@ exports.EventSource = function(request) { * @throws {Error} */ this.data = sync(function(data) { - if (this.response === null) throw new Error('Connection not open'); + if (this.response === null) { + throw new Error('Connection not open'); + } this.response.write(DATA_FIELD); this.response.write(data); @@ -87,7 +91,9 @@ exports.EventSource = function(request) { * @throws {Error} */ this.comment = sync(function(comment) { - if (this.response === null) throw new Error('Connection not open'); + if (this.response === null) { + throw new Error('Connection not open'); + } this.response.write(COMMENT_FIELD); this.response.write(comment); @@ -111,7 +117,9 @@ exports.EventSource = function(request) { * @param {Number} heartBeatInterval in seconds (optional. default: 15) */ this.start = function(headers, heartBeatInterval) { - if (this.response !== null) throw new Error('Connection already open'); + if (this.response !== null) { + throw new Error('Connection already open'); + } if (heartBeatInterval === undefined || isNaN(heartBeatInterval)) { heartBeatInterval = 15; @@ -149,6 +157,6 @@ exports.EventSource = function(request) { * @param {JSGIRequest} request * @returns {Boolean} whether the accept header matches 'text/event-stream */ -exports.isEventSourceRequest = function(request) { +exports.isEventSourceRequest = (request) => { return request.headers.accept.indexOf('text/event-stream') > -1; }; From 1f47930a308100d62a5a5b42f46d4485fefcdc1f Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 14:08:09 +0100 Subject: [PATCH 31/52] code modernization (ie. var -> const/let) --- modules/ringo/jsgi/response.js | 40 ++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/modules/ringo/jsgi/response.js b/modules/ringo/jsgi/response.js index 0e816c733..9200db955 100644 --- a/modules/ringo/jsgi/response.js +++ b/modules/ringo/jsgi/response.js @@ -4,10 +4,10 @@ */ const fs = require("fs"); -var {parseRange, canonicalRanges} = require("ringo/utils/http"); -var {mimeType} = require("ringo/mime"); -var {Stream, MemoryStream} = require("io"); -var {AsyncResponse} = require("./connector"); +const {parseRange, canonicalRanges} = require("ringo/utils/http"); +const {mimeType} = require("ringo/mime"); +const io = require("io"); +const {AsyncResponse} = require("./connector"); const HYPHEN = new ByteString("-", "ASCII"); const CRLF = new ByteString("\r\n", "ASCII"); @@ -20,19 +20,19 @@ const EMPTY_LINE = new ByteString("\r\n\r\n", "ASCII"); * body properties. * @constructor * @example // Using the constructor - * var {JsgiResponse} = require('ringo/jsgi/response'); + * const {JsgiResponse} = require('ringo/jsgi/response'); * return (new JsgiResponse()).text('Hello World!').setCharset('ISO-8859-1'); * * // Using a static helper - * var response = require('ringo/jsgi/response'); + * const response = require('ringo/jsgi/response'); * return response.json({'foo': 'bar'}).error(); */ -var JsgiResponse = exports.JsgiResponse = function(base) { +const JsgiResponse = exports.JsgiResponse = function(base) { // Internal use only /** @ignore */ Object.defineProperty(this, "_charset", { value: "utf-8", - writable: true, + writable: true }); this.status = 200; @@ -123,7 +123,7 @@ Object.defineProperty(JsgiResponse.prototype, "jsonp", { Object.defineProperty(JsgiResponse.prototype, "xml", { value: function(xml) { this.headers["content-type"] = "application/xml"; - this.body = [(typeof xml === 'xml' ? xml.toXMLString() : String(xml))]; + this.body = [(typeof xml === 'xml') ? xml.toXMLString() : String(xml)]; return this; } }); @@ -192,7 +192,7 @@ Object.defineProperty(JsgiResponse.prototype, "binary", { Object.defineProperty(JsgiResponse.prototype, "setCharset", { value: function(charsetName) { this._charset = charsetName; - var ct = this.headers["content-type"]; + const ct = this.headers["content-type"]; if (ct) { this.headers["content-type"] = ct.substring(0, ct.indexOf("; charset=")) + "; charset=" + this._charset; @@ -586,7 +586,6 @@ exports.static = function (resource, contentType) { throw Error("Wrong argument for static response: " + typeof(resource)); } - var input; return { status: 200, headers: { @@ -598,7 +597,7 @@ exports.static = function (resource, contentType) { + resource.length.toString(36); }, forEach: function(fn) { - input = new Stream(resource.getInputStream()); + const input = new io.Stream(resource.getInputStream()); try { input.forEach(fn); } finally { @@ -652,11 +651,11 @@ exports.range = function (request, representation, size, contentType, timeout, m stream = fs.openRaw(localPath, "r"); } else if (representation instanceof org.ringojs.repository.Resource) { - stream = new Stream(representation.getInputStream()); + stream = new io.Stream(representation.getInputStream()); if (size == null && representation.getLength != null) { size = representation.getLength(); } - } else if (representation instanceof Stream) { + } else if (representation instanceof io.Stream) { stream = representation; } else { throw new Error("Invalid representation! Must be a path to a file, a resource, or a stream."); @@ -697,7 +696,7 @@ exports.range = function (request, representation, size, contentType, timeout, m } // check if range can be fulfilled - if(size != null && ranges[ranges.length - 1][1] > size) { + if (size != null && ranges[ranges.length - 1][1] > size) { return new JsgiResponse().setStatus(416).addHeaders({ "content-range": "bytes */" + size }).text("Range Not Satisfiable"); @@ -727,7 +726,7 @@ exports.range = function (request, representation, size, contentType, timeout, m stream.skip(start - currentBytePos); if (arr.length > 1) { - const boundary = new MemoryStream(70); + const boundary = new io.MemoryStream(70); if (index > 0) { boundary.write(CRLF); } @@ -754,7 +753,7 @@ exports.range = function (request, representation, size, contentType, timeout, m if (arr.length > 1 && index === arr.length - 1) { // final boundary - const eofBoundary = new MemoryStream(70); + const eofBoundary = new io.MemoryStream(70); eofBoundary.write(CRLF); eofBoundary.write(HYPHEN); eofBoundary.write(HYPHEN); @@ -771,7 +770,10 @@ exports.range = function (request, representation, size, contentType, timeout, m // commit response servletResponse.flushBuffer(); - } catch (e if e.javaException instanceof org.eclipse.jetty.io.EofException) { + } catch (e) { + if (!(e.javaException instanceof org.eclipse.jetty.io.EofException)) { + throw e; + } // no problem, remote client closed connection ... } @@ -782,4 +784,4 @@ exports.range = function (request, representation, size, contentType, timeout, m }, body: {} }; -}; \ No newline at end of file +}; From 1e92bbe80c634416251012db2da229170586717b Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 15:57:49 +0100 Subject: [PATCH 32/52] code modernization (ie. var -> const/let) removed partition() method - this method was obviously broken and not covered by tests, so i assume it's obsolete --- modules/ringo/utils/arrays.js | 87 ++++++++++++--------------------- test/ringo/utils/arrays_test.js | 61 +++++++++-------------- 2 files changed, 53 insertions(+), 95 deletions(-) diff --git a/modules/ringo/utils/arrays.js b/modules/ringo/utils/arrays.js index 54c831066..9dc9f0b53 100644 --- a/modules/ringo/utils/arrays.js +++ b/modules/ringo/utils/arrays.js @@ -26,9 +26,9 @@ * @param {Object} val the value to check * @returns {Boolean} true if the value is contained */ -function contains(array, val) { - return array.indexOf(val) > -1; -} +const contains = exports.contains = (array, val) => { + return array.indexOf(val) > -1; +}; /** * Return the last element of the array. This is like pop(), but @@ -36,9 +36,9 @@ function contains(array, val) { * @param {Array} array the array * @returns {Object} the last element of the array, or undefined if the array is empty. */ -function peek(array) { +exports.peek = (array) => { return array[array.length - 1]; -} +}; /** * Remove the first occurrence of the argument value from the array. This method @@ -48,25 +48,25 @@ function peek(array) { * @param {Object} val the value to remove * @returns {Array} the array */ -function remove(array, val) { - var index = array.indexOf(val); +exports.remove = (array, val) => { + const index = array.indexOf(val); if(index > -1) { array.splice(index, 1); } return array; -} +}; /** * Retrieve the union set of a bunch of arrays. * @param {Array} array1,... the arrays to unify * @returns {Array} the union set */ -function union() { - var result = []; - var map = new java.util.HashMap(); - for (var i = 0; i < arguments.length; i += 1) { - for (var n in arguments[i]) { - var item = arguments[i][n]; +const union = exports.union = function() { + const result = []; + const map = new java.util.HashMap(); + for (let i = 0; i < arguments.length; i += 1) { + for (let n in arguments[i]) { + let item = arguments[i][n]; if (!map.containsKey(item)) { result.push(item); map.put(item, true); @@ -74,67 +74,42 @@ function union() { } } return result; -} +}; /** * Retrieve the intersection set of a bunch of arrays. * @param {Array} array,... the arrays to intersect * @returns {Array} the intersection set */ -function intersection(array) { - var all = union.apply(null, arguments); - var result = []; - for (var n in all) { - var chksum = 0; - var item = all[n]; - for (var i = 0; i < arguments.length; i += 1) { - if (contains(arguments[i], item)) +exports.intersection = function(array) { + return union.apply(null, arguments).reduce((result, item) => { + let chksum = 0; + for (let i = 0; i < arguments.length; i += 1) { + if (contains(arguments[i], item)) { chksum += 1; - else + } else { break; + } } - if (chksum === arguments.length) + if (chksum === arguments.length) { result.push(item); - } - return result; -} + } + return result; + }, []); +}; /** * @param {Array} array the array * @returns {Number} the maximal element in an array obtained by calling Math.max(). */ -function max(array) { +exports.max = (array) => { return Math.max.apply(Math, array); -} +}; /** * @param {Array} array the array * @returns {Number} the minimal element in an array obtained by calling Math.min(). */ -function min(array) { +exports.min = (array) => { return Math.min.apply(Math, array); -} - -/** - * @param {Function} fn - */ -function partition(fn) { - var trues = [], falses = []; - for (var i=0; i Date: Mon, 2 Nov 2020 16:26:41 +0100 Subject: [PATCH 33/52] code modernization (ie. var -> const/let) --- modules/ringo/utils/dates.js | 389 +++++++++++++++------------------ test/ringo/utils/dates_test.js | 22 +- 2 files changed, 188 insertions(+), 223 deletions(-) diff --git a/modules/ringo/utils/dates.js b/modules/ringo/utils/dates.js index 26007c767..7f8fd1c4b 100644 --- a/modules/ringo/utils/dates.js +++ b/modules/ringo/utils/dates.js @@ -30,6 +30,18 @@ * dates.diff(y2k, now, "mixed"); // { days: 5844, hours: 0, ... } */ +const {Calendar} = java.util; +const {Instant, ZoneOffset} = java.time; + +// Helper +/** @ignore */ +const createGregorianCalender = (date, locale) => { + const cal = locale ? new java.util.GregorianCalendar(locale) : new java.util.GregorianCalendar(); + cal.set(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()); + cal.set(Calendar.MILLISECOND, date.getMilliseconds()); + return cal; +}; + /** * Format a Date to a string in a locale-sensitive manner. * For details on the format pattern, see @@ -60,37 +72,23 @@ * // "1999-12-31 14:00:00 GMT-10:00" * dates.format(y2k, "yyyy-MM-dd HH:mm:ss z", "de", "GMT-10"); */ -function format(date, format, locale, timezone) { +exports.format = (date, format, locale, timezone) => { if (!format) { return date.toString(); } - if (typeof locale == "string") { locale = new java.util.Locale(locale); } - if (typeof timezone == "string") { timezone = java.util.TimeZone.getTimeZone(timezone); } - var sdf = locale ? new java.text.SimpleDateFormat(format, locale) : new java.text.SimpleDateFormat(format); - + const sdf = locale ? new java.text.SimpleDateFormat(format, locale) : new java.text.SimpleDateFormat(format); if (timezone && timezone != sdf.getTimeZone()) { sdf.setTimeZone(timezone); } - return sdf.format(date); -} - -// Helper -/** @ignore */ -function createGregorianCalender(date, locale) { - const cal = locale ? new java.util.GregorianCalendar(locale) : new java.util.GregorianCalendar(); - cal.set(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()); - cal.set(java.util.Calendar.MILLISECOND, date.getMilliseconds()); - - return cal; -} +}; /** * Checks if the date is a valid date. @@ -103,14 +101,14 @@ function createGregorianCalender(date, locale) { * @param {Number} day between 1 and 31 * @returns {Boolean} true, if the date is valid, false if not. */ -function checkDate(fullYear, month, day) { +exports.checkDate = (fullYear, month, day) => { if (fullYear == null || month == null || day == null) { return false; } - var d = new Date(fullYear, month, day); + const d = new Date(fullYear, month, day); return d.getFullYear() === fullYear && d.getMonth() === month && d.getDate() === day; -} +}; /** * Adds delta to the given field or reduces it, if delta is negative. If larger fields are effected, @@ -127,43 +125,43 @@ function checkDate(fullYear, month, day) { * var d2 = dates.add(d1, 1, "hour"); * dates.diff(d1, d2, "hours"); // --> 1 */ -function add(date, delta, unit) { - var unit = (typeof unit === 'undefined') ? "day" : unit, - cal = createGregorianCalender(date), - delta = delta || 0; +exports.add = (date, delta, unit) => { + unit = (typeof unit === 'undefined') ? "day" : unit; + delta || (delta = 0); + const cal = createGregorianCalender(date); switch (unit) { case "year": case "years": - cal.add(java.util.Calendar.YEAR, delta); + cal.add(Calendar.YEAR, delta); break; case "quarter": case "quarters": - cal.add(java.util.Calendar.MONTH, delta * 3); + cal.add(Calendar.MONTH, delta * 3); break; case "month": case "months": - cal.add(java.util.Calendar.MONTH, delta); + cal.add(Calendar.MONTH, delta); break; case "week": case "weeks": - cal.add(java.util.Calendar.WEEK_OF_YEAR, delta); + cal.add(Calendar.WEEK_OF_YEAR, delta); break; case "day": case "days": - cal.add(java.util.Calendar.DATE, delta); + cal.add(Calendar.DATE, delta); break; case "hour": case "hours": - cal.add(java.util.Calendar.HOUR_OF_DAY, delta); + cal.add(Calendar.HOUR_OF_DAY, delta); break; case "minute": case "minutes": - cal.add(java.util.Calendar.MINUTE, delta); + cal.add(Calendar.MINUTE, delta); break; case "second": case "seconds": - cal.add(java.util.Calendar.SECOND, delta); + cal.add(Calendar.SECOND, delta); break; case "millisecond": case "milliseconds": @@ -172,7 +170,7 @@ function add(date, delta, unit) { throw new Error("Invalid unit: " + unit); } return new Date(cal.getTimeInMillis()); -} +}; /** * Checks if the date's year is a leap year. @@ -180,10 +178,10 @@ function add(date, delta, unit) { * @param {Date} date to check year * @returns {Boolean} true if the year is a leap year, false if not. */ -function isLeapYear(date) { - var year = date.getFullYear(); - return year % 4 == 0 && (year % 100 != 0 || (year % 400 == 0)); -} +const isLeapYear = exports.isLeapYear = (date) => { + const year = date.getFullYear(); + return year % 4 === 0 && (year % 100 !== 0 || (year % 400 === 0)); +}; /** * Checks if date a is before date b. This is equals to compareTo(a, b) < 0 @@ -192,9 +190,9 @@ function isLeapYear(date) { * @param {Date} b second date * @returns {Boolean} true if a is before b, false if not. */ -function before(a, b) { +exports.before = (a, b) => { return a.getTime() < b.getTime(); -} +}; /** * Checks if date a is after date b. This is equals to compare(a, b) > 0 @@ -203,9 +201,9 @@ function before(a, b) { * @param {Date} b second date * @returns {Boolean} true if a is after b, false if not. */ -function after(a, b) { +exports.after = (a, b) => { return a.getTime() > b.getTime(); -} +}; /** * Compares the time values of a and b. @@ -215,15 +213,14 @@ function after(a, b) { * @returns {Number} -1 if a is before b, 0 if equals and 1 if a is after b. * @see java.util.Calendar compareTo() */ -function compare(a, b) { +exports.compare = (a, b) => { if (a.getTime() === b.getTime()) { return 0; } else if (a.getTime() < b.getTime()) { return -1; - } else { - return 1; } -} + return 1; +}; /** * Gets the first day of the week. @@ -232,28 +229,28 @@ function compare(a, b) { * @returns {Number} the first day of the week; 1 = Sunday, 2 = Monday. * @see java.util.Calendar constant field values */ -function firstDayOfWeek(locale) { - let calendar = locale ? java.util.Calendar.getInstance(locale) : java.util.Calendar.getInstance(); +exports.firstDayOfWeek = (locale) => { + const calendar = locale ? Calendar.getInstance(locale) : Calendar.getInstance(); return calendar.getFirstDayOfWeek(); -} +}; /** * Gets the second of the day for the given date. * @param {Date} date calculate the second of the day. * @returns {Number} second of the day */ -function secondOfDay(date) { +exports.secondOfDay = (date) => { return (date.getHours() * 3600) + (date.getMinutes() * 60) + date.getSeconds(); -} +}; /** * Gets the day of the year for the given date. * @param {Date} date calculate the day of the year. * @returns {Number} day of the year */ -function dayOfYear(date) { - return createGregorianCalender(date).get(java.util.Calendar.DAY_OF_YEAR); -} +exports.dayOfYear = (date) => { + return createGregorianCalender(date).get(Calendar.DAY_OF_YEAR); +}; /** * Gets the week of the month for the given date. @@ -261,9 +258,9 @@ function dayOfYear(date) { * @param {java.util.Locale} locale (optional) the locale as java Locale * @returns {Number} week of the month */ -function weekOfMonth(date, locale) { - return createGregorianCalender(date, locale).get(java.util.Calendar.WEEK_OF_MONTH); -} +exports.weekOfMonth = (date, locale) => { + return createGregorianCalender(date, locale).get(Calendar.WEEK_OF_MONTH); +}; /** * Gets the week of the year for the given date. @@ -271,9 +268,9 @@ function weekOfMonth(date, locale) { * @param {java.util.Locale} locale (optional) the locale as java Locale * @returns {Number} week of the year */ -function weekOfYear(date, locale) { - return createGregorianCalender(date, locale).get(java.util.Calendar.WEEK_OF_YEAR); -} +exports.weekOfYear = (date, locale) => { + return createGregorianCalender(date, locale).get(Calendar.WEEK_OF_YEAR); +}; /** * Gets the year of the century for the given date. @@ -282,65 +279,65 @@ function weekOfYear(date, locale) { * @example dates.yearInCentury(new Date(1900, 0, 1)); // --> 0 * dates.yearInCentury(new Date(2016, 0, 1)); // --> 16 */ -function yearInCentury(date) { - var year = date.getFullYear(); +exports.yearInCentury = (date) => { + const year = date.getFullYear(); return year - (Math.floor(year / 100) * 100); -} +}; /** * Gets the number of the days in the month. * @param {Date} date to find the maximum number of days. * @returns {Number} days in the month, between 28 and 31. */ -function daysInMonth(date) { - return createGregorianCalender(date).getActualMaximum(java.util.Calendar.DAY_OF_MONTH); -} +exports.daysInMonth = (date) => { + return createGregorianCalender(date).getActualMaximum(Calendar.DAY_OF_MONTH); +}; /** * Gets the number of the days in the year. * @param {Date} date to find the maximum number of days. * @returns {Number} days in the year, 365 or 366, if it's a leap year. */ -function daysInYear(date) { +exports.daysInYear = (date) => { return isLeapYear(date) ? 366 : 365; -} +}; /** * Gets the number of the days in february. * @param {Date} date of year to find the number of days in february. * @returns {Number} days in the february, 28 or 29, if it's a leap year. */ -function daysInFebruary(date) { +exports.daysInFebruary = (date) => { return isLeapYear(date) ? 29 : 28; -} +}; /** * Gets the quarter in the year. * @param {Date} date to calculate the quarter for. * @returns {Number} quarter of the year, between 1 and 4. */ -function quarterInYear(date) { - switch (createGregorianCalender(date).get(java.util.Calendar.MONTH)) { - case java.util.Calendar.JANUARY: - case java.util.Calendar.FEBRUARY: - case java.util.Calendar.MARCH: +const quarterInYear = exports.quarterInYear = (date) => { + switch (createGregorianCalender(date).get(Calendar.MONTH)) { + case Calendar.JANUARY: + case Calendar.FEBRUARY: + case Calendar.MARCH: return 1; - case java.util.Calendar.APRIL : - case java.util.Calendar.MAY : - case java.util.Calendar.JUNE : + case Calendar.APRIL : + case Calendar.MAY : + case Calendar.JUNE : return 2; - case java.util.Calendar.JULY : - case java.util.Calendar.AUGUST : - case java.util.Calendar.SEPTEMBER : + case Calendar.JULY : + case Calendar.AUGUST : + case Calendar.SEPTEMBER : return 3; - case java.util.Calendar.OCTOBER : - case java.util.Calendar.NOVEMBER : - case java.util.Calendar.DECEMBER : + case Calendar.OCTOBER : + case Calendar.NOVEMBER : + case Calendar.DECEMBER : return 4; } throw "Invalid date provided"; -} +}; /** * Gets the quarter in the fiscal year. @@ -351,21 +348,21 @@ function quarterInYear(date) { * // returns 4th quarter * dates.quarterInFiscalYear(new Date(2016, 3, 30), new Date(0, 4, 1)); */ -function quarterInFiscalYear(date, fiscalYearStart) { - var firstDay = fiscalYearStart.getDate(), - firstMonth = fiscalYearStart.getMonth(), - year = date.getFullYear(); - +exports.quarterInFiscalYear = (date, fiscalYearStart) => { + const firstDay = fiscalYearStart.getDate(); + const firstMonth = fiscalYearStart.getMonth(); if (firstDay === 29 && firstMonth === 1) { throw "Fiscal year cannot start on 29th february."; } + let year = date.getFullYear(); // fiscal year starts in the year before the date - if (date.getMonth() < firstMonth || (date.getMonth() == firstMonth && date.getDate() < firstDay)) { + if (date.getMonth() < firstMonth || + (date.getMonth() === firstMonth && date.getDate() < firstDay)) { year --; } - var currentFiscalYear = [ + const currentFiscalYear = [ new Date(year, firstMonth, firstDay), new Date(year, firstMonth + 3, firstDay), new Date(year, firstMonth + 6, firstDay), @@ -373,14 +370,14 @@ function quarterInFiscalYear(date, fiscalYearStart) { new Date(year, firstMonth + 12, firstDay) ]; - for (var i = 1; i <= 4; i++) { + for (let i = 1; i <= 4; i++) { if (inPeriod(date, currentFiscalYear[i-1], currentFiscalYear[i], false, true)) { return i; } } throw "Kudos! You found a bug, if you see this message. Report it!"; -} +}; /** * Get the difference between two dates, specified by the unit of time. @@ -391,18 +388,18 @@ function quarterInFiscalYear(date, fiscalYearStart) { * mixed (returns an object); and their respective plural form. * @returns difference between the given dates in the specified unit of time. * @type Number|Object - * @example var d1 = new Date(Date.UTC(2016, 0, 1, 0, 0)); - * var d2 = new Date(Date.UTC(2017, 0, 1)); + * @example const d1 = new Date(Date.UTC(2016, 0, 1, 0, 0)); + * const d2 = new Date(Date.UTC(2017, 0, 1)); * dates.diff(d1, d2, "years"); // --> 1 * dates.diff(d1, d2, "year"); // --> 1 * dates.diff(d1, d2, "minutes"); // --> 527040 * dates.diff(d1, d2, "mixed"); // --> { days: 366, hours: 0, … } */ -function diff(a, b, unit) { - var unit = (typeof unit === 'undefined') ? "day" : unit, - mDiff = Math.abs(a.getTime() - b.getTime()), - yDiff = a.getFullYear() - b.getFullYear(), - delta = mDiff; +const diff = exports.diff = (a, b, unit) => { + unit = (typeof unit === 'undefined') ? "day" : unit; + const mDiff = Math.abs(a.getTime() - b.getTime()); + const yDiff = a.getFullYear() - b.getFullYear(); + let delta = mDiff; switch (unit) { case "mixed": @@ -450,7 +447,7 @@ function diff(a, b, unit) { } return Math.floor(delta); -} +}; // By Dominik Gruber, written for Tenez.at /** @@ -461,38 +458,34 @@ function diff(a, b, unit) { * @param {Date} bEnd second period's end * @returns {Boolean} true if the periods are overlapping at some point, false if not. */ -function overlapping(aStart, aEnd, bStart, bEnd) { - var aStart = aStart.getTime(), - aEnd = aEnd.getTime(), - bStart = bStart.getTime(), - bEnd = bEnd.getTime(); - - // A |----| - // B |----| - if(aStart >= bStart && aStart <= bEnd && aEnd >= bStart && aEnd >= bEnd) { - return true; - } - - // A |----| - // B |----| - if(aStart <= bStart && aStart <= bEnd && aEnd >= bStart && aEnd <= bEnd) { - return true; - } +exports.overlapping = (aStart, aEnd, bStart, bEnd) => { + aStart = aStart.getTime(); + aEnd = aEnd.getTime(); + bStart = bStart.getTime(); + bEnd = bEnd.getTime(); + + // A |----| + // B |----| + if (aStart >= bStart && aStart <= bEnd && aEnd >= bStart && aEnd >= bEnd) { + return true; + } - // A |-------| - // B |--| - if(aStart <= bStart && aStart <= bEnd && aEnd >= bStart && aEnd >= bEnd) { - return true; - } + // A |----| + // B |----| + if (aStart <= bStart && aStart <= bEnd && aEnd >= bStart && aEnd <= bEnd) { + return true; + } - // A |--| - // B |-------| - if(aStart >= bStart && aStart <= bEnd && aEnd >= bStart && aEnd <= bEnd) { - return true; - } + // A |-------| + // B |--| + if (aStart <= bStart && aStart <= bEnd && aEnd >= bStart && aEnd >= bEnd) { + return true; + } - return false; -} + // A |--| + // B |-------| + return aStart >= bStart && aStart <= bEnd && aEnd >= bStart && aEnd <= bEnd; +}; /** * Look if the date is in the period, using periodStart <= date <= periodEnd. @@ -503,31 +496,30 @@ function overlapping(aStart, aEnd, bStart, bEnd) { * @param {Boolean} periodEndOpen end point is open - default false. * @returns {Boolean} true if the date is in the period, false if not. */ -function inPeriod(date, periodStart, periodEnd, periodStartOpen, periodEndOpen) { - var pStart = periodStart.getTime(), - pEnd = periodEnd.getTime(), - pStartOpen = periodStartOpen || false, - pEndOpen = periodEndOpen || false, - dateMillis = date.getTime(); - - if(!pStartOpen && !pEndOpen && pStart <= dateMillis && dateMillis <= pEnd) { +const inPeriod = exports.inPeriod = (date, periodStart, periodEnd, periodStartOpen, periodEndOpen) => { + const pStart = periodStart.getTime(); + const pEnd = periodEnd.getTime(); + const pStartOpen = periodStartOpen || false; + const pEndOpen = periodEndOpen || false; + const dateMillis = date.getTime(); + + if (!pStartOpen && !pEndOpen && pStart <= dateMillis && dateMillis <= pEnd) { // period |-------| // date ^ return true; - } else if(!pStartOpen && pEndOpen && pStart <= dateMillis && dateMillis < pEnd) { + } else if (!pStartOpen && pEndOpen && pStart <= dateMillis && dateMillis < pEnd) { // period |-------) // date ^ return true; - } else if(pStartOpen && !pEndOpen && pStart < dateMillis && dateMillis <= pEnd) { + } else if (pStartOpen && !pEndOpen && pStart < dateMillis && dateMillis <= pEnd) { // period (-------| // date ^ return true; - } else if(pStartOpen && pEndOpen && pStart < dateMillis && dateMillis < pEnd) { + } else if (pStartOpen && pEndOpen && pStart < dateMillis && dateMillis < pEnd) { // period (-------) // date ^ return true; } - return false; } @@ -535,27 +527,27 @@ function inPeriod(date, periodStart, periodEnd, periodStartOpen, periodEndOpen) * Resets the time values to 0, keeping only year, month and day. * @param {Date} date to reset * @returns {Date} date without any time values - * @example var d = new Date(2016, 5, 10, 10, 20, 30); + * @example const d = new Date(2016, 5, 10, 10, 20, 30); * * // Fri Jun 10 2016 00:00:00 GMT+0200 (MESZ) * dates.resetTime(d); */ -function resetTime(date) { +exports.resetTime = (date) => { return new Date(date.getFullYear(), date.getMonth(), date.getDate()); -} +}; /** * Drops the date values, keeping only hours, minutes, seconds and milliseconds. * @param {Date} date to reset * @returns {Date} date with the original time values and 1970-01-01 as date. - * @example var d = new Date(2016, 5, 10, 10, 20, 30); + * @example const d = new Date(2016, 5, 10, 10, 20, 30); * * // Thu Jan 01 1970 10:20:30 GMT+0100 (MEZ) * dates.resetDate(d); */ -function resetDate(date) { +exports.resetDate = (date) => { return new Date(1970, 0, 1, date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()); -} +}; /** * Creates an ISO 8601 compatible string from the date. This is similar to Date.toISOString(), which @@ -572,7 +564,7 @@ function resetDate(date) { * @example // "2018-08-08T17:16:44.926+02:00" * dates.toISOString(new Date(), true, true); */ -function toISOString(date, withTime, withTimeZone, withSeconds, withMilliseconds) { +exports.toISOString = (date, withTime, withTimeZone, withSeconds, withMilliseconds) => { let year, month, day, hours, minutes, seconds, milliseconds, str; withTime = withTime !== false; @@ -631,7 +623,7 @@ function toISOString(date, withTime, withTimeZone, withSeconds, withMilliseconds } return str; -} +}; /** * Create new Date from UTC timestamp. @@ -645,9 +637,9 @@ function toISOString(date, withTime, withTimeZone, withSeconds, withMilliseconds * @param {Number} millisecond (optional, default 0) * @returns {Date} */ -function fromUTCDate(year, month, date, hour, minute, second, millisecond) { +exports.fromUTCDate = (year, month, date, hour, minute, second, millisecond) => { return new Date(Date.UTC(year, month, date, hour || 0 , minute || 0, second || 0, millisecond || 0)); -} +}; /** * Parse a string to a date using date and time patterns from Java's SimpleDateFormat. @@ -693,7 +685,7 @@ function fromUTCDate(year, month, date, hour, minute, second, millisecond) { * @see W3C Note: Date and Time Formats * @see ES5 Date.parse() */ -function parse(str, format, locale, timezone, lenient) { +exports.parse = (str, format, locale, timezone, lenient) => { let date; // if a format is provided, use java.text.SimpleDateFormat if (typeof format === "string") { @@ -705,7 +697,7 @@ function parse(str, format, locale, timezone, lenient) { timezone = java.util.TimeZone.getTimeZone(timezone); } - var sdf = locale ? new java.text.SimpleDateFormat(format, locale) : new java.text.SimpleDateFormat(format); + const sdf = locale ? new java.text.SimpleDateFormat(format, locale) : new java.text.SimpleDateFormat(format); if (timezone && timezone !== sdf.getTimeZone()) { sdf.setTimeZone(timezone); @@ -717,8 +709,8 @@ function parse(str, format, locale, timezone, lenient) { sdf.setLenient(false); } - var ppos = new java.text.ParsePosition(0); - var javaDate = sdf.parse(str, ppos); + const ppos = new java.text.ParsePosition(0); + const javaDate = sdf.parse(str, ppos); // strict parsing & error during parsing --> return NaN if (lenient === false && ppos.getErrorIndex() >= 0) { @@ -726,41 +718,43 @@ function parse(str, format, locale, timezone, lenient) { } date = javaDate != null ? new Date(javaDate.getTime()) : NaN; - } catch (e if e.javaException instanceof java.text.ParseException) { + } catch (e) { + if (!(e.javaException instanceof java.text.ParseException)) { + throw e; + } date = NaN; } } else { // no date format provided, fall back to RFC 3339 // first check if the native parse method can parse it - var elapsed = Date.parse(str); + const elapsed = Date.parse(str); if (!isNaN(elapsed)) { date = new Date(elapsed); } else { - var match = str.match(/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{1,2}):(\d{2})(?::(\d{2}(?:\.\d+)?))?(Z|(?:[+-]\d{1,2}(?::(\d{2}))?))?)?$/); - var date; + const match = str.match(/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{1,2}):(\d{2})(?::(\d{2}(?:\.\d+)?))?(Z|(?:[+-]\d{1,2}(?::(\d{2}))?))?)?$/); if (match && (match[1] || match[7])) { // must have at least year or time - var year = parseInt(match[1], 10) || 0; - var month = (parseInt(match[2], 10) - 1) || 0; - var day = parseInt(match[3], 10) || 1; + const year = parseInt(match[1], 10) || 0; + const month = (parseInt(match[2], 10) - 1) || 0; + const day = parseInt(match[3], 10) || 1; date = new Date(Date.UTC(year, month, day)); // Check if the given date is valid - if (date.getUTCMonth() != month || date.getUTCDate() != day) { + if (date.getUTCMonth() !== month || date.getUTCDate() !== day) { return NaN; } // optional time if (match[4] !== undefined) { - var type = match[7]; - var hours = parseInt(match[4], 10); - var minutes = parseInt(match[5], 10); - var secFrac = parseFloat(match[6]) || 0; - var seconds = secFrac | 0; - var milliseconds = Math.round(1000 * (secFrac - seconds)); + const type = match[7]; + const hours = parseInt(match[4], 10); + const minutes = parseInt(match[5], 10); + const secFrac = parseFloat(match[6]) || 0; + const seconds = secFrac | 0; + const milliseconds = Math.round(1000 * (secFrac - seconds)); // Checks if the time string is a valid time. - var validTimeValues = function (hours, minutes, seconds) { + const validTimeValues = function (hours, minutes, seconds) { if (hours === 24) { if (minutes !== 0 || seconds !== 0 || milliseconds !== 0) { return false; @@ -774,7 +768,7 @@ function parse(str, format, locale, timezone, lenient) { // Use UTC or local time if (type !== undefined) { date.setUTCHours(hours, minutes, seconds, milliseconds); - if (date.getUTCHours() != hours || date.getUTCMinutes() != minutes || date.getUTCSeconds() != seconds) { + if (date.getUTCHours() !== hours || date.getUTCMinutes() !== minutes || date.getUTCSeconds() !== seconds) { if (!validTimeValues(hours, minutes, seconds, milliseconds)) { return NaN; } @@ -782,9 +776,9 @@ function parse(str, format, locale, timezone, lenient) { // Check offset if (type !== "Z") { - var hoursOffset = parseInt(type, 10); - var minutesOffset = parseInt(match[8]) || 0; - var offset = -1000 * (60 * (hoursOffset * 60) + minutesOffset * 60); + const hoursOffset = parseInt(type, 10); + const minutesOffset = parseInt(match[8]) || 0; + const offset = -1000 * (60 * (hoursOffset * 60) + minutesOffset * 60); // check maximal timezone offset (24 hours) if (Math.abs(offset) >= 86400000) { @@ -794,7 +788,7 @@ function parse(str, format, locale, timezone, lenient) { } } else { date.setHours(hours, minutes, seconds, milliseconds); - if (date.getHours() != hours || date.getMinutes() != minutes || date.getSeconds() != seconds) { + if (date.getHours() !== hours || date.getMinutes() !== minutes || date.getSeconds() !== seconds) { if (!validTimeValues(hours, minutes, seconds, milliseconds)) { return NaN; } @@ -807,7 +801,7 @@ function parse(str, format, locale, timezone, lenient) { } } return date; -} +}; /** * Converts the given date to a java.time.Instant instance. Helps to interact with the @@ -817,9 +811,9 @@ function parse(str, format, locale, timezone, lenient) { * @return {java.time.Instant} instant instance at the given point in time * @see java.time */ -function toInstant(date) { +exports.toInstant = (date) => { return java.time.Instant.ofEpochMilli(date.getTime()); -} +}; /** * Converts the given date to a java.time.OffsetDateTime instance using the date's offset. @@ -829,37 +823,8 @@ function toInstant(date) { * @return {java.time.OffsetDateTime} time instance with offset representing the given date * @see java.time */ -function toOffsetDateTime(date) { - return java.time.Instant.ofEpochMilli(date.getTime()).atOffset( - java.time.ZoneOffset.ofTotalSeconds(date.getTimezoneOffset() * -60) +exports.toOffsetDateTime = (date) => { + return Instant.ofEpochMilli(date.getTime()).atOffset( + ZoneOffset.ofTotalSeconds(date.getTimezoneOffset() * -60) ); -} - -module.exports.format = format; -module.exports.checkDate = checkDate; -module.exports.add = add; -module.exports.isLeapYear = isLeapYear; -module.exports.before = before; -module.exports.after = after; -module.exports.compare = compare; -module.exports.firstDayOfWeek = firstDayOfWeek; -module.exports.secondOfDay = secondOfDay; -module.exports.dayOfYear = dayOfYear; -module.exports.weekOfMonth = weekOfMonth; -module.exports.weekOfYear = weekOfYear; -module.exports.quarterInYear = quarterInYear; -module.exports.quarterInFiscalYear = quarterInFiscalYear; -module.exports.yearInCentury = yearInCentury; -module.exports.daysInMonth = daysInMonth; -module.exports.daysInYear = daysInYear; -module.exports.daysInFebruary = daysInFebruary; -module.exports.diff = diff; -module.exports.overlapping = overlapping; -module.exports.inPeriod = inPeriod; -module.exports.resetTime = resetTime; -module.exports.resetDate = resetDate; -module.exports.toISOString = toISOString; -module.exports.fromUTCDate = fromUTCDate; -module.exports.parse = parse; -module.exports.toInstant = toInstant; -module.exports.toOffsetDateTime = toOffsetDateTime; +}; diff --git a/test/ringo/utils/dates_test.js b/test/ringo/utils/dates_test.js index a8784167f..d07953acf 100644 --- a/test/ringo/utils/dates_test.js +++ b/test/ringo/utils/dates_test.js @@ -1,9 +1,9 @@ -let assert = require('assert'); -let dates = require('ringo/utils/dates'); +const assert = require('assert'); +const dates = require('ringo/utils/dates'); // list of years taken from http://en.wikipedia.org/wiki/List_of_leap_years exports.testIsLeapYear_DaysInFebruary_DaysInYear_DaysInMonth = function () { - let leapYears = [ + const leapYears = [ 1896, 1904, 1908, 1912, 1916, 1920, 1924, 1928, 1932, 1936, 1940, 1944, 1948, 1952, 1956, 1960, 1964, 1968, @@ -20,7 +20,7 @@ exports.testIsLeapYear_DaysInFebruary_DaysInYear_DaysInMonth = function () { ]; leapYears.forEach(function(year) { - let d = new Date(year, 1, 1); + const d = new Date(year, 1, 1); assert.isTrue(dates.isLeapYear(d), "Leap Year " + year); assert.equal(dates.daysInYear(d), 366, "Leap Year " + year); assert.equal(dates.daysInFebruary(d), 29, "Leap Year " + year); @@ -29,7 +29,7 @@ exports.testIsLeapYear_DaysInFebruary_DaysInYear_DaysInMonth = function () { }); noLeapYears.forEach(function(year) { - let d = new Date(year, 0, 1); + const d = new Date(year, 0, 1); assert.isFalse(dates.isLeapYear(d), "No Leap Year " + year); assert.equal(dates.daysInYear(d), 365, "No Leap Year " + year); assert.equal(dates.daysInFebruary(d), 28, "No Leap Year " + year); @@ -52,7 +52,7 @@ exports.testAdd = function () { assert.equal(d.getTime(), Date.UTC(2010, 10, 10, 10, 10, 10, 10)); - let addOne = { + const addOne = { "millisecond": Date.UTC(2010, 10, 10, 10, 10, 10, 11), "second": Date.UTC(2010, 10, 10, 10, 10, 11, 10), "minute": Date.UTC(2010, 10, 10, 10, 11, 10, 10), @@ -477,7 +477,7 @@ exports.testOverlapping = function() { }; exports.testInPeriod = function() { - let pStart = new Date(2010, 0, 10), + const pStart = new Date(2010, 0, 10), pEnd = new Date(2010, 0, 20); // Period [--------] @@ -530,7 +530,7 @@ exports.testInPeriod = function() { }; exports.testResetTime = function() { - let d = new Date(2010, 0, 1, 20, 20, 20); + const d = new Date(2010, 0, 1, 20, 20, 20); assert.equal(dates.resetTime(d).getFullYear(), 2010); assert.equal(dates.resetTime(d).getMonth(), 0); assert.equal(dates.resetTime(d).getDate(), 1); @@ -540,7 +540,7 @@ exports.testResetTime = function() { }; exports.testResetDate = function() { - let d = new Date(2010, 0, 1, 20, 20, 20); + const d = new Date(2010, 0, 1, 20, 20, 20); assert.equal(dates.resetDate(d).getFullYear(), 1970); assert.equal(dates.resetDate(d).getMonth(), 0); assert.equal(dates.resetDate(d).getDate(), 1); @@ -736,7 +736,7 @@ exports.testParse = function() { assert.isFalse(dates.parse("2010-01-01T23:00-25:00") instanceof Date, "parse should return NaN and not an invalid Date"); // java date format tests - assert.strictEqual(dates.parse("2016-06-29T12:11:10.001", "yyyy-MM-dd'T'HH:mm:ss.SSS").getTime(), (new Date(2016,05,29,12,11,10,1)).getTime()); + assert.strictEqual(dates.parse("2016-06-29T12:11:10.001", "yyyy-MM-dd'T'HH:mm:ss.SSS").getTime(), (new Date(2016,5,29,12,11,10,1)).getTime()); assert.strictEqual(dates.parse("2016-06-29T12:11:10.001", "yyyy-MM-dd'T'HH:mm:ss.SSS", "en", "UTC").getTime(), 1467202270001); assert.strictEqual(dates.parse("2016-06-29T12:11:10.001-01:00", "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", "en", "UTC").getTime(), 1467205870001); assert.strictEqual(dates.parse("29. Juni 2016", "dd. MMM yyyy", "de", "UTC").getTime(), 1467158400000); @@ -751,7 +751,7 @@ exports.testParse = function() { assert.isNotNaN(dates.parse("2010-01-01T01:01:01.001").getTime()); // cases map datestrings to objects with corresponding UTC date properties - let cases = { + const cases = { "2000": { year: 2000, month: 0, From 1268b7aacdbf1c115d57d41aa6458bc1687b33b8 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 16:38:55 +0100 Subject: [PATCH 34/52] use strict comparisons and 0o1234 for octals, minor code formatting --- modules/ringo/utils/files.js | 69 ++++++++++++++-------------------- test/ringo/utils/files_test.js | 40 ++++++++++---------- 2 files changed, 49 insertions(+), 60 deletions(-) diff --git a/modules/ringo/utils/files.js b/modules/ringo/utils/files.js index 9702ab415..312b57b96 100644 --- a/modules/ringo/utils/files.js +++ b/modules/ringo/utils/files.js @@ -23,9 +23,9 @@ const FS = FileSystems.getDefault(); * @return {boolean} true if the attribute is supported; false otherwise * @see Java File Attribute View */ -function supportsFileAttributeView(attribute) { +exports.supportsFileAttributeView = (attribute) => { return FS.supportedFileAttributeViews().contains(attribute) === true; -} +}; /** * Resolve an arbitrary number of path elements relative to each other. @@ -35,7 +35,7 @@ function supportsFileAttributeView(attribute) { * Originally adapted for helma/file from narwhal's file module. * @param {...} arbitrary number of path elements */ -function resolveUri() { +const resolveUri = exports.resolveUri = function() { let root = ''; let elements = []; let leaf = ''; @@ -44,29 +44,29 @@ function resolveUri() { const SEPARATOR_RE = /\//; for (let i = 0; i < arguments.length; i++) { path = String(arguments[i]); - if (path.trim() == '') { + if (path.trim() === '') { continue; } let parts = path.split(SEPARATOR_RE); - if (path[0] == '/') { + if (path[0] === '/') { // path is absolute, throw away everyting we have so far root = parts.shift() + SEPARATOR; elements = []; } leaf = parts.pop(); - if (leaf == '.' || leaf == '..') { + if (leaf === '.' || leaf === '..') { parts.push(leaf); leaf = ''; } for (let j = 0; j < parts.length; j++) { let part = parts[j]; - if (part == '..') { - if (elements.length > 0 && arrays.peek(elements) != '..') { + if (part === '..') { + if (elements.length > 0 && arrays.peek(elements) !== '..') { elements.pop(); } else if (!root) { elements.push(part); } - } else if (part != '' && part != '.') { + } else if (part !== '' && part !== '.') { elements.push(part); } } @@ -76,7 +76,7 @@ function resolveUri() { leaf = SEPARATOR + leaf; } return root + path + leaf; -} +}; /** * Resolve path fragment child relative to parent but only @@ -87,10 +87,10 @@ function resolveUri() { * @param {String} parent the parent path * @param {String} child the child path */ -function resolveId(parent, child) { +exports.resolveId = (parent, child) => { // only paths starting with "." or ".." are relative according to module spec const path = child.split("/"); - if (path[0] == "." || path[0] == "..") { + if (path[0] === "." || path[0] === "..") { // we support absolute paths for module ids. Since absolute // paths are platform dependent, use the file module's version // of resolve() for these instead of resolveUri(). @@ -99,7 +99,7 @@ function resolveId(parent, child) { } // child is not relative according to module spec, return it as-is return child; -} +}; /** * Create a new empty temporary file in the default directory for temporary files. @@ -110,7 +110,7 @@ function resolveId(parent, child) { * * @returns {String} the temporary file's path */ -function createTempFile(prefix, suffix, directory, permissions) { +exports.createTempFile = (prefix, suffix, directory, permissions) => { suffix = suffix || null; directory = directory ? getPath(directory) : null; @@ -122,14 +122,13 @@ function createTempFile(prefix, suffix, directory, permissions) { Files.createTempFile(directory, prefix, suffix, posixPermissions.toJavaFileAttribute()) : Files.createTempFile(prefix, suffix, posixPermissions.toJavaFileAttribute()) ).toString(); - } else { - return ( - directory !== null ? - Files.createTempFile(directory, prefix, suffix) : - Files.createTempFile(prefix, suffix) - ).toString(); } -} + return ( + directory !== null ? + Files.createTempFile(directory, prefix, suffix) : + Files.createTempFile(prefix, suffix) + ).toString(); +}; /** * Tests whether the file represented by this File object is a hidden file. @@ -137,9 +136,9 @@ function createTempFile(prefix, suffix, directory, permissions) { * @param {String} file * @returns {Boolean} true if this File object is hidden */ -function isHidden(file) { +exports.isHidden = (file) => { return Files.isHidden(getPath(file)); -} +}; /** * An Array containing the system's file system roots. On UNIX platforms @@ -147,8 +146,8 @@ function isHidden(file) { * contains an element for each mounted drive. * @type Array */ -const roots = (function(rootsIterator) { - let rootDirs = []; +exports.roots = (rootsIterator => { + const rootDirs = []; while(rootsIterator.hasNext()) { rootDirs.push(rootsIterator.next().toString()); } @@ -159,7 +158,7 @@ const roots = (function(rootsIterator) { * The system-dependent file system separator character. * @type String */ -const separator = FS.getSeparator(); +const separator = exports.separator = FS.getSeparator(); /** * Internal use only! @@ -209,8 +208,8 @@ const symbolicToOctalDigit = function(stringPart) { const octalToSymbolicNotation = function(octal) { return [ octalDigitToSymbolic(octal >> 6), - octalDigitToSymbolic((octal >> 3) & 0007), - octalDigitToSymbolic(octal & 0007) + octalDigitToSymbolic((octal >> 3) & 0o0007), + octalDigitToSymbolic(octal & 0o0007) ].join(""); }; @@ -223,7 +222,6 @@ const symbolicToOctalNotation = function(symbolic) { if (symbolic.length !== 9) { throw "Invalid POSIX permission string: " + symbolic; } - return (symbolicToOctalDigit(symbolic.substring(0,3)) << 6) + (symbolicToOctalDigit(symbolic.substring(3,6)) << 3) + symbolicToOctalDigit(symbolic.substring(6,9)); @@ -244,7 +242,7 @@ const enumToOctalNotation = function(javaEnumSet) { * @returns {PosixPermissions} * @constructor */ -function PosixPermissions(permissions) { +const PosixPermissions = exports.PosixPermissions = function(permissions) { if (!(this instanceof PosixPermissions)) { return new PosixPermissions(permissions); } @@ -258,7 +256,7 @@ function PosixPermissions(permissions) { get: function() { return _octalValue; }, set: function(newValue) { if (typeof newValue === "number") { - if (newValue < 0 || newValue > 0777) { + if (newValue < 0 || newValue > 0o0777) { throw "Invalid numeric octal permission: " + newValue.toString(8); } @@ -299,12 +297,3 @@ PosixPermissions.prototype.toJavaFileAttribute = function() { PosixPermissions.prototype.toJavaPosixFilePermissionSet = function() { return PosixFilePermissions.fromString(octalToSymbolicNotation(this.value)); }; - -module.exports.resolveUri = resolveUri; -module.exports.resolveId = resolveId; -module.exports.isHidden = isHidden; -module.exports.createTempFile = createTempFile; -module.exports.roots = roots; -module.exports.separator = separator; -module.exports.supportsFileAttributeView = supportsFileAttributeView; -module.exports.PosixPermissions = PosixPermissions; diff --git a/test/ringo/utils/files_test.js b/test/ringo/utils/files_test.js index 0230c9993..4558f6122 100644 --- a/test/ringo/utils/files_test.js +++ b/test/ringo/utils/files_test.js @@ -1,13 +1,13 @@ -var assert = require("assert"); -var files = require('ringo/utils/files'); -var fs = require('fs'); +const assert = require("assert"); +const files = require('ringo/utils/files'); +const fs = require('fs'); const PARENT = '/home/ringo/'; const CHILD = 'Projects'; const RELATIVE_CHILD = './' + CHILD; const FOO = 'foo'; -exports.testResolveUri = function () { +exports.testResolveUri = () => { // Should work the same for both normal and relative child notations. assert.strictEqual(PARENT + CHILD, files.resolveUri(PARENT, CHILD)); assert.strictEqual(PARENT + CHILD, files.resolveUri(PARENT, RELATIVE_CHILD)); @@ -17,15 +17,15 @@ exports.testResolveUri = function () { assert.strictEqual(PARENT, files.resolveUri(PARENT, PARENT)); }; -exports.testResolveId = function () { +exports.testResolveId = () => { // Parent is ignored unless child starts with "./" or "../" assert.strictEqual(CHILD, files.resolveId(PARENT, CHILD)); assert.strictEqual(PARENT + CHILD, files.resolveId(PARENT, RELATIVE_CHILD)); assert.strictEqual(PARENT, files.resolveId(PARENT, PARENT)); }; -exports.testCreateTempFile = function () { - var tempFile = files.createTempFile('ringo'); +exports.testCreateTempFile = () => { + let tempFile = files.createTempFile('ringo'); assert.isNotNull(tempFile); // Creation w/ prefix only. assert.isTrue(/[\/\\]ringo\w*\.tmp$/.test(tempFile)); assert.isTrue(typeof tempFile === "string", "Result must be string!"); @@ -44,7 +44,7 @@ exports.testCreateTempFile = function () { }; // fixme: test for roots, separator -exports.testHidden = function () { +exports.testHidden = () => { let tempFile = (java.nio.file.Files.createTempFile(".testHidden", ".test")).toString(); assert.isNotNull(tempFile); @@ -86,18 +86,18 @@ exports.testPosixPermissions = function() { return; } - var permissions = new files.PosixPermissions(0777); - assert.strictEqual(0777, permissions.value); + let permissions = new files.PosixPermissions(0o0777); + assert.strictEqual(0o0777, permissions.value); permissions.value = 0; assert.strictEqual(0, permissions.value); - assert.throws(function () { + assert.throws(() => { permissions.value = 1000; }); - var tempPath = java.nio.file.Files.createTempFile(new java.lang.String("ringotest" + Math.random() + Date.now()), null); - var permissionAttributes = java.nio.file.Files.getPosixFilePermissions(tempPath); + const tempPath = java.nio.file.Files.createTempFile(new java.lang.String("ringotest" + Math.random() + Date.now()), null); + const permissionAttributes = java.nio.file.Files.getPosixFilePermissions(tempPath); permissions = new files.PosixPermissions(permissionAttributes); @@ -109,12 +109,12 @@ exports.testPosixPermissions = function() { java.nio.file.Files.delete(tempPath); }; -exports.testCreateTempFileWithPermissions = function () { +exports.testCreateTempFileWithPermissions = () => { if (!java.nio.file.FileSystems.getDefault().supportedFileAttributeViews().contains("posix")) { return; } - let tempFile = files.createTempFile("ringo", null, null, 0000); + let tempFile = files.createTempFile("ringo", null, null, 0o0000); assert.isNotNull(tempFile); // Creation w/ prefix only. assert.isTrue(/[\/\\]ringo\w*\.tmp$/.test(tempFile)); assert.isTrue(typeof tempFile === "string", "Result must be string!"); @@ -124,11 +124,11 @@ exports.testCreateTempFileWithPermissions = function () { ); assert.strictEqual( "[PosixPermissions " + java.nio.file.attribute.PosixFilePermissions.toString(nativePermissions) + "]", - (new files.PosixPermissions(0000)).toString() + (new files.PosixPermissions(0o0000)).toString() ); fs.remove(tempFile); - tempFile = files.createTempFile("ringo", ".js", null, 0000); + tempFile = files.createTempFile("ringo", ".js", null, 0o0000); assert.isNotNull(tempFile); // Creation w/ prefix only. assert.isTrue(/[\/\\]ringo\w*\.js$/.test(tempFile)); assert.isTrue(typeof tempFile === "string", "Result must be string!"); @@ -138,11 +138,11 @@ exports.testCreateTempFileWithPermissions = function () { ); assert.strictEqual( "[PosixPermissions " + java.nio.file.attribute.PosixFilePermissions.toString(nativePermissions) + "]", - (new files.PosixPermissions(0000)).toString() + (new files.PosixPermissions(0o0000)).toString() ); fs.remove(tempFile); - tempFile = files.createTempFile("ringo", ".js", java.lang.System.getProperty("java.io.tmpdir"), 0111); + tempFile = files.createTempFile("ringo", ".js", java.lang.System.getProperty("java.io.tmpdir"), 0o0111); assert.isNotNull(tempFile); // Creation w/ prefix only. assert.isTrue(/[[\/\\]ringo\w*\.js$/.test(tempFile)); assert.isTrue(typeof tempFile === "string", "Result must be string!"); @@ -153,7 +153,7 @@ exports.testCreateTempFileWithPermissions = function () { ); assert.strictEqual( "[PosixPermissions " + java.nio.file.attribute.PosixFilePermissions.toString(nativePermissions) + "]", - (new files.PosixPermissions(0111)).toString() + (new files.PosixPermissions(0o0111)).toString() ); fs.remove(tempFile); }; From 87f41a4fdccad8bbf444b59920de29b781c794ed Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 17:30:44 +0100 Subject: [PATCH 35/52] code modernization (ie. var -> const/let), fixed an error in parseFileUpload() - unfolding multiline headers couldn't have worked --- modules/ringo/utils/http.js | 381 +++++++++++++++++------------------- 1 file changed, 185 insertions(+), 196 deletions(-) diff --git a/modules/ringo/utils/http.js b/modules/ringo/utils/http.js index 6652abe29..0b8ff3ebf 100644 --- a/modules/ringo/utils/http.js +++ b/modules/ringo/utils/http.js @@ -5,16 +5,36 @@ * web framework like stick. */ -var dates = require('ringo/utils/dates'); -var strings = require('ringo/utils/strings'); -var {Buffer} = require('ringo/buffer'); -var {Binary, ByteArray, ByteString} = require('binary'); -var {MemoryStream} = require('io'); +const dates = require('ringo/utils/dates'); +const strings = require('ringo/utils/strings'); +const {Buffer} = require('ringo/buffer'); +const binary = require('binary'); +const io = require('io'); -var open = require('fs').open, - createTempFile = require('ringo/utils/files').createTempFile; +const {open} = require('fs').open; +const {createTempFile} = require('ringo/utils/files'); -var log = require('ringo/logging').getLogger(module.id); +const PATH_CTL = java.util.regex.Pattern.compile("[\x00-\x1F\x7F\x3B]"); +// character codes used for slicing and decoding +const SPACE = " ".charCodeAt(0); +const PERCENT = "%".charCodeAt(0); +const AMPERSAND = "&".charCodeAt(0); +const PLUS = "+".charCodeAt(0); +const EQUALS = "=".charCodeAt(0); + +// character codes used for hex decoding +const CHAR_0 = "0".charCodeAt(0); +const CHAR_9 = "9".charCodeAt(0); +const CHAR_A = "A".charCodeAt(0); +const CHAR_F = "F".charCodeAt(0); +const CHAR_a = "a".charCodeAt(0); +const CHAR_f = "f".charCodeAt(0); + +// used for multipart parsing +const HYPHEN = "-".charCodeAt(0); +const CR = "\r".charCodeAt(0); +const CRLF = new binary.ByteString("\r\n", "ASCII"); +const EMPTY_LINE = new binary.ByteString("\r\n\r\n", "ASCII"); /** * A utility class for implementing JSGI response filters. Each part of the @@ -23,27 +43,31 @@ var log = require('ringo/logging').getLogger(module.id); * @param {Object} body a JSGI response body * @param {Function} filter a filter function */ -function ResponseFilter(body, filter) { +exports.ResponseFilter = function(body, filter) { /** * forEach function called by the JSGI connector. * @param {Function} fn the response handler callback function */ - this.forEach = function(fn) { - body.forEach(function(block) { - var filtered = filter(block); - if (filtered != null) { - fn(filtered); - } - }); - }; -} + Object.defineProperty(this, "forEach", { + "value": (fn) => { + body.forEach(function(block) { + const filtered = filter(block); + if (filtered != null) { + fn(filtered); + } + }); + } + }); + + return this; +}; /** * @ignore interal function, following RFC 7230 section 3.2.2. field order */ -function sanitizeHeaderValue(fieldValue) { +const sanitizeHeaderValue = (fieldValue) => { return fieldValue.replace(/\n/g, "").trim(); -} +}; /** * Returns an object for use as a HTTP request header collection. The returned object @@ -57,18 +81,18 @@ function sanitizeHeaderValue(fieldValue) { * @param {Object} headers an existing JS object. If undefined, a new object is * created */ -function Headers(headers) { +exports.Headers = function(headers) { // when is a duck a duck? if (headers && headers.get && headers.set) { return headers; } headers = headers || {}; - var keys = {}; // populate internal lower case to original case map - for (var key in headers) { - keys[String(key).toLowerCase()] = key; - } + const keys = Object.keys(headers).reduce((result, key) => { + result[String(key).toLowerCase()] = key; + return result; + }, {}); /** * Get the value of the header with the given name @@ -78,12 +102,8 @@ function Headers(headers) { */ Object.defineProperty(headers, "get", { value: function(key) { - var value = this[key]; - if (value === undefined) { - value = (key = keys[key.toLowerCase()]) && this[key]; - } - - return (typeof value === "string" ? sanitizeHeaderValue(value) : value); + const value = this[key] || this[keys[key.toLowerCase()]]; + return (typeof value === "string") ? sanitizeHeaderValue(value) : value; } }); @@ -96,9 +116,9 @@ function Headers(headers) { Object.defineProperty(headers, "set", { value: function(key, value) { value = sanitizeHeaderValue(value); - var oldkey = keys[key.toLowerCase()]; - if (oldkey) { - delete this[oldkey]; + const oldKey = keys[key.toLowerCase()]; + if (oldKey) { + delete this[oldKey]; } this[key] = value; keys[key.toLowerCase()] = key; @@ -119,17 +139,17 @@ function Headers(headers) { this[key] = this[key] + "," + value; return; } - var lowerkey = key.toLowerCase(); - var oldkey = keys[lowerkey]; - if (oldkey) { - value = this[oldkey] + "," + value; - if (key !== oldkey) - delete this[oldkey]; + const lowerKey = key.toLowerCase(); + const oldKey = keys[lowerKey]; + if (oldKey) { + value = this[oldKey] + "," + value; + if (key !== oldKey) { + delete this[oldKey]; + } } this[key] = value; - keys[lowerkey] = key; + keys[lowerKey] = key; } - }); /** @@ -140,8 +160,8 @@ function Headers(headers) { */ Object.defineProperty(headers, "contains", { value: function(key) { - return Boolean(this[key] !== undefined - || (key = keys[key.toLowerCase()]) && this[key] !== undefined); + return Boolean(this[key] !== undefined || + this[keys[key.toLowerCase()]] !== undefined); } }); @@ -152,7 +172,7 @@ function Headers(headers) { */ Object.defineProperty(headers, "unset", { value: function(key) { - key = key.toLowerCase(); + key = key.toLowerCase(); if (key in keys) { delete this[keys[key]]; delete keys[key]; @@ -167,12 +187,12 @@ function Headers(headers) { */ Object.defineProperty(headers, "toString", { value: function() { - var buffer = new Buffer(); - for (var key in this) { + const buffer = new Buffer(); + Object.keys(this).forEach(key => { this[key].split("\n").forEach(function(value) { buffer.write(key).write(": ").writeln(value); }); - } + }, this); return buffer.toString(); } }); @@ -186,18 +206,21 @@ function Headers(headers) { * @param {String} headerValue a header value * @param {String} paramName a MIME parameter name */ -function getMimeParameter(headerValue, paramName) { - if (!headerValue) +const getMimeParameter = exports.getMimeParameter = (headerValue, paramName) => { + if (!headerValue) { return null; - var start, end = 0; + } paramName = paramName.toLowerCase(); - while((start = headerValue.indexOf(";", end)) > -1) { + let end = 0; + let start; + while ((start = headerValue.indexOf(";", end)) > -1) { end = headerValue.indexOf(";", ++start); - if (end < 0) + if (end < 0) { end = headerValue.length; - var eq = headerValue.indexOf("=", start); + } + let eq = headerValue.indexOf("=", start); if (eq > start && eq < end) { - var name = headerValue.slice(start, eq); + let name = headerValue.slice(start, eq); // RFC 2231: Specifically, an asterisk at the end of a parameter name acts as an // indicator that character set and language information may appear at @@ -206,23 +229,22 @@ function getMimeParameter(headerValue, paramName) { name = name.substr(0, name.length - 1); } - if (name.toLowerCase().trim() == paramName) { - var value = headerValue.slice(eq + 1, end).trim(); + if (name.toLowerCase().trim() === paramName) { + const value = headerValue.slice(eq + 1, end).trim(); if (strings.startsWith(value, '"') && strings.endsWith(value, '"')) { return value.slice(1, -1).replace(/\\\\/g, '\\').replace(/\\\"/g, '"'); } else if (strings.startsWith(value, '<') && strings.endsWith(value, '>')) { return value.slice(1, -1); } - return value; } } } return null; -} +}; -function encodeObjectComponent(object, prefix, buffer) { - for (var key in object) { +const encodeObjectComponent = (object, prefix, buffer) => { + for (let key in object) { let value = object[key]; let keyStr = Array.isArray(object) ? "" : key; if (Array.isArray(value)) { @@ -230,11 +252,13 @@ function encodeObjectComponent(object, prefix, buffer) { } else if (typeof value === "object") { encodeObjectComponent(value, prefix + "[" + keyStr + "]", buffer); } else { - if (buffer.length) buffer.write("&"); + if (buffer.length) { + buffer.write("&"); + } buffer.write(encodeURIComponent(prefix + "[" + keyStr + "]"), "=", encodeURIComponent(value)); } } -} +}; /** * Serializes an object's properties into an URL-encoded query string. @@ -252,30 +276,31 @@ function encodeObjectComponent(object, prefix, buffer) { * // "foo%5Bbar%5D%5B%5D%5Bbaz%5D=hello" * http.urlEncode({foo: {bar: [{baz: "hello"}]}}); */ -function urlEncode(object, separator, equals) { - separator = typeof separator === "string" ? separator : "&"; - equals = typeof equals === "string" ? equals : "="; - - var buf = new Buffer(); - var key, value; - for (key in object) { - value = object[key]; +exports.urlEncode = (object, separator, equals) => { + separator = (typeof separator === "string") ? separator : "&"; + equals = (typeof equals === "string") ? equals : "="; + + const buf = new Buffer(); + for (let key in object) { + let value = object[key]; if (Array.isArray(value)) { - for (var i = 0; i < value.length; i++) { - if (buf.length) buf.write(separator); + for (let i = 0; i < value.length; i++) { + if (buf.length) { + buf.write(separator); + } buf.write(encodeURIComponent(key), equals, encodeURIComponent(value[i])); } } else if (typeof value === "object") { encodeObjectComponent(value, key, buf); } else { - if (buf.length) buf.write(separator); + if (buf.length) { + buf.write(separator); + } buf.write(encodeURIComponent(key), equals, encodeURIComponent(value)); } } return buf.toString(); -} - -const PATH_CTL = java.util.regex.Pattern.compile("[\x00-\x1F\x7F\x3B]"); +}; /** * Creates value for the Set-Cookie header for creating a cookie with the given @@ -312,19 +337,20 @@ const PATH_CTL = java.util.regex.Pattern.compile("[\x00-\x1F\x7F\x3B]"); * setCookie("foo", "bar", 10, * { httpOnly: true, secure: true, sameSite: "Lax" }) */ -function setCookie(key, value, days, options) { +exports.setCookie = (key, value, days, options) => { if (value) { // remove newline chars to prevent response splitting attack as value may be user-provided value = value.replace(/[\r\n]/g, ""); } - let buffer = new Buffer(key, "=", value); + const buffer = new Buffer(key, "=", value); if (days !== undefined) { let expires; if (typeof days == "number" && !Number.isNaN(days)) { if (days > -1) { - expires = days == 0 ? - new Date(0) : new Date(Date.now() + days * 1000 * 60 * 60 * 24); + expires = (days === 0) ? + new Date(0) : + new Date(Date.now() + days * 1000 * 60 * 60 * 24); } } else if (days instanceof Date && !Number.isNaN(days.getTime())) { expires = days; @@ -341,7 +367,7 @@ function setCookie(key, value, days, options) { if (options.path && (typeof options.path !== "string" || PATH_CTL.matcher(options.path).find())) { throw new Error("Cookie path not a string or contains CTL characters (%x00-1F;%x7F)"); } - let path = options.path || "/"; + const path = options.path || "/"; buffer.write("; Path=", encodeURI(path)); if (options.domain) { buffer.write("; Domain=", options.domain.toLowerCase()); @@ -361,49 +387,27 @@ function setCookie(key, value, days, options) { } } return buffer.toString(); -} - -// character codes used for slicing and decoding -var SPACE = " ".charCodeAt(0); -var PERCENT = "%".charCodeAt(0); -var AMPERSAND = "&".charCodeAt(0); -var PLUS = "+".charCodeAt(0); -var EQUALS = "=".charCodeAt(0); - -// character codes used for hex decoding -var CHAR_0 = "0".charCodeAt(0); -var CHAR_9 = "9".charCodeAt(0); -var CHAR_A = "A".charCodeAt(0); -var CHAR_F = "F".charCodeAt(0); -var CHAR_a = "a".charCodeAt(0); -var CHAR_f = "f".charCodeAt(0); - -// used for multipart parsing -var HYPHEN = "-".charCodeAt(0); -var CR = "\r".charCodeAt(0); -var CRLF = new ByteString("\r\n", "ASCII"); -var EMPTY_LINE = new ByteString("\r\n\r\n", "ASCII"); +}; /** * Find out whether the content type denotes a format this module can parse. * @param {String} contentType a HTTP request Content-Type header * @returns {Boolean} true if the content type can be parsed as form data by this module */ -function isUrlEncoded(contentType) { +exports.isUrlEncoded = (contentType) => { return contentType && strings.startsWith( String(contentType).toLowerCase(), "application/x-www-form-urlencoded"); -} +}; /** * Find out whether the content type denotes a format this module can parse. * @param {String} contentType a HTTP request Content-Type header * @return {Boolean} true if the content type can be parsed as form data by this module */ -function isFileUpload(contentType) { +exports.isFileUpload = (contentType) => { return contentType && strings.startsWith( String(contentType).toLowerCase(), "multipart/form-data"); -} - +}; /** * Parses a string or binary object representing a query string via an URL or post data into @@ -424,22 +428,23 @@ function isFileUpload(contentType) { * parseParameters("foo[bar][baz]=hello&foo[bar][boo]=world"); * // returns {foo: {bar: {baz: "hello", boo: "world"}}} */ -function parseParameters(input, params, encoding) { +exports.parseParameters = (input, params, encoding) => { if (!input) { return params || {}; - } else if (typeof input === "string" || input instanceof ByteString) { + } else if (typeof input === "string") { // stream.read() should really return ByteArray in the first place... + input = binary.toByteArray(input); + } else if (input instanceof binary.ByteString) { input = input.toByteArray(); } params = params || {}; encoding = encoding || "UTF-8"; - for each (var param in input.split(AMPERSAND)) { - var name, value; - + input.split(AMPERSAND).forEach(param => { + let name, value; // single parameter without any value if (param.indexOf(EQUALS) < 0) { name = param; - value = new ByteString("", encoding); + value = new binary.ByteString("", encoding); } else { [name, value] = param.split(EQUALS, { count: 2 }); } @@ -451,9 +456,9 @@ function parseParameters(input, params, encoding) { if (name !== "") { mergeParameter(params, name, value); } - } + }); return params; -} +}; /** * Adds a value to a parameter object using a square bracket property syntax. @@ -463,10 +468,10 @@ function parseParameters(input, params, encoding) { * @param {String} name the parameter name * @param {String} value the parameter value */ -function mergeParameter(params, name, value) { +const mergeParameter = exports.mergeParameter = (params, name, value) => { // split "foo[bar][][baz]" into ["foo", "bar", "", "baz", ""] - if (name.match(/^[\w_\-\.]+(?:\[[^\]]*\]\s*)+$/)) { - var names = name.split(/\]\s*\[|\[|\]/).map(function(s) s.trim()).slice(0, -1); + if (name.match(/^[\w_\-.]+(?:\[[^\]]*\]\s*)+$/)) { + const names = name.split(/\]\s*\[|\[|\]/).map((s) => s.trim()).slice(0, -1); mergeParameterInternal(params, names, value); } else { // not matching the foo[bar] pattern, add param as is @@ -483,18 +488,18 @@ function mergeParameter(params, name, value) { } } } -} +}; -function mergeParameterInternal(params, names, value) { - if (names.length == 1) { +const mergeParameterInternal = (params, names, value) => { + if (names.length === 1) { // a simple property - push or set depending on params' type Array.isArray(params) ? params.push(value) : params[names[0]] = value; } else { // we have a property path - consume first token and recurse - var name = names.shift(); + const name = names.shift(); if (names[0]) { // foo[bar] - parse as object property - var obj = params[name]; + let obj = params[name]; if (!(obj instanceof Object)) { obj = {}; Array.isArray(params) ? params.push(obj) : params[name] = obj; @@ -502,7 +507,7 @@ function mergeParameterInternal(params, names, value) { mergeParameterInternal(obj, names, value); } else { // foo[] - parse as array - var array = params[name]; + let array = params[name]; if (!Array.isArray(array)) { array = array == null ? [] : [array]; Array.isArray(params) ? params.push(array) : params[name] = array; @@ -510,19 +515,20 @@ function mergeParameterInternal(params, names, value) { mergeParameterInternal(array, names, value); } } -} +}; // convert + to spaces, decode %ff hex sequences, // then decode to string using the specified encoding. -function decodeToString(bytes, encoding) { - var k = 0; - while((k = bytes.indexOf(PLUS, k)) > -1) { +const decodeToString = (bytes, encoding) => { + let k; + while ((k = bytes.indexOf(PLUS, k)) > -1) { bytes[k++] = SPACE; } - var i, j = 0; - while((i = bytes.indexOf(PERCENT, j)) > -1) { + let j = 0; + let i; + while ((i = bytes.indexOf(PERCENT, j)) > -1) { j = i; - while (bytes[i] == PERCENT && i++ <= bytes.length - 3) { + while (bytes[i] === PERCENT && i++ <= bytes.length - 3) { bytes[j++] = (convertHexDigit(bytes[i++]) << 4) + convertHexDigit(bytes[i++]); } @@ -532,15 +538,16 @@ function decodeToString(bytes, encoding) { bytes.length -= i - j; } return bytes.decodeToString(encoding); -} +}; -function convertHexDigit(byte) { - if (byte >= CHAR_0 && byte <= CHAR_9) +const convertHexDigit = (byte) => { + if (byte >= CHAR_0 && byte <= CHAR_9) { return byte - CHAR_0; - if (byte >= CHAR_a && byte <= CHAR_f) + } else if (byte >= CHAR_a && byte <= CHAR_f) { return byte - CHAR_a + 10; - if (byte >= CHAR_A && byte <= CHAR_F) + } else if (byte >= CHAR_A && byte <= CHAR_F) { return byte - CHAR_A + 10; + } return 0; } @@ -555,27 +562,27 @@ function convertHexDigit(byte) { * @returns {Object} an object containing arbitrary parameters as string or uploaded * files as an object with the keys `name`, `filename`, `contentType, `value`. */ -function parseFileUpload(request, params, encoding, streamFactory) { +exports.parseFileUpload = (request, params, encoding, streamFactory) => { params = params || {}; encoding = encoding || "UTF-8"; - streamFactory = streamFactory || BufferFactory; - var boundary = getMimeParameter(request.headers["content-type"], "boundary"); + streamFactory || (streamFactory = BufferFactory); + let boundary = getMimeParameter(request.headers["content-type"], "boundary"); if (!boundary) { return params; } - boundary = new ByteArray("--" + boundary, "ASCII"); - var input = request.input; - var buflen = 8192; - var refillThreshold = 1024; // minimum fill to start parsing - var buffer = new ByteArray(buflen); // input buffer - var data; // data object for current mime part properties - var stream; // stream to write current mime part to - var eof = false; + boundary = new binary.ByteArray("--" + boundary, "ASCII"); + const input = request.input; + const refillThreshold = 1024; // minimum fill to start parsing + const buffer = new binary.ByteArray(8192); // input buffer + let data; // data object for current mime part properties + let stream; // stream to write current mime part to + let eof = false; // the central variables for managing the buffer: // current position and end of read bytes - var position = 0, limit = 0; + let position = 0; + let limit = 0; - var refill = function(waitForMore) { + const refill = (waitForMore) => { if (position > 0) { // "compact" buffer if (position < limit) { @@ -587,9 +594,9 @@ function parseFileUpload(request, params, encoding, streamFactory) { } } // read into buffer starting at limit - var totalRead = 0; + let totalRead = 0; do { - var read = input.readInto(buffer, limit, buffer.length); + let read = input.readInto(buffer, limit, buffer.length); if (read > -1) { totalRead += read; limit += read; @@ -608,51 +615,51 @@ function parseFileUpload(request, params, encoding, streamFactory) { if (!eof && limit - position < refillThreshold) { refill(true); } - var boundaryPos = buffer.indexOf(boundary, position, limit); + let boundaryPos = buffer.indexOf(boundary, position, limit); if (boundaryPos < 0) { throw new Error("boundary not found in multipart stream"); } // move position past boundary to beginning of multipart headers position = boundaryPos + boundary.length + CRLF.length; - if (buffer[position - 2] == HYPHEN && buffer[position - 1] == HYPHEN) { + if (buffer[position - 2] === HYPHEN && buffer[position - 1] === HYPHEN) { // reached final boundary break; } - var b = buffer.indexOf(EMPTY_LINE, position, limit); + let b = buffer.indexOf(EMPTY_LINE, position, limit); if (b < 0) { throw new Error("could not parse headers"); } data = {}; - var headers = []; + let headers = []; buffer.slice(position, b).split(CRLF).forEach(function(line) { line = line.decodeToString(encoding); // unfold multiline headers - if ((strings.startsWith(line, " ") || strings.startsWith(line, "\t")) && headers.length) { - arrays.peek(headers) += line; + if ((line.startsWith(" ") || line.startsWith("\t")) && headers.length) { + headers[headers.length - 1] += arrays.peek(headers); } else { headers.push(line); } }); - for each (var header in headers) { + headers.forEach((header) => { if (strings.startsWith(header.toLowerCase(), "content-disposition:")) { data.name = getMimeParameter(header, "name"); data.filename = getMimeParameter(header, "filename"); } else if (strings.startsWith(header.toLowerCase(), "content-type:")) { data.contentType = header.substring(13).trim(); } - } + }); // move position after the empty line that separates headers from body position = b + EMPTY_LINE.length; // create stream for mime part stream = streamFactory(data, encoding); } - boundaryPos = buffer.indexOf(boundary, position, limit); + let boundaryPos = buffer.indexOf(boundary, position, limit); if (boundaryPos < 0) { // no terminating boundary found, slurp bytes and check for // partial boundary at buffer end which we know starts with "\r\n--" // but we just check for \r to keep it simple. - var cr = buffer.indexOf(CR, Math.max(position, limit - boundary.length - 2), limit); - var end = (cr < 0) ? limit : cr; + let cr = buffer.indexOf(CR, Math.max(position, limit - boundary.length - 2), limit); + let end = (cr < 0) ? limit : cr; stream.write(buffer, position, end); // stream.flush(); position = end; @@ -673,7 +680,7 @@ function parseFileUpload(request, params, encoding, streamFactory) { } } return params; -} +}; /** * Parses the HTTP header and returns a list of ranges to serve. Returns an array of range arrays, @@ -692,13 +699,12 @@ function parseFileUpload(request, params, encoding, streamFactory) { * // returns [[9500,9999]] * parseRange("bytes=-500", 10000); */ -function parseRange(rangeStr, size) { +exports.parseRange = (rangeStr, size) => { if (typeof rangeStr !== "string") { throw new Error("Could not parse range, must be a string, but is " + typeof rangeStr); } // it's not necessary to know the size of the resource - // a size if (size == null) { size = -1 } else if (!Number.isSafeInteger(size) || size < -1) { @@ -726,7 +732,7 @@ function parseRange(rangeStr, size) { try { const rangeSpecs = byteRangeSet.split(","); - return rangeSpecs.map(function (rangeSpec) { + return rangeSpecs.map((rangeSpec) => { const rangeParts = rangeSpec.split("-"); if (rangeParts.length !== 2) { throw new Error("Invalid range"); @@ -777,7 +783,7 @@ function parseRange(rangeStr, size) { } catch (e) { return null; } -} +}; /** * Creates the canonical form of a range array. Also checks if all ranges are valid, otherwise throws an exception. @@ -792,7 +798,7 @@ function parseRange(rangeStr, size) { * // returns [[0, 300]] * canonicalRanges([[0,200], [50, 200], [200, 250], [245, 300]]); */ -function canonicalRanges(ranges) { +exports.canonicalRanges = (ranges) => { if (!Array.isArray(ranges) || ranges.length === 0) { throw new Error("Ranges must be an array of at least one range!"); } @@ -834,9 +840,7 @@ function canonicalRanges(ranges) { // do we have included ranges? // |-----last---------------| // |----range----| - if (range[1] <= highestRangeOnStack[1]) { - return; // do nothing - } else { + if (range[1] > highestRangeOnStack[1]) { // we must extend the latest range on the stack // |-----last-------|+++++++v // |---range---| @@ -846,7 +850,7 @@ function canonicalRanges(ranges) { }); return resultStack; -} +}; /** * A stream factory that stores file upload in a memory buffer. This @@ -857,12 +861,12 @@ function canonicalRanges(ranges) { * @param {Object} data * @param {String} encoding */ -function BufferFactory(data, encoding) { - var isFile = data.filename != null; - var stream = new MemoryStream(); - var close = stream.close; +const BufferFactory = exports.BufferFactory = function(data, encoding) { + const isFile = data.filename != null; + const stream = new io.MemoryStream(); + const {close} = stream; // overwrite stream.close to set the part's content in data - stream.close = function() { + stream.close = () => { close.apply(stream); // set value property to binary for file uploads, string for form data if (isFile) { @@ -884,26 +888,11 @@ function BufferFactory(data, encoding) { * @param {Object} data * @param {String} encoding */ -function TempFileFactory(data, encoding) { +exports.TempFileFactory = function(data, encoding) { if (data.filename == null) { // use in-memory streams for form data return BufferFactory(data, encoding) } data.tempfile = createTempFile("ringo-upload-"); return open(data.tempfile, {write: true, binary: true}); -} - -module.exports.ResponseFilter = ResponseFilter; -module.exports.Headers = Headers; -module.exports.getMimeParameter = getMimeParameter; -module.exports.urlEncode = urlEncode; -module.exports.setCookie = setCookie; -module.exports.isUrlEncoded = isUrlEncoded; -module.exports.isFileUpload = isFileUpload; -module.exports.parseParameters = parseParameters; -module.exports.mergeParameter = mergeParameter; -module.exports.parseFileUpload = parseFileUpload; -module.exports.parseRange = parseRange; -module.exports.canonicalRanges = canonicalRanges; -module.exports.BufferFactory = BufferFactory; -module.exports.TempFileFactory = TempFileFactory; +}; From c8fde042288049afdf795730eec248ca6b179dd9 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 17:32:15 +0100 Subject: [PATCH 36/52] code modernization (ie. var -> const/let) --- modules/ringo/utils/numbers.js | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/modules/ringo/utils/numbers.js b/modules/ringo/utils/numbers.js index fcd80939c..65eba2459 100644 --- a/modules/ringo/utils/numbers.js +++ b/modules/ringo/utils/numbers.js @@ -17,16 +17,13 @@ * >> numbers.format(123, "#,###,##0.00", java.util.Locale.ENGLISH); * '123.00' */ -function format(number, fmt, locale) { - var symbols; - if (locale != null) { - symbols = new java.text.DecimalFormatSymbols(locale); - } else { - symbols = new java.text.DecimalFormatSymbols(); - } - var df = new java.text.DecimalFormat(fmt || "###,##0.##", symbols); +exports.format = (number, fmt, locale) => { + const symbols = (locale != null) ? + new java.text.DecimalFormatSymbols(locale) : + new java.text.DecimalFormatSymbols(); + const df = new java.text.DecimalFormat(fmt || "###,##0.##", symbols); return df.format(+number); -} +}; /** * Invoke a function `num` times, passing 0 .. (this - 1) as argument. @@ -37,11 +34,8 @@ function format(number, fmt, locale) { * console.log("#" + i); * }); */ -function times(num, fun) { - for (var i = 0; i < num; i++) { +exports.times = (num, fun) => { + for (let i = 0; i < num; i++) { fun(i); } -} - -module.exports.format = format; -module.exports.times = times; +}; From 07046a866b2258fb95cae79c6adb3ed7f809a887 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 17:43:55 +0100 Subject: [PATCH 37/52] code modernization (ie. var -> const/let) --- modules/ringo/utils/objects.js | 63 ++++++++--------- test/ringo/utils/objects_test.js | 113 +++++++++++++++---------------- 2 files changed, 84 insertions(+), 92 deletions(-) diff --git a/modules/ringo/utils/objects.js b/modules/ringo/utils/objects.js index 8e504e7b8..425a33a55 100644 --- a/modules/ringo/utils/objects.js +++ b/modules/ringo/utils/objects.js @@ -92,14 +92,14 @@ * console.log(shallowClone.root); // --> 1 * console.dir(shallowClone.a.b.c.d); // --> { e: 'bar' } */ -function clone(object, circular, depth, prototype) { +const clone = exports.clone = (object, circular, depth, prototype) => { if (typeof circular === 'object') { throw new Error("Old function signature used for objects.clone()!"); } // maintain two arrays for circular references, where corresponding parents // and children have the same index - var allParents = []; - var allChildren = []; + const allParents = []; + const allChildren = []; if (typeof circular == 'undefined') { circular = true; @@ -115,21 +115,19 @@ function clone(object, circular, depth, prototype) { if (parent === null) { return null; } - if (depth === 0) { return parent; } - - var child; - var proto; if (typeof parent != 'object') { return parent; } + let child; + let proto; if (Array.isArray(parent)) { child = []; } else if (parent instanceof RegExp) { - var flags = ""; + let flags = ""; if (parent.global) { flags += 'g'; } @@ -141,47 +139,46 @@ function clone(object, circular, depth, prototype) { } child = new RegExp(parent.source, flags); - if (parent.lastIndex) child.lastIndex = parent.lastIndex; + if (parent.lastIndex) { + child.lastIndex = parent.lastIndex; + } } else if (parent instanceof Date) { child = new Date(parent.getTime()); } else { if (typeof prototype == 'undefined') { proto = Object.getPrototypeOf(parent); child = Object.create(proto); - } - else { + } else { child = Object.create(prototype); proto = prototype; } } if (circular) { - var index = allParents.indexOf(parent); - - if (index != -1) { + const index = allParents.indexOf(parent); + if (index !== -1) { return allChildren[index]; } allParents.push(parent); allChildren.push(child); } - for (var i in parent) { - var attrs; + Object.keys(parent).forEach(key => { + let attrs; if (proto) { - attrs = Object.getOwnPropertyDescriptor(proto, i); + attrs = Object.getOwnPropertyDescriptor(proto, key); } - if (attrs && attrs.set == null) { - continue; + if (!attrs || attrs.set !== null) { + child[key] = _clone(parent[key], depth - 1); } - child[i] = _clone(parent[i], depth - 1); - } + }); return child; } return _clone(object, depth); -} +}; /** * Creates a new object as the as the keywise union of the provided objects. @@ -195,17 +192,15 @@ function clone(object, circular, depth, prototype) { * // result: { k1: 'val-A', k2: 'val-B' } * const result = objects.merge(a, b, c); */ -function merge() { - var result = {}; - for (var i = arguments.length; i > 0; --i) { - var obj = arguments[i - 1]; - for (var id in obj) { - if (!obj.hasOwnProperty(id)) continue; - result[id] = obj[id]; - } +exports.merge = function() { + const result = {}; + for (let i = arguments.length; i > 0; --i) { + let obj = arguments[i - 1]; + Object.keys(obj).forEach(key => { + if (obj.hasOwnProperty(key)) { + result[key] = obj[key]; + } + }); } return result; -} - -module.exports.clone = clone; -module.exports.merge = merge; +}; diff --git a/test/ringo/utils/objects_test.js b/test/ringo/utils/objects_test.js index 26fb91f5d..24898ceed 100644 --- a/test/ringo/utils/objects_test.js +++ b/test/ringo/utils/objects_test.js @@ -20,25 +20,25 @@ // https://github.com/pvorb/node-clone/blob/master/LICENSE // http://paul.vorba.ch/ and https://github.com/pvorb/node-clone/graphs/contributors -var assert = require('assert'); -var {merge, clone} = require('ringo/utils/objects'); +const assert = require('assert'); +const {merge, clone} = require('ringo/utils/objects'); exports.testMerge = function() { - var x = {a: 1, b: 2}; - var y = {b: 3, c: 4}; - var z = {c: 5, d: 6}; + const x = {a: 1, b: 2}; + const y = {b: 3, c: 4}; + const z = {c: 5, d: 6}; // degenerate zero/single-argument cases - assert.deepEqual(merge(), {}); - assert.deepEqual(merge(x), {a: 1, b: 2}); + assert.deepEqual(merge(), {}); + assert.deepEqual(merge(x), {a: 1, b: 2}); // property values of "earlier" arguments are promoted into the result - assert.deepEqual(merge(x, y), {a: 1, b: 2, c: 4}); - assert.deepEqual(merge(y, x), {b: 3, c: 4, a: 1}); + assert.deepEqual(merge(x, y), {a: 1, b: 2, c: 4}); + assert.deepEqual(merge(y, x), {b: 3, c: 4, a: 1}); - assert.deepEqual(merge(x, y, z), {a: 1, b: 2, c: 4, d: 6}); - assert.deepEqual(merge(y, z, x), {b: 3, c: 4, d: 6, a: 1}); - assert.deepEqual(merge(z, x, y), {c: 5, d: 6, a: 1, b: 2}); + assert.deepEqual(merge(x, y, z), {a: 1, b: 2, c: 4, d: 6}); + assert.deepEqual(merge(y, z, x), {b: 3, c: 4, d: 6, a: 1}); + assert.deepEqual(merge(z, x, y), {c: 5, d: 6, a: 1, b: 2}); // check that the objects passed as arguments were not modified assert.deepEqual(x, {a: 1, b: 2}); @@ -60,60 +60,58 @@ exports.testCloneNumber = function() { }; exports.testCloneDate = function() { - var a = new Date(); - var c = clone(a); + const a = new Date(); + const c = clone(a); assert.isTrue(!!a.getUTCDate && !!a.toUTCString); assert.isTrue(!!c.getUTCDate && !!c.toUTCString); assert.strictEqual(a.getTime(), c.getTime()); }; exports.testCloneObject = function() { - var a = { foo: { bar: "baz" } }; - var b = clone(a); - + const a = { foo: { bar: "baz" } }; + const b = clone(a); assert.deepEqual(b, a); }; assert.testCloneArray = function() { - var a = [ + const a = [ { foo: "bar" }, "baz" ]; - var b = clone(a); - + const b = clone(a); assert.isTrue(b instanceof Array); assert.deepEqual(b, a); }; exports.testCloneRegExp = function() { - var a = /abc123/gi; - var b = clone(a); + const a = /abc123/gi; + const b = clone(a); assert.deepEqual(b, a); - var c = /a/g; + const c = /a/g; assert.isTrue(c.lastIndex === 0); c.exec('123a456a'); assert.isTrue(c.lastIndex === 4); - var d = clone(c); + const d = clone(c); assert.isTrue(d.global); assert.isTrue(d.lastIndex === 4); }; exports.testCloneObjectWithArray = function() { - var a = { + const a = { arr1: [ { a: '1234', b: '2345' } ], arr2: [ { c: '345', d: '456' } ] }; - var b = clone(a); + const b = clone(a); assert.deepEqual(b, a); }; exports.testCloneCircularReferences = function() { - const inspect = function(obj) { - var seen = []; + const inspect = (obj) => { + const seen = []; return JSON.stringify(obj, function (key, val) { if (val !== null && typeof val == "object") { if (seen.indexOf(val) >= 0) { @@ -124,48 +122,47 @@ exports.testCloneCircularReferences = function() { return val; }); }; + const eq = (x, y) => { + return inspect(x) === inspect(y); + }; - var c = [1, "foo", {'hello': 'bar'}, function () {}, false, [2]]; - var b = [c, 2, 3, 4]; + const c = [1, "foo", {'hello': 'bar'}, function () {}, false, [2]]; + const b = [c, 2, 3, 4]; - var a = {'b': b, 'c': c}; + const a = {'b': b, 'c': c}; a.loop = a; a.loop2 = a; c.loop = c; c.aloop = a; - var aCopy = clone(a); - assert.isTrue(a != aCopy); - assert.isTrue(a.c != aCopy.c); - assert.isTrue(aCopy.c == aCopy.b[0]); - assert.isTrue(aCopy.c.loop.loop.aloop == aCopy); - assert.isTrue(aCopy.c[0] == a.c[0]); + const aCopy = clone(a); + assert.isTrue(a !== aCopy); + assert.isTrue(a.c !== aCopy.c); + assert.isTrue(aCopy.c === aCopy.b[0]); + assert.isTrue(aCopy.c.loop.loop.aloop === aCopy); + assert.isTrue(aCopy.c[0] === a.c[0]); assert.isTrue(eq(a, aCopy)); aCopy.c[0] = 2; assert.isTrue(!eq(a, aCopy)); aCopy.c = "2"; assert.isTrue(!eq(a, aCopy)); - - function eq(x, y) { - return inspect(x) === inspect(y); - } }; exports.testCloneObjectsWithoutConstructor = function() { - var n = null; + const n = null; - var a = { foo: 'bar' }; + const a = { foo: 'bar' }; a.__proto__ = n; assert.isTrue(typeof a === 'object'); assert.isTrue(typeof a !== null); - var b = clone(a); + const b = clone(a); assert.strictEqual(a.foo, b.foo); }; exports.testCloneWithDeep = function() { - var a = { + const a = { foo: { bar : { baz : 'qux' @@ -173,7 +170,7 @@ exports.testCloneWithDeep = function() { } }; - var b = clone(a, false, 1); + let b = clone(a, false, 1); assert.deepEqual(b, a); assert.notEqual(b, a); assert.strictEqual(b.foo, a.foo); @@ -185,23 +182,23 @@ exports.testCloneWithDeep = function() { }; exports.testCloneWithPrototype = function() { - function T() {} + const T = function() {}; - var a = new T(); - var b = clone(a); + const a = new T(); + const b = clone(a); assert.strictEqual(Object.getPrototypeOf(a), Object.getPrototypeOf(b)); }; exports.testCloneWithProvidedPrototype = function() { - function T() {} + const T = function() {}; - var a = new T(); - var b = clone(a, true, Infinity, null); + const a = new T(); + const b = clone(a, true, Infinity, null); assert.strictEqual(b.__defineSetter__, undefined); }; exports.testCloneWithNullChildren = function() { - var a = { + const a = { foo: { bar: null, baz: { @@ -210,22 +207,22 @@ exports.testCloneWithNullChildren = function() { } }; - var b = clone(a); + const b = clone(a); assert.deepEqual(b, a); }; exports.testCloneWithGetter = function() { - function Ctor() {} + const Ctor = function() {}; Object.defineProperty(Ctor.prototype, 'prop', { configurable: true, enumerable: true, - get: function() { + get: () => { return 'value'; } }); - var a = new Ctor(); - var b = clone(a); + const a = new Ctor(); + const b = clone(a); assert.strictEqual(b.prop, 'value'); }; From fcbb093ab15d8a0b64bee986945534de9dd2275c Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 2 Nov 2020 18:11:04 +0100 Subject: [PATCH 38/52] code modernization (ie. var -> const/let) --- modules/ringo/utils/strings.js | 441 ++++++++++++++----------------- test/ringo/utils/strings_test.js | 20 +- 2 files changed, 207 insertions(+), 254 deletions(-) diff --git a/modules/ringo/utils/strings.js b/modules/ringo/utils/strings.js index 8fe662bbd..27f877d92 100644 --- a/modules/ringo/utils/strings.js +++ b/modules/ringo/utils/strings.js @@ -63,7 +63,7 @@ const URLPATTERN = java.util.regex.Pattern.compile("^" + // Copyright (c) 2014 Chris O'Hara cohara87@gmail.com // licensed unter MIT license - https://github.com/chriso/validator.js/blob/master/LICENSE const INT = /^(?:[-+]?(?:0|[1-9][0-9]*))$/; -const FLOAT = /^(?:[-+]?(?:[0-9]*))(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/; +const FLOAT = /^(?:[-+]?(?:[0-9]*))(?:\.[0-9]*)?(?:[eE][+\-]?(?:[0-9]+))?$/; const base64 = require('ringo/base64'); const dates = require('ringo/utils/dates'); @@ -81,14 +81,14 @@ const dates = require('ringo/utils/dates'); * strings.isDateFormat(""); // --> true * strings.isDateFormat("PPPP"); // --> false */ -function isDateFormat(string) { +exports.isDateFormat = (string) => { try { new java.text.SimpleDateFormat(string); return true; } catch (err) { return false; } -} +}; /** * Parse a timestamp into a `Date` object. @@ -100,16 +100,16 @@ function isDateFormat(string) { * strings.toDate("24-12-2015", "dd-MM-yyyy"); * * // Thu Dec 24 2015 09:00:00 GMT+0100 (MEZ) - * var tz = java.util.TimeZone.getTimeZone("America/Los_Angeles"); + * const tz = java.util.TimeZone.getTimeZone("America/Los_Angeles"); * strings.toDate("24-12-2015", "dd-MM-yyyy", tz); */ -function toDate(string, format, timezone) { - var simpleDateFormat = new java.text.SimpleDateFormat(format); +exports.toDate = (string, format, timezone) => { + const simpleDateFormat = new java.text.SimpleDateFormat(format); if (timezone && timezone != simpleDateFormat.getTimeZone()) { simpleDateFormat.setTimeZone(timezone); } return new Date(simpleDateFormat.parse(string).getTime()); -} +}; /** * Checks if the string is a valid URL. Only HTTP, HTTPS and FTP are allowed protocols. @@ -132,11 +132,11 @@ function toDate(string, format, timezone) { * strings.isUrl("//example.com"); * strings.isUrl("http://10.1.1.255"); */ -function isUrl(string) { +exports.isUrl = (string) => { // uses java.util.regex.Pattern for performance reasons, // pure JS / Rhino RegExp will not stop in feasible time! return (URLPATTERN.matcher(string)).matches(); -} +}; /** * Checks if the string passed contains any characters @@ -155,9 +155,9 @@ function isUrl(string) { * strings.isFileName("foo/bar/baz"); * strings.isFileName("foo-bar+baz"); */ -function isFileName(string) { +exports.isFileName = (string) => { return !FILEPATTERN.test(string); -} +}; /** * Cleans the string passed as argument from any characters @@ -167,9 +167,9 @@ function isFileName(string) { * @example // returns "..foobarbaz" * strings.toFileName("../foo/bar+baz"); */ -function toFileName(string) { +exports.toFileName = (string) => { return string.replace(new RegExp(FILEPATTERN.source, "g"), ''); -} +}; /** * Checks a string for a valid color value in hexadecimal format. @@ -188,11 +188,12 @@ function toFileName(string) { * strings.isHexColor("#matcha"); * strings.isHexColor("#tea"); */ -function isHexColor(string) { - if (string.indexOf("#") == 0) +exports.isHexColor = (string) => { + if (string.indexOf("#") === 0) { string = string.substring(1); - return string.length == 6 && !HEXPATTERN.test(string); -} + } + return string.length === 6 && !HEXPATTERN.test(string); +}; /** * Converts a string into a hexadecimal color @@ -205,21 +206,21 @@ function isHexColor(string) { * strings.toHexColor("rgb (255, 204, 51)"); // --> ffcc33 * strings.toHexColor("rgba(255, 204, 51)"); // --> ffcc33 */ -function toHexColor(string) { - if (startsWith(string, "rgb")) { - var buffer = []; - var col = string.replace(/[^0-9,]/g, ''); - var parts = col.split(","); - for (var i in parts) { - var num = parseInt(parts[i], 10); - var hex = num.toString(16); +exports.toHexColor = (string) => { + if (string.startsWith("rgb")) { + const buffer = []; + const col = string.replace(/[^0-9,]/g, ''); + const parts = col.split(","); + parts.forEach(part => { + const num = parseInt(part, 10); + const hex = num.toString(16); buffer.push(pad(hex, "0", 2, -1)); - } + }); return buffer.join(""); } - var color = string.replace(new RegExp(HEXPATTERN.source), ''); + const color = string.replace(new RegExp(HEXPATTERN.source), ''); return pad(color.toLowerCase(), "0", 6, -1); -} +}; /** * Returns true if the string contains only a-z, A-Z and 0-9 (case insensitive). @@ -228,9 +229,9 @@ function toHexColor(string) { * @example strings.isAlphanumeric("foobar123"); // --> true * strings.isAlphanumeric("foo@example"); // --> false */ -function isAlphanumeric(string) { +exports.isAlphanumeric = (string) => { return string.length && !ANUMPATTERN.test(string); -} +}; /** * Cleans a string by throwing away all non-alphanumeric characters. @@ -239,9 +240,9 @@ function isAlphanumeric(string) { * @example // returns "dogdogecom" * strings.toAlphanumeric("dog@doge.com"); */ -function toAlphanumeric(string) { +exports.toAlphanumeric = (string) => { return string.replace(new RegExp(ANUMPATTERN.source, "g"), ''); -} +}; /** * Returns true if the string contains only characters a-z and A-Z. @@ -250,9 +251,9 @@ function toAlphanumeric(string) { * @example strings.isAlpha("foo"); // --> true * strings.isAlpha("foo123"); // --> false */ -function isAlpha(string) { +exports.isAlpha = (string) => { return string.length && !APATTERN.test(string); -} +}; /** * Returns true if the string contains only 0-9. @@ -262,9 +263,9 @@ function isAlpha(string) { * strings.isNumeric("00012345"); // --> true * strings.isAlpha("foo123"); // --> false */ -function isNumeric(string) { +exports.isNumeric = (string) => { return string.length && !NUMPATTERN.test(string); -} +}; /** * Transforms string from space, dash, or underscore notation to camel-case. @@ -274,7 +275,7 @@ function isNumeric(string) { * strings.toCamelCase("the-dog_jumps"); // "theDogJumps" * strings.toCamelCase("FOObarBaz"); // "FoobarBaz" */ -function toCamelCase(string) { +exports.toCamelCase = (string) => { return string.replace(/([A-Z]+)/g, function(m, l) { // "ABC" -> "Abc" return l[0].toUpperCase() + l.substring(1).toLowerCase(); @@ -282,7 +283,7 @@ function toCamelCase(string) { // foo-bar -> fooBar return l.toUpperCase(); }); -} +}; /** * Transforms string from camel-case to dash notation. @@ -292,9 +293,9 @@ function toCamelCase(string) { * strings.toDashes("fooBARBaz"); // "foo-b-a-r-baz" * strings.toDashes("foo-Bar-Baz"); // "foo--bar--baz" */ -function toDashes(string) { +exports.toDashes = (string) => { return string.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();}); -} +}; /** * Transforms string from camel-case to underscore notation. @@ -305,25 +306,26 @@ function toDashes(string) { * strings.toUnderscores("foo_Bar_Baz"); // "foo__bar__baz" * strings.toUnderscores("foo-Bar-Baz"); // foo-_bar-_baz */ -function toUnderscores(string) { +exports.toUnderscores = (string) => { return string.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();}); -} +}; /** * Transforms the first n characters of a string to uppercase. - * @param {String} the string to capitalize - * @param {Number} amount of characters to transform + * @param {String} string the string to capitalize + * @param {Number} limit amount of characters to transform * @returns {String} the resulting string * @example strings.capitalize("example text"); // "Example text" * strings.capitalize("example text", 7); // EXAMPLE text */ -function capitalize(string, limit) { - if (limit == null) +const capitalize = exports.capitalize = (string, limit) => { + if (limit == null) { limit = 1; - var head = string.substring(0, limit); - var tail = string.substring(limit, this.length); + } + const head = string.substring(0, limit); + const tail = string.substring(limit, this.length); return head.toUpperCase() + tail.toLowerCase(); -} +}; /** * Transforms the first n characters of each word in a string to uppercase. @@ -334,14 +336,11 @@ function capitalize(string, limit) { * strings.titleize("the bar is foo", 2); // --> "THe BAr IS FOo" * strings.titleize("the bar is foo", 3); // --> "THE BAR IS FOO" */ -function titleize(string, amount) { - var parts = string.split(" "); - var buffer = []; - for (var i in parts) { - buffer.push(capitalize(parts[i], amount)); - } - return buffer.join(" "); -} +exports.titleize = (string, amount) => { + return string.split(" ").map(part => { + return capitalize(part, amount); + }).join(" "); +}; /** * Translates all characters of a string into HTML entities. @@ -350,19 +349,19 @@ function titleize(string, amount) { * @returns {String} translated result * @example strings.entitize("@foo"); // --> "&#64;&#102;&#111;&#111;" */ -function entitize(string) { - var buffer = []; - for (var i = 0; i < string.length; i++) { +exports.entitize = (string) => { + const buffer = []; + for (let i = 0; i < string.length; i++) { buffer.push("&#", string.charCodeAt(i).toString(), ";"); } return buffer.join(""); -} +}; /** * Inserts a string every number of characters. * @param {String} string * @param {Number} interval number of characters after which insertion should take place, defaults to 20 - * @param {String} string to be inserted + * @param {String} str string to be inserted * @param {Boolean} ignoreWhiteSpace optional, definitely insert at each interval position * @returns {String} resulting string * @example // returns "fobaro fobaro fobaro" @@ -371,22 +370,24 @@ function entitize(string) { * // returns "fobaro barfobaro barfobarobar" * strings.group("foo foo foo", 2, "bar", true); */ -function group(string, interval, str, ignoreWhiteSpace) { - if (!interval || interval < 1) +exports.group = (string, interval, str, ignoreWhiteSpace) => { + if (!interval || interval < 1) { interval = 20; - if (!str || string.length < interval) + } + if (!str || string.length < interval) { return string; - var buffer = []; - for (var i = 0; i < string.length; i += interval) { - var strPart = string.substring(i, i + interval); + } + const buffer = []; + for (let i = 0; i < string.length; i += interval) { + let strPart = string.substring(i, i + interval); buffer.push(strPart); - if (ignoreWhiteSpace == true || - (strPart.length == interval && !/\s/g.test(strPart))) { + if (ignoreWhiteSpace === true || + (strPart.length === interval && !/\s/g.test(strPart))) { buffer.push(str); } } return buffer.join(""); -} +}; /** * Calculates a message digest of a string. If no argument is passed, the MD5 algorithm is used. @@ -399,11 +400,11 @@ function group(string, interval, str, ignoreWhiteSpace) { * @example // "C3499C2729730A7F807EFB8676A92DCB6F8A3F8F" * strings.digest("example", "sha-1"); */ -function digest(string, algorithm) { - var md = java.security.MessageDigest.getInstance(algorithm || 'MD5'); - var b = ByteString.wrap(md.digest(string.toByteString())); +exports.digest = (string, algorithm) => { + const md = java.security.MessageDigest.getInstance(algorithm || 'MD5'); + const b = ByteString.wrap(md.digest(string.toByteString())); return b16encode(b); -} +}; /** * Repeats a string passed as argument multiple times. @@ -412,12 +413,13 @@ function digest(string, algorithm) { * @returns {String} resulting string * @example strings.repeat("foo", 3); // --> "foofoofoo" */ -function repeat(string, num) { - var list = []; - for (var i = 0; i < num; i++) +exports.repeat = (string, num) => { + const list = []; + for (let i = 0; i < num; i++) { list[i] = string; + } return list.join(''); -} +}; /** * Returns true if string starts with the given substring. @@ -428,9 +430,9 @@ function repeat(string, num) { * @example strings.startsWith("foobar", "foo"); // --> true * strings.startsWith("foobar", "bar"); // --> false */ -function startsWith(string, substring) { - return string.indexOf(substring) == 0; -} +exports.startsWith = (string, substring) => { + return string.indexOf(substring) === 0; +}; /** * Returns true if string ends with the given substring. @@ -441,10 +443,10 @@ function startsWith(string, substring) { * @example strings.endsWith("foobar", "bar"); // --> true * strings.endsWith("foobar", "foo"); // --> false */ -function endsWith(string, substring) { - var diff = string.length - substring.length; - return diff > -1 && string.lastIndexOf(substring) == diff; -} +exports.endsWith = (string, substring) => { + const diff = string.length - substring.length; + return diff > -1 && string.lastIndexOf(substring) === diff; +}; /** * Fills a string with another string up to a desired length. @@ -469,36 +471,36 @@ function endsWith(string, substring) { * // "worldwohelloworldwor" * strings.pad("hello", "world", 20, 0); */ -function pad(string, fill, length, mode) { +const pad = exports.pad = (string, fill, length, mode) => { if (typeof string !== "string") { string = string.toString(); } if (fill == null || length == null) { return string; } - var diff = length - string.length; - if (diff == 0) { + const diff = length - string.length; + if (diff === 0) { return string; } - var left, right = 0; + let left, right = 0; if (mode == null || mode > 0) { right = diff; } else if (mode < 0) { left = diff; - } else if (mode == 0) { + } else if (mode === 0) { right = Math.round(diff / 2); left = diff - right; } - var list = []; - for (var i = 0; i < left; i++) { + const list = []; + for (let i = 0; i < left; i++) { list[i] = fill[i % fill.length]; } list.push(string); - for (i = 0; i < right; i++) { + for (let i = 0; i < right; i++) { list.push(fill[i % fill.length]); } return list.join(''); -} +}; /** * Returns true if string contains substring. @@ -511,10 +513,9 @@ function pad(string, fill, length, mode) { * strings.contains("foobar", "oo", 1); // --> true * strings.contains("foobar", "oo", 2); // --> false */ -function contains(string, substring, fromIndex) { - fromIndex = fromIndex || 0; - return string.indexOf(substring, fromIndex) > -1; -} +const contains = exports.contains = (string, substring, fromIndex) => { + return string.indexOf(substring, fromIndex || 0) > -1; +}; /** * Get the longest common segment that two strings @@ -525,22 +526,22 @@ function contains(string, substring, fromIndex) { * @example strings.getCommonPrefix("foobarbaz", "foobazbar"); // --> "fooba" * strings.getCommonPrefix("foobarbaz", "bazbarfoo"); // --> "" */ -function getCommonPrefix(str1, str2) { +exports.getCommonPrefix = (str1, str2) => { if (str1 == null || str2 == null) { return null; - } else if (str1.length > str2.length && str1.indexOf(str2) == 0) { + } else if (str1.length > str2.length && str1.indexOf(str2) === 0) { return str2; - } else if (str2.length > str1.length && str2.indexOf(str1) == 0) { + } else if (str2.length > str1.length && str2.indexOf(str1) === 0) { return str1; } - var length = Math.min(str1.length, str2.length); - for (var i = 0; i < length; i++) { - if (str1[i] != str2[i]) { + const length = Math.min(str1.length, str2.length); + for (let i = 0; i < length; i++) { + if (str1[i] !== str2[i]) { return str1.slice(0, i); } } return str1.slice(0, length); -} +}; /** * Returns true if the string looks like an e-mail. @@ -550,9 +551,9 @@ function getCommonPrefix(str1, str2) { * @example strings.isEmail("rhino@ringojs.org"); // --> true * strings.isEmail("rhino@ringojs"); // --> false */ -function isEmail(string) { +exports.isEmail = (string) => { return EMAILPATTERN.test(string); -} +}; /** * Returns the amount of occurrences of one string in another. @@ -561,15 +562,15 @@ function isEmail(string) { * @returns {Number} occurrences * @example strings.count("foobarfoo", "foo"); // --> 2 */ -function count(string, pattern) { - var count = 0; - var offset = 0; - while ((offset = string.indexOf(pattern, offset)) > -1) { - count += 1; - offset += 1; - } - return count; +exports.count = (string, pattern) => { + let count = 0; + let offset = 0; + while ((offset = string.indexOf(pattern, offset)) > -1) { + count += 1; + offset += 1; } + return count; +}; /** * Encode a string or binary to a Base64 encoded string. @@ -579,9 +580,9 @@ function count(string, pattern) { * @returns {String} the Base64 encoded string * @example strings.b64encode("foob"); // --> "Zm9vYg==" */ -function b64encode(string, encoding) { +const b64encode = exports.b64encode = (string, encoding) => { return base64.encode(string, encoding); -} +}; /** * Encode a string or binary to a Y64 encoded string. Y64 @@ -597,7 +598,7 @@ function b64encode(string, encoding) { * @see Detailed Y64 description * @example strings.y64encode("foob"); // --> "Zm9vYg--" */ -function y64encode(string, encoding) { +exports.y64encode = (string, encoding) => { return b64encode(string, encoding).replace(/[\+\=\/]/g, function(toReplace){ switch(toReplace){ case '+': return '.'; @@ -617,10 +618,9 @@ function y64encode(string, encoding) { * @example strings.b64decode("Zm9vYg=="); // --> "foob" * strings.b64decode("Zm9vYg==", "raw"); // --> [ByteArray 4] */ -function b64decode(string, encoding) { - if (!base64) base64 = require('ringo/base64'); +const b64decode = exports.b64decode = (string, encoding) => { return base64.decode(string, encoding); -} +}; /** * Decodes a Y64 encoded string to a string or byte array. @@ -631,7 +631,7 @@ function b64decode(string, encoding) { * @example strings.y64decode("Zm9vYg--"); // --> "foob" * strings.y64decode("Zm9vYg--", "raw"); // --> [ByteArray 4] */ -function y64decode(string, encoding) { +exports.y64decode = (string, encoding) => { return b64decode(string.replace(/[\.\-\_]/g, function(toReplace){ switch(toReplace){ case '.': return '+'; @@ -650,20 +650,20 @@ function y64decode(string, encoding) { * @returns {String} the Base16 encoded string * @example strings.b16encode("foo"); // --> "666F6F" */ -function b16encode(str, encoding) { +const b16encode = exports.b16encode = (str, encoding) => { encoding = encoding || 'utf8'; - var input = str instanceof Binary ? str : String(str).toByteString(encoding); - var length = input.length; - var result = []; - var chars = ['0', '1', '2', '3', '4', '5', '6', '7', + const input = str instanceof Binary ? str : String(str).toByteString(encoding); + const length = input.length; + const result = []; + const chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; - for (var i = 0; i < length; i++) { - var n = input[i]; + for (let i = 0; i < length; i++) { + let n = input[i]; result.push(chars[n >>> 4], chars[n & 0xf]); } return result.join(''); -} +}; /** * Decodes a Base16 encoded string to a string or byte array. @@ -674,26 +674,26 @@ function b16encode(str, encoding) { * @example strings.b16decode("666F6F"); // --> "foo" * strings.b16decode("666F6F", "raw"); // --> [ByteArray 3] */ -function b16decode(str, encoding) { - var input = str instanceof Binary ? str : String(str).toByteString('ascii'); - var length = input.length / 2; - var output = new ByteArray(length); +exports.b16decode = (str, encoding) => { + const input = str instanceof Binary ? str : String(str).toByteString('ascii'); + const length = input.length / 2; + const output = new ByteArray(length); - function decodeChar(c) { + const decodeChar = (c) => { if (c >= 48 && c <= 57) return c - 48; if (c >= 65 && c <= 70) return c - 55; if (c >= 97 && c <= 102) return c - 87; throw new Error('Invalid base16 character: ' + c); - } + }; - for (var i = 0; i < length; i++) { - var n1 = decodeChar(input[i * 2]); - var n2 = decodeChar(input[i * 2 + 1]); + for (let i = 0; i < length; i++) { + let n1 = decodeChar(input[i * 2]); + let n2 = decodeChar(input[i * 2 + 1]); output[i] = (n1 << 4) + n2; } encoding = encoding || 'utf8'; - return encoding == 'raw' ? output : output.decodeToString(encoding); -} + return (encoding === 'raw') ? output : output.decodeToString(encoding); +}; /** * Escape the string to make it safe for use within an HTML document. @@ -704,7 +704,7 @@ function b16decode(str, encoding) { * @example // returns "&lt;a href=&#39;foo&#39;&gt;bar&lt;/a&gt;" * strings.escapeHtml("<a href='foo'>bar</a>"); */ -function escapeHtml(string) { +exports.escapeHtml = (string) => { return String((string === null || string === undefined) ? '' : string) .replace(/&/g, '&') .replace(/"/g, '"') @@ -712,7 +712,7 @@ function escapeHtml(string) { .replace(/`/g, '`') .replace(/>/g, '>') .replace(/ { return str.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&"); -} +}; /** * Factory to create functions for sorting objects in an array. * @param {String} field name of the field each object is compared with * @param {Number} order (ascending or descending) * @returns {Function} ready for use in Array.prototype.sort - * @example var arr = [{ name: "Foo", age: 10 }, {name: "Bar", age: 20 }]; + * @example const arr = [{ name: "Foo", age: 10 }, {name: "Bar", age: 20 }]; * * // returns [ { name: 'Bar', age: 20 }, { name: 'Foo', age: 10 } ] - * var x = arr.sort(new Sorter("name", 1)); + * const x = arr.sort(new Sorter("name", 1)); * * // returns [ { name: 'Foo', age: 10 }, { name: 'Bar', age: 20 } ] * x.sort(new Sorter("name", -1)); */ -function Sorter(field, order) { - if (!order) - order = 1; - return function(a, b) { - var str1 = String(a[field] || '').toLowerCase(); - var str2 = String(b[field] || '').toLowerCase(); - if (str1 > str2) +exports.Sorter = (field, order) => { + order || (order = 1); + return (a, b) => { + const str1 = String(a[field] || '').toLowerCase(); + const str2 = String(b[field] || '').toLowerCase(); + if (str1 > str2) { return order; - if (str1 < str2) + } else if (str1 < str2) { return order * -1; + } return 0; }; -} +}; /** * Create a string from a bunch of substrings. @@ -761,9 +761,9 @@ function Sorter(field, order) { * @returns {String} the resulting string * @example strings.compose("foo", "bar", "baz"); // --> "foobarbaz" */ -function compose() { +exports.compose = function() { return Array.prototype.join.call(arguments, ''); -} +}; /** * Creates a random string (numbers and chars). @@ -776,51 +776,51 @@ function compose() { * strings.random(10, 1); // --> "bqpfj36tn4" * strings.random(10, 2); // --> 5492950742 */ -function random(len, mode) { - if (mode == 2) { - var x = Math.random() * Math.pow(10, len); - return Math.floor(x); +exports.random = (len, mode) => { + if (mode === 2) { + return Math.floor(Math.random() * Math.pow(10, len)); } - var keystr = ''; - for (var i = 0; i < len; i++) { - x = Math.floor((Math.random() * 36)); - if (mode == 1) { + let keystr = ""; + for (let i = 0; i < len; i++) { + let x = Math.floor((Math.random() * 36)); + if (mode === 1) { // skip 0,1 - x = (x<2) ? x + 2 : x; + x = (x < 2) ? x + 2 : x; // don't use the letters l (charCode 21+87) and o (24+87) - x = (x==21) ? 22 : x; - x = (x==24) ? 25 : x; + x = (x === 21) ? 22 : x; + x = (x === 24) ? 25 : x; } - if (x<10) { + if (x < 10) { keystr += String(x); } else { - keystr += String.fromCharCode(x+87); + keystr += String.fromCharCode(x + 87); } } return keystr; -} +}; /** * Append one string onto another and add some "glue" * if none of the strings is empty or null. - * @param {String} the first string - * @param {String} the string to be appended onto the first one - * @param {String} the "glue" to be inserted between both strings + * @param {String} str1 the first string + * @param {String} str2 the string to be appended onto the first one + * @param {String} str3 the "glue" to be inserted between both strings * @returns {String} the resulting string * @example strings.join("foo", "bar"); // "foobar" * strings.join("foo", "bar", "-"); // "foo-bar" * strings.join("foo", "", "-"); // "foo" */ -function join(str1, str2, glue) { - if (glue == null) +exports.join = (str1, str2, glue) => { + if (glue === null || glue === undefined) { glue = ''; - if (str1 && str2) + } + if (str1 && str2) { return str1 + glue + str2; - else if (str2) + } else if (str2) { return str2; - return str1; -} + }return str1; +}; /** * A simple string formatter. If the first argument is a format string @@ -838,18 +838,17 @@ function join(str1, str2, glue) { * // My age is 10! 20 30 * strings.format("My {} is {}!", "age", 10, 20, 30); */ -function format() { - if (arguments.length == 0) { +exports.format = function() { + if (arguments.length === 0) { return ""; } - var format = arguments[0]; - var index = 1; + let format = arguments[0]; + let index = 1; // Replace placehoder with argument as long as possible if (typeof format === "string") { if (contains(format, "{}") && arguments.length > 1) { - var args = arguments; - format = format.replace(/{}/g, function(m) { - return index < args.length ? args[index++] : m; + format = format.replace(/{}/g, (m) => { + return index < arguments.length ? arguments[index++] : m; }); } } else { @@ -861,7 +860,7 @@ function format() { } else { return format; } -} +}; /** * Returns true if the string is uppercase. @@ -870,9 +869,9 @@ function format() { * @example strings.isUpperCase("FOO"); // --> true * strings.isUpperCase("FOo"); // --> false */ -function isUpperCase(string) { +exports.isUpperCase = (string) => { return string.toUpperCase() === string; -} +}; /** * Returns true if the string is lowercase. @@ -881,9 +880,9 @@ function isUpperCase(string) { * @example strings.isLowerCase("foo"); // --> true * strings.isLowerCase("Foo"); // --> false */ -function isLowerCase(string) { +exports.isLowerCase = (string) => { return string.toLowerCase() === string; -} +}; /** * Returns true if the string is an integer literal. @@ -898,7 +897,7 @@ function isLowerCase(string) { * strings.isInt("0123"); // --> false * strings.isInt("bar"); // --> false */ -function isInt(string) { +exports.isInt = (string) => { return INT.test(string); }; @@ -915,7 +914,7 @@ function isInt(string) { * strings.isFloat("foo"); // --> false * strings.isFloat("0"); // --> false */ -function isFloat(string) { +exports.isFloat = (string) => { return string !== '' && FLOAT.test(string) && !INT.test(string); }; @@ -949,52 +948,6 @@ function isFloat(string) { * // false, since strict parsing with lenient=false * strings.isDate("20-40-2016", "MM-dd-yyyy", "en", "UTC", false); */ -function isDate(string, format, locale, timezone, lenient) { +exports.isDate = (string, format, locale, timezone, lenient) => { return !isNaN(dates.parse(string, format, locale, timezone, lenient)); -} - -module.exports.isDateFormat = isDateFormat; -module.exports.toDate = toDate; -module.exports.isUrl = isUrl; -module.exports.isFileName = isFileName; -module.exports.toFileName = toFileName; -module.exports.isHexColor = isHexColor; -module.exports.toHexColor = toHexColor; -module.exports.isAlphanumeric = isAlphanumeric; -module.exports.toAlphanumeric = toAlphanumeric; -module.exports.isAlpha = isAlpha; -module.exports.isNumeric = isNumeric; -module.exports.toCamelCase = toCamelCase; -module.exports.toDashes = toDashes; -module.exports.toUnderscores = toUnderscores; -module.exports.capitalize = capitalize; -module.exports.titleize = titleize; -module.exports.entitize = entitize; -module.exports.group = group; -module.exports.digest = digest; -module.exports.repeat = repeat; -module.exports.startsWith = startsWith; -module.exports.endsWith = endsWith; -module.exports.pad = pad; -module.exports.contains = contains; -module.exports.getCommonPrefix = getCommonPrefix; -module.exports.isEmail = isEmail; -module.exports.count = count; -module.exports.b16encode = b16encode; -module.exports.b16decode = b16decode; -module.exports.b64encode = b64encode; -module.exports.b64decode = b64decode; -module.exports.y64encode = y64encode; -module.exports.y64decode = y64decode; -module.exports.escapeHtml = escapeHtml; -module.exports.escapeRegExp = escapeRegExp; -module.exports.Sorter = Sorter; -module.exports.compose = compose; -module.exports.random = random; -module.exports.join = join; -module.exports.format = format; -module.exports.isUpperCase = isUpperCase; -module.exports.isLowerCase = isLowerCase; -module.exports.isInt = isInt; -module.exports.isFloat = isFloat; -module.exports.isDate = isDate; +}; diff --git a/test/ringo/utils/strings_test.js b/test/ringo/utils/strings_test.js index 98d4f993f..d7aca9030 100644 --- a/test/ringo/utils/strings_test.js +++ b/test/ringo/utils/strings_test.js @@ -1,5 +1,5 @@ -var assert = require('assert'); -var strings = require('ringo/utils/strings'); +const assert = require('assert'); +const strings = require('ringo/utils/strings'); const DATE_FORMAT = 'MM\'/\'dd\'/\'yyyy'; const DATE = '10/10/2010'; @@ -26,11 +26,11 @@ exports.testIsDateFormat = function () { }; exports.testToDate = function () { - var date = strings.toDate(DATE, DATE_FORMAT); + const date = strings.toDate(DATE, DATE_FORMAT); assert.isTrue(date instanceof Date); assert.deepEqual(new Date(DATE), date); - assert.throws(function () strings.toDate(FOO), - java.lang.IllegalArgumentException); // Invalid date format. + assert.throws(() => strings.toDate(FOO), + java.lang.IllegalArgumentException); // Invalid date format. }; exports.testIsUrl = function () { @@ -122,7 +122,7 @@ exports.testIsFileName = function () { }; exports.testToFileName = function () { - var fileName = strings.toFileName(URL); + const fileName = strings.toFileName(URL); assert.isNotNull(fileName); assert.isTrue(strings.isFileName(fileName)); }; @@ -144,7 +144,7 @@ exports.testIsAlphanumeric = function () { }; exports.testToAlphanumeric = function () { - var alphanumeric = strings.toAlphanumeric(URL); + const alphanumeric = strings.toAlphanumeric(URL); assert.isNotNull(alphanumeric); assert.isTrue(strings.isAlphanumeric(alphanumeric)); }; @@ -281,13 +281,13 @@ exports.testB64Decode = function () { }; exports.testB64EncodeDecode = function() { - for each (var test in BASE16) { + BASE16.forEach(test => { assert.strictEqual(strings.b16encode(test[0]), test[1]); assert.strictEqual(strings.b16decode(strings.b16encode(test[0])), test[0]); assert.deepEqual(strings.b16decode( strings.b16encode(test[0]), 'raw').toArray(), new ByteString(test[0], 'utf8').toArray()); - } + }); }; exports.testEscapeHtml = function () { @@ -456,4 +456,4 @@ exports.testIsDate = function() { if (require.main === module) { require('system').exit(require("test").run(module.id)); -} \ No newline at end of file +} From d406b5fb14a32fb08fa62b0edeb47a69ead209a2 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Tue, 3 Nov 2020 10:51:30 +0100 Subject: [PATCH 39/52] stack traces now exclude the test module too, code modernization --- modules/ringo/utils/test.js | 79 +++++++++++++++---------------------- 1 file changed, 31 insertions(+), 48 deletions(-) diff --git a/modules/ringo/utils/test.js b/modules/ringo/utils/test.js index cf411eb06..627455418 100644 --- a/modules/ringo/utils/test.js +++ b/modules/ringo/utils/test.js @@ -1,21 +1,23 @@ -var strings = require("ringo/utils/strings"); +const strings = require("ringo/utils/strings"); + +const indent = (lvl) => strings.repeat(" ", lvl); +const quote = (str) => JSON.stringify(str.toString()); /** * Converts the value passed as argument into a nicely formatted and * indented string * @param {Object} value The value to convert into a string * @param {Number} lvl Optional indentation level (defaults to zero) - * @returns The string representation of the object passed as argument - * @type String + * @returns {String} The string representation of the object passed as argument */ -const jsDump = exports.jsDump = function jsDump(value, lvl) { +const jsDump = exports.jsDump = (value, lvl) => { if (!lvl) { lvl = 0; } - + let buf; switch (getType(value)) { case "string": - return jsDump.quote(value); + return quote(value); case "boolean": case "number": case "nan": @@ -31,41 +33,26 @@ const jsDump = exports.jsDump = function jsDump(value, lvl) { } return value.toSource(); case "array": - var buf = value.map(function(val) { - return jsDump.indent(lvl + 1) + jsDump(val, lvl + 1); - }); - return ["[", buf.join(",\n"), jsDump.indent(lvl) + "]"].join("\n"); + buf = value.map(val => indent(lvl + 1) + jsDump(val, lvl + 1)); + return ["[", buf.join(",\n"), indent(lvl) + "]"].join("\n"); case "object": - var buf = []; - for (var propName in value) { - buf.push(jsDump.indent(lvl + 1) + '"' + propName + '": ' + jsDump(value[propName], lvl + 1)); - } - return ["{", buf.join(",\n"), jsDump.indent(lvl) + "}"].join("\n"); + buf = Object.keys(value).map(key => { + return indent(lvl + 1) + '"' + + key + '": ' + + jsDump(value[key], lvl + 1); + }); + return ["{", buf.join(",\n"), indent(lvl) + "}"].join("\n"); case "java": return ''; } -} -/** - * @ignore - */ -jsDump.indent = function(lvl) { - return strings.repeat(" ", lvl); -}; - -/** - * @ignore - */ -jsDump.quote = function(str) { - return JSON.stringify(str.toString()); }; /** * Returns the type of the object passed as argument. * @param {Object} obj - * @returns The type of the object passed as argument - * @type String + * @returns {String} The type of the object passed as argument */ -const getType = exports.getType = function getType(obj) { +const getType = exports.getType = (obj) => { if (typeof(obj) === "string") { return "string"; } else if (typeof(obj) === "boolean") { @@ -88,34 +75,30 @@ const getType = exports.getType = function getType(obj) { return "java"; } return "object"; -} +}; /** * Creates a stack trace and parses it for display. - * @param {java.lang.StackTraceElement} trace The trace to parse. If not given - * a stacktrace will be generated - * @returns The parsed stack trace - * @type String + * @param {java.lang.StackTraceElement} trace Optional stacktrace to parse. + * If undefined a stacktrace will be generated + * @returns {String} The parsed stack trace */ -const getStackTrace = exports.getStackTrace = function getStackTrace(trace) { +exports.getStackTrace = (trace) => { // create exception and fill in stack trace if (!trace) { - var ex = new Packages.org.mozilla.javascript.EvaluatorException(""); + const ex = new org.mozilla.javascript.EvaluatorException(""); ex.fillInStackTrace(); trace = ex.getScriptStack(); } - var stack = []; - var el, fileName, lineNumber; - for (var i = 0; i < trace.length; i += 1) { - el = trace[i]; + return trace.reduce((stack, el) => { if (el.fileName != null && el.lineNumber > -1) { // exclude all lines containing the unittest module itself - // FIXME (ro): this is quite ugly, but it works ... - if (el.fileName.indexOf(module.id) === 0 || el.fileName.indexOf("assert") === 0) { - continue; + if (!el.fileName.startsWith(module.id) && + !el.fileName.startsWith("assert.js") && + el.fileName !== "test.js") { + stack.push("at " + el.fileName + ":" + el.lineNumber); } - stack.push("at " + el.fileName + ":" + el.lineNumber); } - } - return stack; + return stack; + }, []); }; From 7d999ba854996014be610384f2f4df1d00a216df Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Tue, 3 Nov 2020 10:54:48 +0100 Subject: [PATCH 40/52] code modernization --- modules/ringo/logging.js | 2 +- modules/ringo/profiler.js | 4 ++-- modules/ringo/subprocess.js | 6 +++--- modules/ringo/utils/dates.js | 12 ++++++------ modules/ringo/utils/numbers.js | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/ringo/logging.js b/modules/ringo/logging.js index 0879133b4..463d04146 100644 --- a/modules/ringo/logging.js +++ b/modules/ringo/logging.js @@ -124,7 +124,7 @@ function Logger(name, impl) { * repeatedly checks the resource for updates. */ const setConfig = exports.setConfig = function(resource) { - var logContext = org.apache.logging.log4j.LogManager.getContext(false); + const logContext = org.apache.logging.log4j.LogManager.getContext(false); logContext.setConfigLocation(new java.net.URI(resource.url)); logContext.updateLoggers(); configured = module.singleton("configured", () => true); diff --git a/modules/ringo/profiler.js b/modules/ringo/profiler.js index 03391e9fd..7269d23fa 100644 --- a/modules/ringo/profiler.js +++ b/modules/ringo/profiler.js @@ -189,7 +189,7 @@ const Profiler = exports.Profiler = function() { const commonPrefix = list.reduce((previous, current) => { return strings.getCommonPrefix(previous, current.name); }, ""); - var lines = []; + const lines = []; let maxLength = 0; list.forEach(item => { const str = item.renderLine(commonPrefix.length); @@ -210,7 +210,7 @@ const Profiler = exports.Profiler = function() { return this.formatResult(null); }; - var profiler = new org.ringojs.util.DebuggerBase(this); + const profiler = new org.ringojs.util.DebuggerBase(this); profiler.debuggerScript = module.id + ".js"; return profiler; } diff --git a/modules/ringo/subprocess.js b/modules/ringo/subprocess.js index ca0c4cf20..27965b0df 100644 --- a/modules/ringo/subprocess.js +++ b/modules/ringo/subprocess.js @@ -120,11 +120,11 @@ const createProcess = exports.createProcess = function(args) { * Executes a given command and returns the standard output. * If the exit status is non-zero, throws an Error. Examples: * - *
    var {command} = require("ringo/subprocess");
    + *
    const {command} = require("ringo/subprocess");
    * // get PATH environment variable on Unix-like systems - * var path = command("/bin/bash", "-c", "echo $PATH");
    + * const path = command("/bin/bash", "-c", "echo $PATH");
    * // a simple ping - * var result = command("ping", "-c 1", "ringojs.org"); + * const result = command("ping", "-c 1", "ringojs.org"); *
    * * @param {String} command command to call in the runtime environment diff --git a/modules/ringo/utils/dates.js b/modules/ringo/utils/dates.js index 7f8fd1c4b..0066454f7 100644 --- a/modules/ringo/utils/dates.js +++ b/modules/ringo/utils/dates.js @@ -17,9 +17,9 @@ /** * @fileoverview Adds useful functions for working with JavaScript Date objects. - * @example var dates = require("ringo/utils/dates"); - * var now = new Date(2016, 0, 1); - * var y2k = new Date(2000, 0, 1); + * @example const dates = require("ringo/utils/dates"); + * const now = new Date(2016, 0, 1); + * const y2k = new Date(2000, 0, 1); * * dates.after(now, y2k); // --> true * dates.before(now, y2k); // --> false @@ -60,7 +60,7 @@ const createGregorianCalender = (date, locale) => { * is used. * @returns {String} the formatted Date * @see java.text.SimpleDateFormat - * @example var y2k = new Date(Date.UTC(2000, 0, 1)); + * @example const y2k = new Date(Date.UTC(2000, 0, 1)); * // "year 2000" * dates.format(y2k, "'year' yyyy"); * // "Samstag, Januar 1, '00" @@ -121,8 +121,8 @@ exports.checkDate = (fullYear, month, day) => { * millisecond, and their respective plural form. * @returns {Date} date with the calculated date and time * @see java.util.GregorianCalendar add() - * @example var d1 = new Date(Date.UTC(2016, 0, 1, 0, 0)); - * var d2 = dates.add(d1, 1, "hour"); + * @example const d1 = new Date(Date.UTC(2016, 0, 1, 0, 0)); + * const d2 = dates.add(d1, 1, "hour"); * dates.diff(d1, d2, "hours"); // --> 1 */ exports.add = (date, delta, unit) => { diff --git a/modules/ringo/utils/numbers.js b/modules/ringo/utils/numbers.js index 65eba2459..ef8927210 100644 --- a/modules/ringo/utils/numbers.js +++ b/modules/ringo/utils/numbers.js @@ -9,7 +9,7 @@ * @param {java.util.Locale} locale optional locale * @returns {String} the number formatted as string * @see java.text.DecimalFormat - * @example >> var numbers = require('ringo/utils/numbers'); + * @example >> const numbers = require('ringo/utils/numbers'); * >> numbers.format(123, "#,###,##0.00"); // uses the default locale * '123.00' * >> numbers.format(123, "#,###,##0.00", java.util.Locale.GERMAN); @@ -29,7 +29,7 @@ exports.format = (number, fmt, locale) => { * Invoke a function `num` times, passing 0 .. (this - 1) as argument. * @param {Number} num the number * @param {Function} fun the function to call - * @example var numbers = require('ringo/utils/numbers'); + * @example const numbers = require('ringo/utils/numbers'); * numbers.times(5, function(i) { * console.log("#" + i); * }); From 81ed2705a1f03d5c996f605d131a809695e3cb74 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Tue, 3 Nov 2020 11:06:20 +0100 Subject: [PATCH 41/52] #409 implemented binary.toByteString() as replacement of the (now deprecated) String.prototype.toByteString() method --- modules/binary.js | 26 ++++++++++++++++++++++++++ modules/io.js | 3 ++- modules/net.js | 2 +- modules/ringo/jsgi/connector.js | 2 +- modules/ringo/utils/strings.js | 7 ++++--- 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/modules/binary.js b/modules/binary.js index 52116ad3c..cf64d731a 100644 --- a/modules/binary.js +++ b/modules/binary.js @@ -80,11 +80,36 @@ exports.ByteArray = ByteArray; */ exports.ByteString = ByteString; +/** + * Converts the String to a mutable ByteArray using the specified encoding. + * @param {String} string The string to convert into a ByteArray + * @param {String} charset the name of the string encoding. Defaults to 'UTF-8' + * @returns {ByteArray} a ByteArray representing the string + * @example const binary = require("binary"); + * const ba = binary.toByteArray("hello world"); + */ +exports.toByteArray = (string, charset) => { + return new ByteArray(String(string), charset || 'utf8'); +}; + +/** + * Converts the String to an immutable ByteString using the specified encoding. + * @param {String} string The string to convert into a ByteString + * @param {String} charset the name of the string encoding. Defaults to 'UTF-8' + * @returns {ByteString} a ByteString representing the string + * @example const binary = require("binary"); + * const bs = binary.toByteString("hello world"); + */ +exports.toByteString = (string, charset) => { + return new ByteArray(String(string), charset || 'utf8'); +}; + /** * Converts the String to a mutable ByteArray using the specified encoding. * @param {String} charset the name of the string encoding. Defaults to 'UTF-8' * @returns {ByteArray} a ByteArray representing the string * @example const ba = "hello world".toByteArray(); + * @deprecated */ Object.defineProperty(String.prototype, 'toByteArray', { value: function(charset) { @@ -98,6 +123,7 @@ Object.defineProperty(String.prototype, 'toByteArray', { * @param {String} charset the name of the string encoding. Defaults to 'UTF-8' * @returns {ByteString} a ByteString representing the string * @example const bs = "hello world".toByteString(); + * @deprecated */ Object.defineProperty(String.prototype, 'toByteString', { value: function(charset) { diff --git a/modules/io.js b/modules/io.js index f8426952f..b24c285b1 100644 --- a/modules/io.js +++ b/modules/io.js @@ -11,6 +11,7 @@ */ const {Encoder, Decoder} = require("ringo/encoding"); +const binary = require("binary"); defineClass(org.ringojs.wrappers.Stream); @@ -214,7 +215,7 @@ exports.MemoryStream = function MemoryStream(binaryOrNumber) { if (typeof source === "string") { require("system").stderr.print("Warning: binary write called with string argument. " + "Using default encoding"); - source = source.toByteString(); + source = binary.toByteString(source); } if (!(source instanceof Binary)) { throw new Error("write(): first argument must be binary"); diff --git a/modules/net.js b/modules/net.js index e1db44dd1..924efb7a9 100644 --- a/modules/net.js +++ b/modules/net.js @@ -209,7 +209,7 @@ const DatagramSocket = exports.DatagramSocket = function() { if (arg instanceof binary.Binary) { return new java.net.DatagramPacket(arg, arg.length); } else if (typeof arg === "string") { - return new java.net.DatagramPacket(arg.toByteString(), arg.length); + return new java.net.DatagramPacket(binary.toByteString(arg), arg.length); } else { throw new Error("Unsupported argument to send: " + arg); } diff --git a/modules/ringo/jsgi/connector.js b/modules/ringo/jsgi/connector.js index 43761b1a3..29b829bc1 100644 --- a/modules/ringo/jsgi/connector.js +++ b/modules/ringo/jsgi/connector.js @@ -130,7 +130,7 @@ const writeBody = (response, body, charset) => { const output = response.getOutputStream(); body.forEach(part => { if (!(part instanceof binary.Binary)) { - part = part.toByteString(charset); + part = binary.toByteString(part, charset); } output.write(part); }); diff --git a/modules/ringo/utils/strings.js b/modules/ringo/utils/strings.js index 27f877d92..0fb2c67fb 100644 --- a/modules/ringo/utils/strings.js +++ b/modules/ringo/utils/strings.js @@ -65,6 +65,7 @@ const URLPATTERN = java.util.regex.Pattern.compile("^" + const INT = /^(?:[-+]?(?:0|[1-9][0-9]*))$/; const FLOAT = /^(?:[-+]?(?:[0-9]*))(?:\.[0-9]*)?(?:[eE][+\-]?(?:[0-9]+))?$/; +const binary = require('binary'); const base64 = require('ringo/base64'); const dates = require('ringo/utils/dates'); @@ -402,7 +403,7 @@ exports.group = (string, interval, str, ignoreWhiteSpace) => { */ exports.digest = (string, algorithm) => { const md = java.security.MessageDigest.getInstance(algorithm || 'MD5'); - const b = ByteString.wrap(md.digest(string.toByteString())); + const b = ByteString.wrap(md.digest(binary.toByteString(string))); return b16encode(b); }; @@ -652,7 +653,7 @@ exports.y64decode = (string, encoding) => { */ const b16encode = exports.b16encode = (str, encoding) => { encoding = encoding || 'utf8'; - const input = str instanceof Binary ? str : String(str).toByteString(encoding); + const input = str instanceof Binary ? str : binary.toByteString(String(str), encoding); const length = input.length; const result = []; const chars = ['0', '1', '2', '3', '4', '5', '6', '7', @@ -675,7 +676,7 @@ const b16encode = exports.b16encode = (str, encoding) => { * strings.b16decode("666F6F", "raw"); // --> [ByteArray 3] */ exports.b16decode = (str, encoding) => { - const input = str instanceof Binary ? str : String(str).toByteString('ascii'); + const input = str instanceof Binary ? str : binary.toByteString(String(str), 'ascii'); const length = input.length / 2; const output = new ByteArray(length); From d5547a4635bd59550c6a147a6342465b162034c9 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Tue, 3 Nov 2020 11:06:31 +0100 Subject: [PATCH 42/52] minor: simplified named exports --- modules/ringo/buffer.js | 2 +- modules/ringo/encoding.js | 2 +- modules/ringo/zip.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ringo/buffer.js b/modules/ringo/buffer.js index 635af62e3..5f4605753 100644 --- a/modules/ringo/buffer.js +++ b/modules/ringo/buffer.js @@ -10,7 +10,7 @@ const strings = require('ringo/utils/strings'); * as a simple wrapper around a JavaScript array. * @param {*...} args... initial parts to write to the buffer */ -module.exports.Buffer = function Buffer() { +exports.Buffer = function Buffer() { const content = []; let length = 0; diff --git a/modules/ringo/encoding.js b/modules/ringo/encoding.js index 6b6ea7d83..e0cb052ee 100644 --- a/modules/ringo/encoding.js +++ b/modules/ringo/encoding.js @@ -285,7 +285,7 @@ exports.Decoder = function Decoder(charset, strict, capacity) { * @param {Number} capacity initial capacity for the input character buffer and output byte buffer. * The binary buffer's size depends on the average bytes used per character by the charset. */ -module.exports.Encoder = function Encoder(charset, strict, capacity) { +exports.Encoder = function Encoder(charset, strict, capacity) { if (!(this instanceof Encoder)) { return new Encoder(charset, strict, capacity); diff --git a/modules/ringo/zip.js b/modules/ringo/zip.js index 30104331c..c70885a0c 100644 --- a/modules/ringo/zip.js +++ b/modules/ringo/zip.js @@ -96,7 +96,7 @@ exports.ZipFile = function(path) { * @param {Stream|String} resource an input stream or file name * @see #ZipFile */ -module.exports.ZipIterator = function*(resource) { +exports.ZipIterator = function*(resource) { const zipStream = new ZipInputStream((typeof resource == "string") ? fs.openRaw(resource) : resource); const stream = new io.Stream(zipStream); From d43a229e2af305b6cde1a0dcf507299492caad94 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Tue, 3 Nov 2020 13:19:15 +0100 Subject: [PATCH 43/52] regression fix: short option can be null/undefined --- modules/ringo/args.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ringo/args.js b/modules/ringo/args.js index f69911f66..5565120b3 100644 --- a/modules/ringo/args.js +++ b/modules/ringo/args.js @@ -134,7 +134,7 @@ exports.Parser = function() { * @returns {Object} this parser for chained invocation */ this.addOption = function(shortName, longName, argument, helpText) { - if (typeof(shortName) !== "string" || shortName.length !== 1) { + if (typeof(shortName) === "string" && shortName.length !== 1) { throw new Error("Short option must be a string of length 1"); } longName = longName || ""; From bc00d84c6ff5191eecc6e346d9d1f87429011692 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Tue, 3 Nov 2020 15:32:31 +0100 Subject: [PATCH 44/52] modified prototype construction of AssertionError and ArgumentsError (jsdoc rendered the constructor property) --- modules/assert.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/assert.js b/modules/assert.js index 21a93152b..029894673 100644 --- a/modules/assert.js +++ b/modules/assert.js @@ -189,8 +189,9 @@ const AssertionError = exports.AssertionError = function AssertionError(options) }; /** @ignore */ -AssertionError.prototype = Object.create(Error.prototype); -AssertionError.prototype.constructor = AssertionError; +AssertionError.prototype = Object.create(Error.prototype, { + "constructor": {"value": AssertionError} +}); /** @ignore */ AssertionError.toString = function() { @@ -225,8 +226,9 @@ const ArgumentsError = exports.ArgumentsError = function ArgumentsError(message) } /** @ignore */ -ArgumentsError.prototype = Object.create(Error.prototype); -ArgumentsError.prototype.constructor = ArgumentsError; +ArgumentsError.prototype = Object.create(Error.prototype, { + "constructor": {"value": ArgumentsError} +}); /** @ignore */ ArgumentsError.toString = function() { From de3e2e47e15a9ae458caa249f50e6c74bf7c2c8d Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Wed, 4 Nov 2020 08:26:30 +0100 Subject: [PATCH 45/52] regression fix: printResult and printError must be declared as local const variables, otherwise RingoShell class is unable to invoke them. --- modules/ringo/shell.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ringo/shell.js b/modules/ringo/shell.js index 8d1681d26..bebbfa565 100644 --- a/modules/ringo/shell.js +++ b/modules/ringo/shell.js @@ -200,7 +200,7 @@ const convert = (value, nesting, visited) => { * @param {Object} value * @param {Stream} writer */ -exports.printResult = (value, writer) => { +const printResult = exports.printResult = (value, writer) => { if (typeof value !== "undefined") { writer = writer || term; printValue(convert(value, 0, []), writer, 0); @@ -269,7 +269,7 @@ const printValue = (value, writer, nesting) => { * @param {Array} errors * @param {Boolean} verbose */ -exports.printError = (xcept, errors, verbose) => { +const printError = exports.printError = (xcept, errors, verbose) => { if (xcept instanceof org.mozilla.javascript.RhinoException) { term.writeln(term.BOLD, term.RED, xcept.details()); } else { From 556bcc70a456b73c3ff5691c2810001c4fcfb190 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Wed, 4 Nov 2020 09:08:31 +0100 Subject: [PATCH 46/52] regression fix: objects.merge() must handle null/undefined arguments removed hasOwnProperty() check since Object.keys() returns only own enumerable property names --- modules/ringo/utils/objects.js | 8 +++---- test/ringo/utils/objects_test.js | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/modules/ringo/utils/objects.js b/modules/ringo/utils/objects.js index 425a33a55..c1bfec7cc 100644 --- a/modules/ringo/utils/objects.js +++ b/modules/ringo/utils/objects.js @@ -196,11 +196,9 @@ exports.merge = function() { const result = {}; for (let i = arguments.length; i > 0; --i) { let obj = arguments[i - 1]; - Object.keys(obj).forEach(key => { - if (obj.hasOwnProperty(key)) { - result[key] = obj[key]; - } - }); + if (obj !== null && obj !== undefined) { + Object.keys(obj).forEach(key => result[key] = obj[key]); + } } return result; }; diff --git a/test/ringo/utils/objects_test.js b/test/ringo/utils/objects_test.js index 24898ceed..7ea0b004a 100644 --- a/test/ringo/utils/objects_test.js +++ b/test/ringo/utils/objects_test.js @@ -44,6 +44,42 @@ exports.testMerge = function() { assert.deepEqual(x, {a: 1, b: 2}); assert.deepEqual(y, {b: 3, c: 4}); assert.deepEqual(z, {c: 5, d: 6}); + + // null/undefined args + [null, undefined].forEach(value => { + assert.deepEqual(merge(value, x), {a: 1, b: 2}); + assert.deepEqual(merge(x, value), {a: 1, b: 2}); + assert.deepEqual(merge(value, x, y), {a: 1, b: 2, c: 4}); + assert.deepEqual(merge(x, value, y), {a: 1, b: 2, c: 4}); + assert.deepEqual(merge(x, y, value), {a: 1, b: 2, c: 4}); + }); + + // only include own enumerable properties + const Base = function() { + Object.defineProperties(this, { + "baseName": { + "value": "base", + "enumerable": true + } + }); + return this; + }; + const Extend = function(name) { + Object.defineProperties(this, { + "name": { + "value": name, + "enumerable": true + }, + "nonenumerable": { + "value": "excluded" + } + }); + return this; + }; + Extend.prototype = Object.create(Base.prototype, { + "constructor": {"value": Extend} + }); + assert.deepEqual(merge(new Extend("extend")), {"name": "extend"}); }; exports.testCloneNumber = function() { From 73a093ac6c4f07ed410486e71182e87d6355c3e1 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Wed, 4 Nov 2020 12:21:55 +0100 Subject: [PATCH 47/52] fixed variable declaration --- modules/ringo/shell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ringo/shell.js b/modules/ringo/shell.js index bebbfa565..360735f36 100644 --- a/modules/ringo/shell.js +++ b/modules/ringo/shell.js @@ -174,7 +174,7 @@ const convert = (value, nesting, visited) => { let keys = Object.keys(value); count = 0; for (let i = 0; i < keys.length; i++) { - part = convert(value[keys[i]], nesting + 1, visited); + let part = convert(value[keys[i]], nesting + 1, visited); count += String(keys[i]).length + 4; count += part.string && part.string.length || part.count || 0; retval.items.push({ From 7b34b34414e9f49e921b45752b8c109f3cc07399 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Wed, 4 Nov 2020 12:31:40 +0100 Subject: [PATCH 48/52] added worker test --- test/all.js | 1 + test/ringo/worker/worker.js | 18 ++++++++++ test/ringo/worker/worker_test.js | 60 ++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 test/ringo/worker/worker.js create mode 100644 test/ringo/worker/worker_test.js diff --git a/test/all.js b/test/all.js index cc7bdf79f..8055dff6f 100644 --- a/test/all.js +++ b/test/all.js @@ -14,6 +14,7 @@ exports.testPromise = require('./ringo/promise_test'); exports.testScheduler = require('./ringo/scheduler_test'); exports.testSubProcess = require('./ringo/subprocess_test'); exports.testWebSocket = require('./ringo/websocket_test'); +exports.testWorker = require('./ringo/worker/worker_test'); exports.testZip = require('./ringo/zip_test'); exports.testUtils = require('./ringo/utils/all'); exports.testFile = require('./file/all'); diff --git a/test/ringo/worker/worker.js b/test/ringo/worker/worker.js new file mode 100644 index 000000000..1baf27260 --- /dev/null +++ b/test/ringo/worker/worker.js @@ -0,0 +1,18 @@ +const onmessage = (event) => { + const {method, payload} = event.data; + switch (method) { + case "postMessage": + event.source.postMessage(payload); + break; + case "postError": + event.source.postError(payload); + break; + case "timeoutError": + setTimeout(() => { + throw new Error("Error thrown in worker timeout"); + }, 10); + break; + case "throwError": + throw new Error("Error thrown in worker"); + } +} diff --git a/test/ringo/worker/worker_test.js b/test/ringo/worker/worker_test.js new file mode 100644 index 000000000..97ec669f8 --- /dev/null +++ b/test/ringo/worker/worker_test.js @@ -0,0 +1,60 @@ +const assert = require("assert"); +const system = require("system"); +const {Worker} = require("ringo/worker"); +const {Semaphore} = require("ringo/concurrent"); + +exports.testPostMessage = () => { + const worker = new Worker(module.resolve("./worker")); + const semaphore = new Semaphore(); + const payload = {"one": 1, "two": null}; + let received = null; + try { + worker.onmessage = (event) => { + received = event.data; + semaphore.signal(); + }; + worker.onerror = (event) => { + received = event.data; + semaphore.signal(); + }; + + // postMessage + worker.postMessage({ + "method": "postMessage", + "payload": payload + }, true); + assert.isTrue(semaphore.tryWait(100)); + assert.deepEqual(received, payload); + + // postError + worker.postMessage({ + "method": "postError", + "payload": payload + }, true); + assert.isTrue(semaphore.tryWait(100)); + assert.deepEqual(received, payload); + + // errors thrown by worker must be received in onerror callback + worker.postMessage({ + "method": "throwError" + }, true); + assert.isTrue(semaphore.tryWait(100)); + assert.isTrue(received instanceof Error); + assert.strictEqual(received.message, "Error thrown in worker"); + + // errors thrown by worker in setTimeout + worker.postMessage({ + "method": "timeoutError" + }, true); + assert.isTrue(semaphore.tryWait(100)); + assert.isTrue(received instanceof Error); + assert.strictEqual(received.message, "Error thrown in worker timeout"); + } finally { + worker.terminate(); + } +}; + +if (require.main == module.id) { + system.exit(require("test").run.apply(null, + [exports].concat(system.args.slice(1)))); +} From 2da80dcb4fa6d62acab93d6f01bb92aed136dd15 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Wed, 4 Nov 2020 12:57:22 +0100 Subject: [PATCH 49/52] fixed write/writeln method binding --- examples/file-term.js | 12 ++++++------ modules/ringo/term.js | 8 ++++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/examples/file-term.js b/examples/file-term.js index c12ff8577..bda07fc12 100644 --- a/examples/file-term.js +++ b/examples/file-term.js @@ -1,14 +1,14 @@ -var fs = require('fs'); -var {GREEN, BLUE, writeln} = require('ringo/term'); +const fs = require('fs'); +const {GREEN, BLUE, writeln, RESET} = require('ringo/term'); -var filename = module.path; +const filename = module.path; // text streams have an iterator that reads the next line -var file = fs.open(filename); // text mode +let file = fs.open(filename); // text mode file.forEach(function(line) { - writeln(GREEN, line); + writeln(GREEN, line, RESET); }); // binary streams read into ByteArrays/ByteStrings file = fs.open(filename, {binary: true}); -writeln(BLUE, file.read()) +writeln(BLUE, file.read(), RESET) diff --git a/modules/ringo/term.js b/modules/ringo/term.js index 37c2fffa8..4bc6bb74f 100644 --- a/modules/ringo/term.js +++ b/modules/ringo/term.js @@ -127,12 +127,16 @@ const tw = new TermWriter(); * support has been detected. * @param {*...} args... variable number of arguments to write */ -exports.write = tw.write; +exports.write = function() { + tw.write.apply(tw, arguments); +}; /** * Write the arguments to `system.stdout` followed by a newline character, * applying ANSI terminal colors if support has been detected. * @param {*...} args... variable number of arguments to write */ -exports.writeln = tw.writeln; +exports.writeln = function() { + tw.writeln.apply(tw, arguments); +}; From 18bb889027906a560d69ef5e6f825801bcedef15 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Wed, 4 Nov 2020 13:06:10 +0100 Subject: [PATCH 50/52] reverted change to arrow functions to maintain correct scope --- modules/ringo/jsgi/connector.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ringo/jsgi/connector.js b/modules/ringo/jsgi/connector.js index 29b829bc1..7e30b6ac6 100644 --- a/modules/ringo/jsgi/connector.js +++ b/modules/ringo/jsgi/connector.js @@ -214,12 +214,12 @@ exports.AsyncResponse = function(request, timeout) { const writeListener = new WriteListenerImpl(asyncContext); out.setWriteListener(writeListener); return { - "start": (status, headers) => { + "start": function(status, headers) { servletResponse.setStatus(status); writeHeaders(servletResponse, headers || {}); return this; }, - "write": (data, encoding) => { + "write": function(data, encoding) { if (asyncContext.getHttpChannelState().isResponseCompleted()) { throw new Error("AsyncResponse already closed"); } @@ -230,10 +230,10 @@ exports.AsyncResponse = function(request, timeout) { writeListener.onWritePossible(); return this; }, - "flush": () => { + "flush": function() { this.write(FLUSH); }, - "close": () => { + "close": function() { if (asyncContext.getHttpChannelState().isResponseCompleted()) { throw new Error("AsyncResponse already closed"); } From b8f35ce3615f4a9c3b19ed5c881532a998de28fc Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Wed, 4 Nov 2020 13:35:50 +0100 Subject: [PATCH 51/52] fixed & modernized examples --- examples/eventsource-server.js | 20 ++++++-------- examples/httpserver-app.js | 6 ++-- examples/httpserver-async-worker.js | 12 ++++---- examples/httpserver-async.js | 12 ++++---- examples/httpserver-default.js | 12 ++++---- examples/httpserver-fluent.js | 10 +++---- examples/httpserver-jettyxml.js | 8 +++--- examples/httpserver.js | 2 +- examples/parse-options.js | 13 ++++----- examples/promise-chain.js | 14 +++++----- examples/promise-fail.js | 12 ++++---- examples/swing.js | 15 +++++----- examples/websocket-server-push.js | 43 +++++++++++++++++------------ examples/websocket-server.js | 37 +++++++++++++++---------- examples/worker-fanout-semaphore.js | 24 ++++++++-------- examples/worker-fanout.js | 10 +++---- examples/worker-pingpong.js | 12 ++++---- examples/worker-semaphore.js | 26 +++++++++-------- examples/worker.js | 8 +++--- 19 files changed, 157 insertions(+), 139 deletions(-) diff --git a/examples/eventsource-server.js b/examples/eventsource-server.js index b19a0476f..e548e9987 100644 --- a/examples/eventsource-server.js +++ b/examples/eventsource-server.js @@ -1,15 +1,13 @@ // Simple event source server demo -var response = require("ringo/jsgi/response"); -var arrays = require("ringo/utils/arrays"); -var {EventSource, isEventSourceRequest} = require("ringo/jsgi/eventsource"); +const response = require("ringo/jsgi/response"); +const arrays = require("ringo/utils/arrays"); +const {EventSource, isEventSourceRequest} = require("ringo/jsgi/eventsource"); -var connections = module.singleton('connections', function() { - return []; -}); +const connections = module.singleton('connections', () => []); -exports.app = function(req) { +exports.app = (req) => { if (isEventSourceRequest(req)) { - var eventSource = new EventSource(req); + const eventSource = new EventSource(req); eventSource.start({ 'Access-Control-Allow-Origin': '*' }); @@ -20,7 +18,7 @@ exports.app = function(req) { } }; -function doPing() { +const doPing = () => { console.info("Sending ping to all ", connections.length ,"connections"); connections.forEach(function(eventSource) { try { @@ -33,6 +31,6 @@ function doPing() { } if (require.main == module) { - var server = require("ringo/httpserver").main(module.id); + const server = require("ringo/httpserver").main(module.id); setInterval(doPing, 2 * 1000); -} \ No newline at end of file +} diff --git a/examples/httpserver-app.js b/examples/httpserver-app.js index d367f6a16..9e3e49f67 100644 --- a/examples/httpserver-app.js +++ b/examples/httpserver-app.js @@ -1,5 +1,5 @@ -var response = require("ringo/jsgi/response"); +const response = require("ringo/jsgi/response"); -module.exports = function(req) { +module.exports = (req) => { return response.html("Hello World!"); -}; \ No newline at end of file +}; diff --git a/examples/httpserver-async-worker.js b/examples/httpserver-async-worker.js index 693e2da61..31dfd359e 100644 --- a/examples/httpserver-async-worker.js +++ b/examples/httpserver-async-worker.js @@ -1,11 +1,11 @@ -var fs = require("fs"); +const fs = require("fs"); -var onmessage = function(event) { - var {response, file} = event.data; - var stream = fs.openRaw(file); - var intervalId = setInterval(function() { +const onmessage = (event) => { + const {response, file} = event.data; + const stream = fs.openRaw(file); + const intervalId = setInterval(() => { try { - var buf = stream.read(4096); + const buf = stream.read(4096); if (buf.length > 0) { response.write(buf); response.flush(); diff --git a/examples/httpserver-async.js b/examples/httpserver-async.js index 4a14acbf7..776352918 100644 --- a/examples/httpserver-async.js +++ b/examples/httpserver-async.js @@ -1,8 +1,8 @@ -var {AsyncResponse} = require('ringo/jsgi/connector'); -var {Worker} = require("ringo/worker"); +const {AsyncResponse} = require('ringo/jsgi/connector'); +const {Worker} = require("ringo/worker"); -var worker = module.singleton("worker", function() { - var worker = new Worker(module.resolve("./httpserver-async-worker")); +const worker = module.singleton("worker", () => { + const worker = new Worker(module.resolve("./httpserver-async-worker")); worker.onmessage = function(event) { console.log('Got message from worker:', event.data); }; @@ -12,8 +12,8 @@ var worker = module.singleton("worker", function() { return worker; }); -exports.app = function(request) { - var response = new AsyncResponse(request, 0, true); +exports.app = (request) => { + const response = new AsyncResponse(request, 0, true); response.start(200, {'Content-Type': 'image/png'}); worker.postMessage({ "response": response, diff --git a/examples/httpserver-default.js b/examples/httpserver-default.js index f7af1f7d8..cef3ee9de 100644 --- a/examples/httpserver-default.js +++ b/examples/httpserver-default.js @@ -1,19 +1,19 @@ -var {HttpServer} = require("../lib/main"); +const {HttpServer} = require("ringo/httpserver"); -var httpServer = new HttpServer(); +const httpServer = new HttpServer(); httpServer.enableSessions({ "name": "myapp" }); // init the application context -var appContext = httpServer.serveApplication("/", module.resolve("./app"), { +const appContext = httpServer.serveApplication("/", module.resolve("./httpserver-app"), { "sessions": true }); // and add a websocket to it -appContext.addWebSocket("/events", function() {}); +appContext.addWebSocket("/events", () => {}); // initialize static file serving -var staticContext = httpServer.serveStatic("/static", module.resolve("./"), { +const staticContext = httpServer.serveStatic("/static", module.resolve("./"), { "allowDirectoryListing": true }); @@ -31,4 +31,4 @@ httpServer.createHttpsListener({ }); // start -httpServer.jetty.start(); \ No newline at end of file +httpServer.jetty.start(); diff --git a/examples/httpserver-fluent.js b/examples/httpserver-fluent.js index 49cfe4fd2..d5d460a6c 100644 --- a/examples/httpserver-fluent.js +++ b/examples/httpserver-fluent.js @@ -1,16 +1,16 @@ -var httpServer = require("../lib/main"); -var builder = httpServer.build() +const httpServer = require("ringo/httpserver"); +const builder = httpServer.build() // enable sessions with a custom node name .enableSessions({ "name": "test1" }) // serve application - .serveApplication("/", module.resolve("./app"), { + .serveApplication("/", module.resolve("./httpserver-app"), { "sessions": true }) // add websocket - this must be called after serveApplication // as it operates on the current context of the builder - .addWebSocket("/websocket", function() {}) + .addWebSocket("/websocket", () => {}) // static file serving .serveStatic("/static", module.resolve("./"), { "allowDirectoryListing": true @@ -27,4 +27,4 @@ var builder = httpServer.build() "keyManagerPassword": "secret" }) // start up the server - .start(); \ No newline at end of file + .start(); diff --git a/examples/httpserver-jettyxml.js b/examples/httpserver-jettyxml.js index a03c30052..b18706463 100644 --- a/examples/httpserver-jettyxml.js +++ b/examples/httpserver-jettyxml.js @@ -1,10 +1,10 @@ -var httpServer = require("../lib/main"); -var builder = httpServer.build("config/jetty.xml") +const httpServer = require("ringo/httpserver"); +const builder = httpServer.build("config/jetty.xml") // serve application - .serveApplication("/", module.resolve("./app")) + .serveApplication("/", module.resolve("./httpserver-app")) // static file serving .serveStatic("/static", module.resolve("./"), { "allowDirectoryListing": true }) // start up the server - .start(); \ No newline at end of file + .start(); diff --git a/examples/httpserver.js b/examples/httpserver.js index 5869cb506..253bcd421 100644 --- a/examples/httpserver.js +++ b/examples/httpserver.js @@ -1,6 +1,6 @@ // Minimal hello-world HTTP server demo -exports.app = function(req) { +exports.app = (req) => { return { status: 200, headers: {"Content-Type": "text/plain"}, diff --git a/examples/parse-options.js b/examples/parse-options.js index d32e5b275..5ca7f3a7d 100644 --- a/examples/parse-options.js +++ b/examples/parse-options.js @@ -1,14 +1,14 @@ -var {Parser} = require('ringo/args'); -var {RED, BLUE, YELLOW, BOLD, writeln} = require('ringo/term'); -var system = require('system'); +const {Parser} = require('ringo/args'); +const {RED, BLUE, YELLOW, BOLD, writeln} = require('ringo/term'); +const system = require('system'); -function main(args) { - var parser = new Parser(); +const main = (args) => { + const parser = new Parser(); parser.addOption('f', 'foo', null, 'Enable foo bit'); parser.addOption('b', 'bar', '[BAR-FACTOR]', 'Specify bar factor'); parser.addOption('h', 'help', null, 'Display help'); args.shift(); - var options = parser.parse(args); + const options = parser.parse(args); if (options.help) { writeln(BLUE, BOLD, 'Options:'); writeln(BLUE, parser.help()); @@ -23,7 +23,6 @@ function main(args) { if (!Object.keys(options).length) { writeln(BOLD, "Run with -h/--help to see available options"); } - } if (require.main === module) { diff --git a/examples/promise-chain.js b/examples/promise-chain.js index b796b3544..3a503a3fe 100644 --- a/examples/promise-chain.js +++ b/examples/promise-chain.js @@ -6,21 +6,21 @@ * in the chain as soon as it is resolved. */ -var {Deferred} = require('ringo/promise'); +const {Deferred} = require('ringo/promise'); -var deferred = new Deferred(); +const deferred = new Deferred(); -deferred.promise.then(function(val) { +deferred.promise.then(val => { print('Step 1:', val); return val.toUpperCase(); -}).then(function(val) { +}).then(val => { print('Step 2:', val); - var d = new Deferred(); + const d = new Deferred(); d.resolve(val.split(' ').join(' CRUEL ')); return d.promise; -}).then(function(val) { +}).then(val => { print('Step 3:', val); -}, function(err) { +}, err => { print('Failed:', err); }); diff --git a/examples/promise-fail.js b/examples/promise-fail.js index 116e78501..85e61d926 100644 --- a/examples/promise-fail.js +++ b/examples/promise-fail.js @@ -1,20 +1,20 @@ /* * This example demonstrates chaining of error handlers with promises. - * An error thrown by the first promise handler is passed on to the + * An error thrown by the first promise handler is passed on to the * error handler at the end of the chain. */ -var {Deferred} = require('ringo/promise'); +const {Deferred} = require('ringo/promise'); -var deferred = new Deferred(); +const deferred = new Deferred(); -deferred.promise.then(function(val) { +deferred.promise.then(val => { print('Step 1:', val); throw 'Error'; -}).then(function(val) { +}).then(val => { print('Step 2', val); return val.toUpperCase(); -}).then(function(val) { +}).then(val => { print('Step 3:', val); }, function(err) { print('Failed:', err); diff --git a/examples/swing.js b/examples/swing.js index 35f220b17..390c30906 100644 --- a/examples/swing.js +++ b/examples/swing.js @@ -1,11 +1,11 @@ -var {JFrame, JButton, ImageIcon, JLabel} = javax.swing; -var system = require('system'); +const {JFrame, JButton, ImageIcon, JLabel} = javax.swing; +const system = require('system'); -var n = 0; +const n = 0; function main() { - var frame = new JFrame("Swing Demo"); - var button = new JButton(new ImageIcon(module.resolve("img/ringo-drums.png"))); + const frame = new JFrame("Swing Demo"); + const button = new JButton(new ImageIcon(module.resolve("img/ringo-drums.png"))); button.addActionListener(function(e) { setInterval(function() { if (n++ > 200) system.exit(); @@ -19,8 +19,9 @@ function main() { frame.setVisible(true); } -function random() (Math.random() - 0.5) * 50; - +function random() { + return (Math.random() - 0.5) * 50; +} if (require.main == module) { main(); diff --git a/examples/websocket-server-push.js b/examples/websocket-server-push.js index cb8438b17..3eca2b93d 100644 --- a/examples/websocket-server-push.js +++ b/examples/websocket-server-push.js @@ -1,36 +1,45 @@ // Simple websocket server demo -var response = require("ringo/jsgi/response"); -var arrays = require("ringo/utils/arrays"); +const response = require("ringo/jsgi/response"); +const arrays = require("ringo/utils/arrays"); +const httpServer = require("ringo/httpserver"); -var connections = []; +const connections = []; // Schedule an interval function that periodically broadcasts the number of open connections -setInterval(function() { - connections.forEach(function(conn) { +setInterval(() => { + connections.forEach((conn) => { conn.send((connections.length - 1) + " other connection(s) open"); }); }, 5000) -exports.app = function(req) { +const app = (req) => { return response.static(module.resolve("html/websocket.html"), "text/html"); }; -function onconnect(conn) { +const onConnect = (conn) => { connections.push(conn); console.info("Opening connection, " + connections.length + " open"); - conn.addListener("text", function(message) { - connections.forEach(function(conn) { - conn.send(message); - }); + conn.addListener("text", message => { + connections.forEach(conn => conn.send(message)); console.info("Sending message"); }); - conn.addListener("close", function() { + conn.addListener("close", () => { arrays.remove(connections, conn); console.info("Closing connection, " + connections.length + " remaining"); - }) -} + }); +}; if (require.main == module) { - var server = require("ringo/httpserver").main(module.id); - server.getDefaultContext().addWebSocket("/websocket", onconnect); -} \ No newline at end of file + httpServer.build() + // enable sessions with a custom node name + // serve application + .serveApplication("/", app) + // add websocket - this must be called after serveApplication + // as it operates on the current context of the builder + .addWebSocket("/websocket", onConnect) + .http({ + "port": 8080 + }) + // start up the server + .start(); +} diff --git a/examples/websocket-server.js b/examples/websocket-server.js index ffacdf4d2..4823c9d7a 100644 --- a/examples/websocket-server.js +++ b/examples/websocket-server.js @@ -1,29 +1,38 @@ // Simple websocket server demo -var response = require("ringo/jsgi/response"); -var arrays = require("ringo/utils/arrays"); +const response = require("ringo/jsgi/response"); +const arrays = require("ringo/utils/arrays"); +const httpServer = require("ringo/httpserver"); -var connections = []; +const connections = []; -exports.app = function(req) { +const app = (req) => { return response.static(module.resolve("html/websocket.html"), "text/html"); }; -function onconnect(conn) { +const onConnect = (conn) => { connections.push(conn); console.info("Opening connection, " + connections.length + " open"); - conn.addListener("text", function(message) { - connections.forEach(function(conn) { - conn.send(message); - }); + conn.addListener("text", message => { + connections.forEach(conn => conn.send(message)); console.info("Sending message"); }); - conn.addListener("close", function() { + conn.addListener("close", () => { arrays.remove(connections, conn); console.info("Closing connection, " + connections.length + " remaining"); }) -} +}; if (require.main == module) { - var server = require("ringo/httpserver").main(module.id); - server.getDefaultContext().addWebSocket("/websocket", onconnect); -} \ No newline at end of file + httpServer.build() + // enable sessions with a custom node name + // serve application + .serveApplication("/", app) + // add websocket - this must be called after serveApplication + // as it operates on the current context of the builder + .addWebSocket("/websocket", onConnect) + .http({ + "port": 8080 + }) + // start up the server + .start(); +} diff --git a/examples/worker-fanout-semaphore.js b/examples/worker-fanout-semaphore.js index e66f6bdf3..df50303fa 100644 --- a/examples/worker-fanout-semaphore.js +++ b/examples/worker-fanout-semaphore.js @@ -1,29 +1,29 @@ -var {Worker} = require("ringo/worker"); -var {Semaphore} = require("ringo/concurrent"); +const {Worker} = require("ringo/worker"); +const {Semaphore} = require("ringo/concurrent"); function main() { // Create a semaphore to wait for response from all workers - var s = new Semaphore(); - var NUMBER_OF_WORKERS = 8; - + const semaphore = new Semaphore(); + const NUMBER_OF_WORKERS = 8; + // Create a new workers from this same module. Note that this will // create a new instance of this module as workers are isolated. - for (var i = 0; i < NUMBER_OF_WORKERS; i++) { - var w = new Worker(module.id); - w.onmessage = function(e) { + for (let i = 0; i < NUMBER_OF_WORKERS; i++) { + let worker = new Worker(module.id); + worker.onmessage = function(e) { print("Got reply from worker " + e.data); - s.signal(); + semaphore.signal(); } // Calling worker.postMessage with true as second argument causes // callbacks from the worker to be executed synchronously in // the worker's own thread instead of in our own event loop thread, // allowing us to wait synchronously for replies. - w.postMessage(i, true); + worker.postMessage(i, true); } - + // Wait until we have responses from all workers, but with // a timeout that is barely long enough. - if (s.tryWait(800, NUMBER_OF_WORKERS)) { + if (semaphore.tryWait(800, NUMBER_OF_WORKERS)) { print("Got responses from all workers, quitting."); } else { print("Timed out; quitting."); diff --git a/examples/worker-fanout.js b/examples/worker-fanout.js index c12b40413..d55b1226a 100644 --- a/examples/worker-fanout.js +++ b/examples/worker-fanout.js @@ -1,14 +1,14 @@ -var {Worker} = require("ringo/worker"); +const {Worker} = require("ringo/worker"); function main() { // Create a new workers from this same module. Note that this will // create a new instance of this module as workers are isolated. - for (var i = 0; i < 8; i++) { - var w = new Worker(module.id); - w.onmessage = function(e) { + for (let i = 0; i < 8; i++) { + let worker = new Worker(module.id); + worker.onmessage = function(e) { print("Got reply from worker " + e.data); } - w.postMessage(i); + worker.postMessage(i); } } diff --git a/examples/worker-pingpong.js b/examples/worker-pingpong.js index c02e1e710..00fc40417 100644 --- a/examples/worker-pingpong.js +++ b/examples/worker-pingpong.js @@ -1,22 +1,22 @@ -var {Worker} = require("ringo/worker"); +const {Worker} = require("ringo/worker"); -var i = 0; +let i = 0; function main() { // Create a new workers from this same module. Note that this will // create a new instance of this module as workers are isolated. - var w = new Worker(module.id); + const worker = new Worker(module.id); - w.onmessage = function(e) { + worker.onmessage = function(e) { print(e.data); e.source.postMessage(" PING"); }; - w.onerror = function(e) { + worker.onerror = function(e) { print(e.data); } - w.postMessage(" PING"); + worker.postMessage(" PING"); } function onmessage(e) { diff --git a/examples/worker-semaphore.js b/examples/worker-semaphore.js index 95ad2771b..0b6733eef 100644 --- a/examples/worker-semaphore.js +++ b/examples/worker-semaphore.js @@ -1,39 +1,41 @@ -var {Worker} = require("ringo/worker") -var {Semaphore} = require("ringo/concurrent") +const {Worker} = require("ringo/worker") +const {Semaphore} = require("ringo/concurrent") function main() { // Create a new workers from this same module. Note that this will // create a new instance of this module as workers are isolated. - var w = new Worker(module.id); - var s = new Semaphore(); + const worker = new Worker(module.id); + const semaphore = new Semaphore(); - w.onmessage = function(e) { + worker.onmessage = function(e) { print(" Response from worker: " + e.data); - s.signal(); + semaphore.signal(); }; // Calling worker.postMessage with true as second argument causes // callbacks from the worker to be executed synchronously in // the worker's own thread instead of in our own event loop thread, // allowing us to wait synchronously for replies. - w.postMessage(1, true); + worker.postMessage(1, true); // Wait until the semaphore gets 3 signals. - s.wait(3); + semaphore.wait(3); print("Got 3 responses from worker."); // Wait for 2 more responses. - s.wait(2); + semaphore.wait(2); print("Got 2 more responses, quitting."); } function onmessage(e) { print("Worker got message: " + e.data); - var count = 1; + let count = 1; // Send 5 responses back to the caller. - var id = setInterval(function() { + const id = setInterval(function() { e.source.postMessage(count); - if (count++ >= 5) clearInterval(id); + if (count++ >= 5) { + clearInterval(id); + } }, 500); } diff --git a/examples/worker.js b/examples/worker.js index a72c25723..df10474c7 100644 --- a/examples/worker.js +++ b/examples/worker.js @@ -1,17 +1,17 @@ -var {Worker} = require("ringo/worker") +const {Worker} = require("ringo/worker") function main() { // Create a new workers from this same module. Note that this will // create a new instance of this module as workers are isolated. - var w = new Worker(module.id); + const worker = new Worker(module.id); // Define callback for messages from the worker - w.onmessage = function(e) { + worker.onmessage = function(e) { print("Message from worker: " + e.data); }; // Post a message to the worker - w.postMessage("Hi there!"); + worker.postMessage("Hi there!"); } function onmessage(e) { From 2965bf1f20c02cad55cd9847d42aecb6d34e62f5 Mon Sep 17 00:00:00 2001 From: Robert Gaggl Date: Mon, 16 Nov 2020 12:08:12 +0100 Subject: [PATCH 52/52] #409 binary module no longer modifies the String prototype also fixes toByteString to return a ByteString, not a ByteArray --- modules/binary.js | 30 +-------------- modules/ringo/jsgi/connector.js | 2 +- test/binary/bytestring-encodings-tests.js | 4 +- test/io_test.js | 47 ++++++++++++----------- test/net_test.js | 5 ++- test/ringo/httpclient_test.js | 6 +-- test/ringo/websocket_test.js | 37 ++++++++++-------- 7 files changed, 54 insertions(+), 77 deletions(-) diff --git a/modules/binary.js b/modules/binary.js index cf64d731a..50fc49b39 100644 --- a/modules/binary.js +++ b/modules/binary.js @@ -101,37 +101,9 @@ exports.toByteArray = (string, charset) => { * const bs = binary.toByteString("hello world"); */ exports.toByteString = (string, charset) => { - return new ByteArray(String(string), charset || 'utf8'); + return new ByteString(String(string), charset || 'utf8'); }; -/** - * Converts the String to a mutable ByteArray using the specified encoding. - * @param {String} charset the name of the string encoding. Defaults to 'UTF-8' - * @returns {ByteArray} a ByteArray representing the string - * @example const ba = "hello world".toByteArray(); - * @deprecated - */ -Object.defineProperty(String.prototype, 'toByteArray', { - value: function(charset) { - charset = charset || 'utf8'; - return new ByteArray(String(this), charset); - }, writable: true -}); - -/** - * Converts the String to an immutable ByteString using the specified encoding. - * @param {String} charset the name of the string encoding. Defaults to 'UTF-8' - * @returns {ByteString} a ByteString representing the string - * @example const bs = "hello world".toByteString(); - * @deprecated - */ -Object.defineProperty(String.prototype, 'toByteString', { - value: function(charset) { - charset = charset || 'utf8'; - return new ByteString(String(this), charset); - }, writable: true -}); - /** * Reverses the content of the ByteArray in-place. * @returns {ByteArray} this ByteArray with its elements reversed diff --git a/modules/ringo/jsgi/connector.js b/modules/ringo/jsgi/connector.js index 7e30b6ac6..a4b770151 100644 --- a/modules/ringo/jsgi/connector.js +++ b/modules/ringo/jsgi/connector.js @@ -224,7 +224,7 @@ exports.AsyncResponse = function(request, timeout) { throw new Error("AsyncResponse already closed"); } if (!(data instanceof binary.Binary)) { - data = String(data).toByteArray(encoding); + data = binary.toByteArray(String(data), encoding); } writeListener.queue.add(data); writeListener.onWritePossible(); diff --git a/test/binary/bytestring-encodings-tests.js b/test/binary/bytestring-encodings-tests.js index b9cd785e8..af74da620 100644 --- a/test/binary/bytestring-encodings-tests.js +++ b/test/binary/bytestring-encodings-tests.js @@ -62,8 +62,8 @@ exports.testDecodeToString = function() { }; exports.testStringToByteString = function() { - assert.strictEqual("hello world", "hello world".toByteString("US-ASCII").decodeToString("US-ASCII")); - assert.strictEqual("I ♥ JS", "I ♥ JS".toByteString("UTF-8").decodeToString("UTF-8")); + assert.strictEqual("hello world", toByteString("hello world", "US-ASCII").decodeToString("US-ASCII")); + assert.strictEqual("I ♥ JS", toByteString("I ♥ JS", "UTF-8").decodeToString("UTF-8")); }; if (require.main === module) { diff --git a/test/io_test.js b/test/io_test.js index 8a5a40af1..ed8d29459 100644 --- a/test/io_test.js +++ b/test/io_test.js @@ -1,29 +1,29 @@ include('io'); -var {ByteString} = require('binary'); -var assert = require('assert'); +const assert = require('assert'); +const binary = require('binary'); exports.testReadFixed = function() { - var resource = getResource('./io_test.js'); - var io = new Stream(resource.inputStream); - var bytes = io.read(7); + const resource = getResource('./io_test.js'); + const stream = new Stream(resource.inputStream); + const bytes = stream.read(7); assert.strictEqual(bytes.length, 7); assert.strictEqual(bytes.decodeToString(), 'include'); }; exports.testReadIndefinite = function() { - var resource = getResource('./assert.js'); - var io = new Stream(resource.inputStream); - var bytes = io.read(); + const resource = getResource('./assert.js'); + const stream = new Stream(resource.inputStream); + const bytes = stream.read(); assert.strictEqual(bytes.length, resource.length); assert.strictEqual(bytes.decodeToString(), resource.content); }; exports.testStreamForEach = function() { - var resource = getResource('./assert.js'); - var io = new Stream(resource.inputStream); - var str = ''; - var read = 0; - io.forEach(function(data) { + const resource = getResource('./assert.js'); + const stream = new Stream(resource.inputStream); + let str = ''; + let read = 0; + stream.forEach(function(data) { read += data.length; str += data.decodeToString(); }); @@ -32,27 +32,28 @@ exports.testStreamForEach = function() { }; exports.testMemoryStream = function() { - var m = new MemoryStream(20); - var line = 'Lorem ipsum dolor sit amet, eam suas agam phaedrum an, cetero ' + + const m = new MemoryStream(20); + const line = 'Lorem ipsum dolor sit amet, eam suas agam phaedrum an, cetero ' + 'apeirian id vix, menandri evertitur eu cum.'; - var bytes = line.toByteString(); - for (var i = 0; i < 100; i++) { + const bytes = binary.toByteString(line); + for (let i = 0; i < 100; i++) { m.write(bytes); } assert.equal(m.length, bytes.length * 100); assert.equal(m.position, bytes.length * 100); m.position = 0; - for (var j = 0; j < 100; j++) { + debugger + for (let j = 0; j < 100; j++) { assert.deepEqual(m.read(bytes.length), bytes); } - assert.deepEqual(m.read(bytes.length), new ByteString()); + assert.deepEqual(m.read(bytes.length), new binary.ByteString()); } exports.testTextStream = function() { // Carriage return should be dropped - var input = new java.io.ByteArrayInputStream((new java.lang.String("Hello\r\nWorld!")).getBytes("UTF-8")); - var stream = new TextStream(new Stream(input)); - var lines = stream.readLines(); + const input = new java.io.ByteArrayInputStream((new java.lang.String("Hello\r\nWorld!")).getBytes("UTF-8")); + let stream = new TextStream(new Stream(input)); + const lines = stream.readLines(); assert.strictEqual(lines[0], "Hello\n"); assert.strictEqual(lines[1], "World!"); @@ -68,7 +69,7 @@ exports.testTextStream = function() { stream.close(); // Check writing - var output = new java.io.ByteArrayOutputStream(); + const output = new java.io.ByteArrayOutputStream(); stream = new TextStream(new Stream(output)); stream.writeLine("Hello"); stream.write("World!"); diff --git a/test/net_test.js b/test/net_test.js index 2373f2229..051326364 100644 --- a/test/net_test.js +++ b/test/net_test.js @@ -3,6 +3,7 @@ const {Socket, ServerSocket, DatagramSocket} = require("net"); const {TextStream} = require("io"); const {Semaphore} = require("ringo/concurrent"); const {Arrays} = java.util; +const binary = require("binary"); const HOST = "localhost"; const HOST_IP = "127.0.0.1"; @@ -69,8 +70,8 @@ exports.testUDP = () => { semaphores.client.tryWait(200); assert.strictEqual(messages.toServer.address, HOST_IP); assert.strictEqual(messages.toServer.port, PORT + 1); - assert.isTrue(Arrays.equals(messages.toServer.data, "hello".toByteArray())); + assert.isTrue(Arrays.equals(messages.toServer.data, binary.toByteArray("hello"))); assert.strictEqual(messages.toClient.address, HOST_IP); assert.strictEqual(messages.toClient.port, PORT); - assert.isTrue(Arrays.equals(messages.toClient.data, "world".toByteArray())); + assert.isTrue(Arrays.equals(messages.toClient.data, binary.toByteArray("world"))); }; diff --git a/test/ringo/httpclient_test.js b/test/ringo/httpclient_test.js index 2e1a0a706..f3d1bf35f 100644 --- a/test/ringo/httpclient_test.js +++ b/test/ringo/httpclient_test.js @@ -333,7 +333,7 @@ exports.testContentDecoding = () => { const compress = (CompressorOutputStream) => { const bos = new ByteArrayOutputStream(); const cos = new CompressorOutputStream(bos, true); - cos.write(unzipped.toByteArray()); + cos.write(binary.toByteArray(unzipped)); cos.finish(); const bytes = binary.ByteArray.wrap(bos.toByteArray()); cos.close(); @@ -406,7 +406,7 @@ exports.testPost = () => { // use this module's source as test data const data = fs.read(module.path); - let inputByteArray = data.toByteArray(); + let inputByteArray = binary.toByteArray(data); // POSTing byte array let exchange = request({ @@ -432,7 +432,7 @@ exports.testPost = () => { exchange = request({ url: baseUri, method: "POST", - data: new TextStream(new MemoryStream(data.toByteString()), {charset: "utf-8"}) + data: new TextStream(new MemoryStream(binary.toByteString(data)), {charset: "utf-8"}) }); assert.strictEqual(exchange.status, 200); assert.strictEqual(exchange.contentBytes.length, inputByteArray.length); diff --git a/test/ringo/websocket_test.js b/test/ringo/websocket_test.js index 305688b8f..0f290e789 100644 --- a/test/ringo/websocket_test.js +++ b/test/ringo/websocket_test.js @@ -1,21 +1,23 @@ -var assert = require("assert"); +const assert = require("assert"); -var {Worker} = require("ringo/worker"); -var {Semaphore} = require("ringo/concurrent"); -var {Arrays} = java.util; +const {Worker} = require("ringo/worker"); +const {Semaphore} = require("ringo/concurrent"); +const {Arrays} = java.util; +const binary = require("binary"); exports.testTextMessage = function() { - var message = "hello world!"; - var worker = new Worker(module.resolve("./websocket_worker")); + const message = "hello world!"; + const worker = new Worker(module.resolve("./websocket_worker")); + let received = null; worker.onmessage = function(event) { received = event.data; }; worker.onerror = function(event) { console.error(event.data); }; - for each (let isAsync in [false, true]) { - var semaphore = new Semaphore(); - var received = null; + [false, true].forEach(isAsync => { + const semaphore = new Semaphore(); + received = null; worker.postMessage({ "message": message, "semaphore": semaphore, @@ -26,19 +28,20 @@ exports.testTextMessage = function() { assert.fail("web socket text timed out"); } assert.equal(received, message); - } + }); worker.terminate(); }; exports.testBinaryMessage = function() { - var message = "hello world!".toByteArray(); - var worker = new Worker(module.resolve("./websocket_worker")); + const message = binary.toByteArray("hello world!"); + const worker = new Worker(module.resolve("./websocket_worker")); + let received = null; worker.onmessage = function(event) { received = event.data; }; - for each (let isAsync in [false, true]) { - var semaphore = new Semaphore(); - var received = null; + [false, true].forEach(isAsync => { + const semaphore = new Semaphore(); + received = null; worker.postMessage({ "message": message.slice(), "semaphore": semaphore, @@ -49,10 +52,10 @@ exports.testBinaryMessage = function() { assert.fail("web socket binary timed out"); } assert.isTrue(Arrays.equals(received, message)); - } + }); worker.terminate(); }; if (require.main === module) { require('system').exit(require("test").run(module.id)); -} \ No newline at end of file +}