protoblast
Advanced tools
Comparing version 0.7.25 to 0.7.26
@@ -0,1 +1,9 @@ | ||
## 0.7.26 (2022-12-09) | ||
* Fix `RURL` instances parsing single-word hostnames wrong | ||
* Rewrite `String#camelize()` to make it 65x as fast | ||
* Add `String#decamelize(separator)` method | ||
* Rewrite `String#encodeHTML()` to not use regexes | ||
* Add `getDescendants()`, `getDescendantsDict()` and `getDescendant(name)` class methods | ||
## 0.7.25 (2022-12-03) | ||
@@ -2,0 +10,0 @@ |
@@ -750,2 +750,88 @@ const finished_constitutors = new WeakMap(), | ||
/** | ||
* Get all the descendants of this class | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
* | ||
* @param {Function} constructor | ||
* | ||
* @return {Array} | ||
*/ | ||
defClassMethod(function getDescendants(constructor) { | ||
let result = []; | ||
if (!constructor.children) { | ||
return result; | ||
} | ||
let i; | ||
for (i = 0; i < constructor.children.length; i++) { | ||
result.push(constructor.children[i]); | ||
result.push(...constructor.children[i].getDescendants()); | ||
} | ||
return result; | ||
}); | ||
/** | ||
* Get all the descendants of this class as an enum dictionary | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
*/ | ||
defClassMethod(function getDescendantsDict(constructor) { | ||
let parent_namespace = constructor.namespace, | ||
namespace, | ||
type_path, | ||
children = constructor.getDescendants(), | ||
result = {}, | ||
child; | ||
for (child of children) { | ||
type_path = child.type_name; | ||
namespace = child.namespace; | ||
// Add extra identifier info if this child comes from another namespace | ||
if (namespace != parent_namespace) { | ||
if (namespace.startsWith(parent_namespace)) { | ||
namespace = namespace.after(parent_namespace); | ||
if (namespace[0] == '.') { | ||
namespace = namespace.slice(1); | ||
} | ||
} | ||
type_path = Bound.String.underscore(Bound.String.slug(namespace)) + '.' + type_path; | ||
} | ||
result[type_path] = child; | ||
} | ||
return result; | ||
}); | ||
/** | ||
* Get a specific descendant by their name | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
*/ | ||
defClassMethod(function getDescendant(constructor, name) { | ||
if (!name) { | ||
throw new Error('Unable to get class member of ' + constructor.name + ', given name is empty'); | ||
} | ||
let result = constructor.getDescendantsDict()[name]; | ||
return result; | ||
}); | ||
/** | ||
* Do the constitutors for the given constructor | ||
@@ -752,0 +838,0 @@ * |
@@ -206,3 +206,96 @@ /** | ||
const CHAR_UPPER_A = 0x41 | ||
const CHAR_LOWER_A = 0x61 | ||
const CHAR_UPPER_Z = 0x5a | ||
const CHAR_LOWER_Z = 0x7a | ||
const CHAR_0 = 0x30 | ||
const CHAR_9 = 0x39 | ||
const CHAR_MINUS = 0x2d; | ||
const CHAR_SPACE = 0x20; | ||
const CHAR_UNDERSCORE = 0x5f; | ||
/** | ||
* Is this an upper char number? | ||
* | ||
* @author Jacob Gillespie <jacobwgillespie@gmail.com> | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
* | ||
* @param {Number} char_code | ||
*/ | ||
function isUpper(char_code) { | ||
return CHAR_UPPER_A <= char_code && char_code <= CHAR_UPPER_Z; | ||
} | ||
/** | ||
* Is this a lower char number? | ||
* | ||
* @author Jacob Gillespie <jacobwgillespie@gmail.com> | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
* | ||
* @param {Number} char_code | ||
*/ | ||
function isLower(char_code) { | ||
return CHAR_LOWER_A <= char_code && char_code <= CHAR_LOWER_Z; | ||
} | ||
/** | ||
* Is this a digit char number? | ||
* | ||
* @author Jacob Gillespie <jacobwgillespie@gmail.com> | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
* | ||
* @param {Number} char_code | ||
*/ | ||
function isDigit(char_code) { | ||
return CHAR_0 <= char_code && char_code <= CHAR_9; | ||
} | ||
/** | ||
* Convert the charcode to upper | ||
* | ||
* @author Jacob Gillespie <jacobwgillespie@gmail.com> | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
* | ||
* @param {Number} char_code | ||
*/ | ||
function toUpper(char_code) { | ||
return char_code - 0x20; | ||
} | ||
/** | ||
* Convert the charcode to upper | ||
* | ||
* @author Jacob Gillespie <jacobwgillespie@gmail.com> | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
* | ||
* @param {Number} char_code | ||
*/ | ||
function toLower(char_code) { | ||
return char_code + 0x20; | ||
} | ||
/** | ||
* Define something on the string prototype | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
* | ||
* @param {Function} fnc | ||
*/ | ||
function defString(fnc) { | ||
return Blast.definePrototype('String', fnc); | ||
} | ||
/** | ||
* Pluralize a string | ||
@@ -218,3 +311,3 @@ * | ||
*/ | ||
Blast.definePrototype('String', function pluralize(plural) { | ||
defString(function pluralize(plural) { | ||
return InflectionJS.apply_rules( | ||
@@ -239,3 +332,3 @@ this, | ||
*/ | ||
Blast.definePrototype('String', function singularize(singular) { | ||
defString(function singularize(singular) { | ||
return InflectionJS.apply_rules( | ||
@@ -260,3 +353,3 @@ this, | ||
*/ | ||
Blast.definePrototype('String', function modelName(postfix) { | ||
defString(function modelName(postfix) { | ||
@@ -309,3 +402,3 @@ var str = this, | ||
*/ | ||
Blast.definePrototype('String', function modelClassName() { | ||
defString(function modelClassName() { | ||
@@ -336,3 +429,3 @@ var result; | ||
*/ | ||
Blast.definePrototype('String', function controllerName(postfix) { | ||
defString(function controllerName(postfix) { | ||
@@ -392,3 +485,3 @@ var str = this, | ||
*/ | ||
Blast.definePrototype('String', function controllerClassName() { | ||
defString(function controllerClassName() { | ||
@@ -411,43 +504,112 @@ var result; | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @author Jacob Gillespie <jacobwgillespie@gmail.com> | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.0.1 | ||
* @version 0.0.1 | ||
* @version 0.7.26 | ||
* | ||
* @param {Boolean} lowFirstLetter The first char is lowercased if true | ||
* @param {Boolean} lower_first_letter The first char is lowercased if true | ||
* | ||
* @return {String} Lower case underscored words will be returned in camel | ||
* case. Additionally '/' is translated to '::' | ||
* @return {String} | ||
*/ | ||
Blast.definePrototype('String', function camelize(lowFirstLetter) { | ||
defString(function camelize(lower_first_letter) { | ||
var str = this, | ||
str_path, | ||
str_arr, | ||
initX, | ||
i, | ||
x; | ||
let first_char = this.charCodeAt(0), | ||
char_code, | ||
changed = false, | ||
length = this.length, | ||
i; | ||
// If there are capitals, underscore this first | ||
if (S.capitals(str)) str = S.underscore(str); | ||
if (lower_first_letter) { | ||
if (isUpper(first_char)) { | ||
changed = true; | ||
first_char = toLower(first_char); | ||
} | ||
} else { | ||
if (isLower(first_char)) { | ||
changed = true; | ||
first_char = toUpper(first_char); | ||
} | ||
} | ||
str_path = str.split('/'); | ||
const transformed = [first_char]; | ||
for (i = 0; i < str_path.length; i++) { | ||
for (i = 1; i < length; i++) { | ||
char_code = this.charCodeAt(i); | ||
str_arr = str_path[i].split('_'); | ||
initX = ((lowFirstLetter && i + 1 === str_path.length) ? (1) : (0)); | ||
if (char_code === CHAR_UNDERSCORE || char_code === CHAR_SPACE || char_code === CHAR_MINUS) { | ||
changed = true; | ||
char_code = this.charCodeAt(++i); | ||
for (x = initX; x < str_arr.length; x++) { | ||
str_arr[x] = str_arr[x].charAt(0).toUpperCase() + str_arr[x].substring(1); | ||
if (isLower(char_code)) { | ||
char_code = toUpper(char_code); | ||
} | ||
} | ||
str_path[i] = str_arr.join(''); | ||
transformed.push(char_code); | ||
} | ||
str = str_path.join('::'); | ||
if (!changed) { | ||
return this; | ||
} | ||
return str; | ||
return String.fromCharCode(...transformed); | ||
}); | ||
/** | ||
* Turn a camelized string into something else | ||
* | ||
* @author Jacob Gillespie <jacobwgillespie@gmail.com> | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.26 | ||
* @version 0.7.26 | ||
* | ||
* @param {String} separator | ||
* | ||
* @return {String} | ||
*/ | ||
defString(function decamelize(separator) { | ||
let first_char = this.charCodeAt(0), | ||
char_code, | ||
changed = false, | ||
length = this.length, | ||
i; | ||
let separator_code; | ||
if (separator) { | ||
separator_code = separator.charCodeAt(0); | ||
} | ||
if (separator_code == null) { | ||
separator_code = CHAR_UNDERSCORE; | ||
} | ||
if (isUpper(first_char)) { | ||
changed = true; | ||
first_char = toLower(first_char); | ||
} | ||
const transformed = [first_char]; | ||
for (i = 1; i < length; i++) { | ||
char_code = this.charCodeAt(i); | ||
if (isUpper(char_code)) { | ||
changed = true; | ||
transformed.push(separator_code); | ||
char_code = toLower(char_code); | ||
} | ||
transformed.push(char_code); | ||
} | ||
if (!changed) { | ||
return this; | ||
} | ||
return String.fromCharCode(...transformed); | ||
}); | ||
/** | ||
* Underscore a string | ||
@@ -461,3 +623,3 @@ * | ||
*/ | ||
Blast.definePrototype('String', function underscore() { | ||
defString(function underscore() { | ||
@@ -545,3 +707,3 @@ var previous_underscore = true, // Act as if it already starts with an underscore | ||
*/ | ||
Blast.definePrototype('String', function humanize(lowFirstLetter) { | ||
defString(function humanize(lowFirstLetter) { | ||
@@ -577,3 +739,3 @@ var str = S.underscore(this), | ||
*/ | ||
Blast.definePrototype('String', function capitalize() { | ||
defString(function capitalize() { | ||
@@ -598,3 +760,3 @@ // Lowercase the complete string | ||
*/ | ||
Blast.definePrototype('String', function dasherize() { | ||
defString(function dasherize() { | ||
var str = this; | ||
@@ -616,3 +778,3 @@ str = str.replace(InflectionJS.space_or_underbar, '-'); | ||
*/ | ||
Blast.definePrototype('String', function titleize(alwaysCapitalize) { | ||
defString(function titleize(alwaysCapitalize) { | ||
@@ -661,3 +823,3 @@ // Underscore the string | ||
*/ | ||
Blast.definePrototype('String', function demodulize() { | ||
defString(function demodulize() { | ||
@@ -681,3 +843,3 @@ var str = this, | ||
*/ | ||
Blast.definePrototype('String', function tableize() { | ||
defString(function tableize() { | ||
var str = S.underscore(this); | ||
@@ -697,3 +859,3 @@ str = S.pluralize(str); | ||
*/ | ||
Blast.definePrototype('String', function classify() { | ||
defString(function classify() { | ||
var str = S.camelize(this); | ||
@@ -715,3 +877,3 @@ str = S.singularize(str); | ||
*/ | ||
Blast.definePrototype('String', function foreign_key(dropIdUbar) { | ||
defString(function foreign_key(dropIdUbar) { | ||
var str = S.demodulize(this); | ||
@@ -733,3 +895,3 @@ str = S.underscore(str); | ||
*/ | ||
Blast.definePrototype('String', function ordinalize() { | ||
defString(function ordinalize() { | ||
@@ -783,3 +945,3 @@ var str = this, | ||
*/ | ||
Blast.definePrototype('String', function deplugin(str) { | ||
defString(function deplugin(str) { | ||
@@ -786,0 +948,0 @@ var s = this.split('.'), |
@@ -445,3 +445,3 @@ var rx_protocol = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i, | ||
* @since 0.5.7 | ||
* @version 0.5.7 | ||
* @version 0.7.26 | ||
* | ||
@@ -454,9 +454,32 @@ * @param {String} address | ||
var match = rx_protocol.exec(address), | ||
result; | ||
let match = rx_protocol.exec(address), | ||
protocol = match[1] ? match[1].toLowerCase() : '', | ||
slashes = !!match[2], | ||
rest = match[3], | ||
adjusted = false; | ||
result = { | ||
protocol : match[1] ? match[1].toLowerCase() : '', | ||
slashes : !!match[2], | ||
rest : match[3] | ||
// Ignore obvious hostnames as protocol | ||
if (protocol && protocol.indexOf('.') > -1) { | ||
rest = protocol; | ||
protocol = ''; | ||
adjusted = true; | ||
} | ||
// Make sure the port isn't seen as the hostname, | ||
// and the hostname as the protocol | ||
// This would be the case for `localhost:3470` | ||
if (rest && isFinite(rest)) { | ||
rest = protocol; | ||
protocol = ''; | ||
adjusted = true; | ||
} | ||
if (adjusted && rest.indexOf(':') > -1) { | ||
rest = rest.replace(':', ''); | ||
} | ||
let result = { | ||
protocol, | ||
slashes, | ||
rest | ||
}; | ||
@@ -916,3 +939,3 @@ | ||
* @since 0.5.7 | ||
* @version 0.7.16 | ||
* @version 0.7.26 | ||
* | ||
@@ -930,3 +953,3 @@ * @type {String} | ||
if (extracted.protocol && extracted.protocol.indexOf('.') == -1) { | ||
if (extracted.protocol) { | ||
this._data.protocol = extracted.protocol; | ||
@@ -933,0 +956,0 @@ this._data.slashes = extracted.slashes; |
@@ -87,3 +87,2 @@ /** | ||
"&": [ | ||
false, | ||
"amp", | ||
@@ -90,0 +89,0 @@ "AMP" |
@@ -58,2 +58,4 @@ /** | ||
let HTMLEntities, | ||
HTMLEntityCodes, | ||
HTMLEntityCodeMap, | ||
non_ascii_rx = /(?:[\u0100-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g, | ||
@@ -88,2 +90,4 @@ char_map, | ||
HTMLEntities = {}; | ||
HTMLEntityCodes = {}; | ||
HTMLEntityCodeMap = new Map(); | ||
@@ -103,2 +107,4 @@ for (key in char_map) { | ||
let skip_code = false; | ||
for (i = 0; i < values.length; i++) { | ||
@@ -108,2 +114,3 @@ value = values[i]; | ||
if (value === false) { | ||
skip_code = true; | ||
continue; | ||
@@ -113,2 +120,17 @@ } | ||
HTMLEntities[value] = key; | ||
if (skip_code) { | ||
continue; | ||
} | ||
if (HTMLEntityCodes[key.charCodeAt(0)]) { | ||
continue; | ||
} | ||
let codes = []; | ||
HTMLEntityCodes[key.charCodeAt(0)] = codes; | ||
HTMLEntityCodeMap.set(key.charCodeAt(0), codes); | ||
for (let i = 0; i < value.length; i++) { | ||
codes.push(value.charCodeAt(i)); | ||
} | ||
} | ||
@@ -198,2 +220,13 @@ } | ||
const CHAR_RETURN = 13; | ||
const CHAR_QUOT = 34; | ||
const CHAR_HASH = 35; | ||
const CHAR_AMP = 38; | ||
const CHAR_SQUOT = 39; | ||
const CHAR_SEMI = 59; | ||
const CHAR_LT = 60; | ||
const CHAR_GT = 62; | ||
const CHAR_BACK = 92; | ||
const CHAR_X = 120; | ||
/** | ||
@@ -204,3 +237,3 @@ * Browser-side implementation of encoding HTML entities | ||
* @since 0.1.2 | ||
* @version 0.7.5 | ||
* @version 0.7.26 | ||
* | ||
@@ -218,12 +251,76 @@ * @param {Boolean} replace_more Replace more characters (inside attributes) | ||
let result; | ||
const length = this.length; | ||
if (replace_more) { | ||
result = this.replace(base_rx, baseReplace); | ||
} else { | ||
result = this.replace(base_rx, baseDangerousReplace); | ||
let start_index = 0, | ||
end_index = 0, | ||
code_string, | ||
code_point, | ||
char_code, | ||
replaced, | ||
changed = false, | ||
pieces = [], | ||
codes, | ||
i, | ||
j; | ||
for (i = 0; i < length; i++) { | ||
char_code = this.charCodeAt(i); | ||
if (char_code > 31 && char_code < 256) { | ||
if (char_code == CHAR_LT || char_code == CHAR_GT || char_code == CHAR_AMP) { | ||
// Has to be replaced | ||
} else if (replace_more && (char_code == CHAR_BACK || char_code == CHAR_QUOT)) { | ||
// Also has to be replaced! | ||
} else { | ||
end_index = i + 1; | ||
continue; | ||
} | ||
} | ||
codes = HTMLEntityCodeMap.get(char_code); | ||
if (codes) { | ||
replaced = '&'; | ||
if (start_index != end_index) { | ||
pieces.push(this.slice(start_index, end_index)); | ||
} | ||
changed = true; | ||
for (j = 0; j < codes.length; j++) { | ||
replaced += String.fromCharCode(codes[j]) | ||
} | ||
replaced += ';'; | ||
pieces.push(replaced); | ||
start_index = end_index = i + 1; | ||
} else { | ||
code_point = this.codePointAt(i); | ||
if (char_code == code_point) { | ||
end_index = i; | ||
} else { | ||
i++; | ||
changed = true; | ||
code_string = code_point.toString(16); | ||
if (start_index != end_index) { | ||
pieces.push(this.slice(start_index, end_index)); | ||
} | ||
replaced = '&#x' + code_string + ';'; | ||
pieces.push(replaced); | ||
start_index = end_index = i + 1; | ||
} | ||
} | ||
} | ||
return result.replace(xml_rx, namedReplace) | ||
.replace(non_ascii_rx, singleCharReplacer); | ||
if (!changed) { | ||
return this; | ||
} | ||
pieces.push(this.slice(start_index, end_index)); | ||
return pieces.join(''); | ||
}); | ||
@@ -230,0 +327,0 @@ |
{ | ||
"name": "protoblast", | ||
"description": "Native object expansion library", | ||
"version": "0.7.25", | ||
"version": "0.7.26", | ||
"author": "Jelle De Loecker <jelle@elevenways.be>", | ||
@@ -6,0 +6,0 @@ "keywords": [ |
790930
32585