protoblast
Advanced tools
Comparing version 0.9.0 to 0.9.1
@@ -0,1 +1,6 @@ | ||
## 0.9.1 (2024-02-19) | ||
* Rewrite JavaScript tokenizer to no longer use regexes | ||
* Allow `Pledge` instances to be cancelled | ||
## 0.9.0 (2024-02-15) | ||
@@ -2,0 +7,0 @@ |
@@ -0,0 +0,0 @@ const defStat = Blast.createStaticDefiner('Function'); |
@@ -6,7 +6,2 @@ const defStat = Blast.createStaticDefiner('Function'), | ||
let tokenMatches, | ||
tokenTesters, | ||
haveCombined, | ||
combineError; | ||
let keywords = [ | ||
@@ -85,74 +80,19 @@ 'async', 'await', | ||
let token_patterns = { | ||
whitespace : /\s+/, | ||
keyword : null, | ||
name : /[a-zA-Z_\$][a-zA-Z_\$0-9]*/, | ||
string1 : /"(?:(?:\\\n|\\"|[^"\n]))*?"/, | ||
string2 : /'(?:(?:\\\n|\\'|[^'\n]))*?'/, | ||
string3 : /`(?:(?:\\`|.|[\n\r]))*?`/, | ||
comment1 : /\/\*[\s\S]*?\*\//, | ||
comment2 : /\/\/.*?(?=\r\n|\r|\n|$)/, | ||
number2 : /\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:e[+-]?\d+(?:_\d+)*)?/i, | ||
number : /\d+(?:\.\d+)?(?:e[+-]?\d+)?/, | ||
parens : /[\(\)]/, | ||
curly : /[{}]/, | ||
square : /[\[\]]/, | ||
punct : /[;.:\?\^%<>=!&|+\-,~]/, | ||
regexp : /\/(?:(?:\\\/|[^\n\/]))*?\//, | ||
}; | ||
const TOKEN_WHITESPACE = 1, | ||
TOKEN_KEYWORD = 2, | ||
TOKEN_NAME = 3, | ||
TOKEN_STRING_DOUBLE = 4, | ||
TOKEN_STRING_SINGLE = 5, | ||
TOKEN_STRING_BACK = 6, | ||
TOKEN_COMMENT_BLOCK = 7, | ||
TOKEN_COMMENT_INLINE = 8, | ||
TOKEN_NUMBER = 9, | ||
TOKEN_PARENS = 10, | ||
TOKEN_CURLY = 11, | ||
TOKEN_SQUARE = 12, | ||
TOKEN_PUNCT = 13, | ||
TOKEN_REGEXP = 14, | ||
TOKEN_REGEXP_FLAG = 15, | ||
TOKEN_INVALID = 16; | ||
let rx_regex = /^\/(?:(?:\\\/|[^\n\/]))*?\/(?:[gimuy]*)$/; | ||
let patternNames = { | ||
string1 : 'string', | ||
string2 : 'string', | ||
string3 : 'string', | ||
comment1 : 'comment', | ||
comment2 : 'comment', | ||
}; | ||
Blast._fn_token_prepare = function BlastReadyFunction() { | ||
var patterns = [], | ||
temp, | ||
name, | ||
key, | ||
i; | ||
token_patterns.keyword = RegExp('\\b(?:' + keywords.join('|') + ')\\b'); | ||
temp = ''; | ||
for (key in operators) { | ||
if (temp) { | ||
temp += '|'; | ||
} | ||
temp += Bound.RegExp.escape(key); | ||
} | ||
token_patterns.punct = RegExp('(?:' + temp + ')'); | ||
for (key in token_patterns) { | ||
patterns.push(token_patterns[key]); | ||
} | ||
try { | ||
// Create the matches | ||
tokenMatches = Collection.RegExp.combine.apply(null, patterns); | ||
} catch (err) { | ||
combineError = err; | ||
return; | ||
} | ||
// Create the testers | ||
tokenTesters = {}; | ||
for (name in token_patterns) { | ||
tokenTesters[name] = new RegExp('^' + Collection.RegExp.prototype.getPattern.call(token_patterns[name]) + '$'); | ||
} | ||
haveCombined = true; | ||
}; | ||
/** | ||
@@ -263,3 +203,3 @@ * Create a function with the given variable as name. | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* @version 0.9.0 | ||
* | ||
@@ -271,21 +211,4 @@ * @param {string} tokenString | ||
defStat(function getTokenType(tokenString) { | ||
var patternName; | ||
if (!haveCombined) { | ||
throw combineError; | ||
} | ||
for (patternName in token_patterns) { | ||
if (tokenTesters[patternName].test(tokenString)) { | ||
if (patternNames[patternName]) { | ||
return patternNames[patternName]; | ||
} | ||
return patternName; | ||
} | ||
} | ||
return 'invalid'; | ||
let result = Fn.tokenize(tokenString, true, false); | ||
return result?.[0]?.type || 'invalid'; | ||
}); | ||
@@ -300,177 +223,430 @@ | ||
* | ||
* @param {string} sourceCode | ||
* @param {boolean} addType Add the type of the token | ||
* @param {boolean} throwErrors Throw error when invalid token is found | ||
* @param {string} source_code | ||
* @param {boolean} add_type Add the type of the token | ||
* @param {boolean} throw_errors Throw error when invalid token is found | ||
* | ||
* @return {Array} | ||
*/ | ||
defStat(function tokenize(sourceCode, addType, throwErrors) { | ||
defStat(function tokenize(source_code, add_type, throw_errors) { | ||
let line_nr = 0, | ||
tokens = [], | ||
obj, | ||
if (typeof source_code !== 'string') { | ||
source_code = ''+source_code; | ||
} | ||
let prev_usable_token, | ||
check_next_state, | ||
is_punctuation = false, | ||
current_state, | ||
current_line = 0, | ||
string_state = false, | ||
prev_token, | ||
is_digit = false, | ||
end_char, | ||
has_dot = false, | ||
escaped = false, | ||
result = [], | ||
length = source_code.length, | ||
buffer, | ||
next, | ||
trim, | ||
prev, | ||
char, | ||
i; | ||
if (!haveCombined) { | ||
throw combineError; | ||
} | ||
const createBuffer = (state, char) => { | ||
endState(); | ||
current_state = state; | ||
if (typeof sourceCode !== 'string') { | ||
sourceCode = ''+sourceCode; | ||
} | ||
buffer = { | ||
type : state, | ||
value : '', | ||
line_start : current_line, | ||
line_end : current_line, | ||
}; | ||
sourceCode = sourceCode.split(tokenMatches); | ||
pushChar(char); | ||
}; | ||
for (i = 0; i < sourceCode.length; i++) { | ||
const createStringState = (state, char) => { | ||
createBuffer(state, char); | ||
end_char = char; | ||
string_state = true; | ||
}; | ||
// Every uneven match should be used | ||
if (i % 2) { | ||
tokens.push(sourceCode[i]); | ||
} else if (sourceCode[i] !== '') { | ||
const endState = (last_char) => { | ||
string_state = false; | ||
current_state = null; | ||
end_char = null; | ||
has_dot = false; | ||
// If an even match contains something, it's invalid | ||
if (throwErrors) { | ||
throw new Error('Invalid token: ' + JSON.stringify(e)); | ||
if (buffer) { | ||
pushChar(last_char); | ||
buffer.line_end = current_line; | ||
result.push(buffer); | ||
if (buffer.type != TOKEN_WHITESPACE && buffer.type != TOKEN_COMMENT_INLINE && buffer.type != TOKEN_COMMENT_BLOCK) { | ||
prev_usable_token = buffer; | ||
} | ||
tokens.push(sourceCode[i]); | ||
prev_token = buffer; | ||
buffer = null; | ||
} | ||
} | ||
}; | ||
if (!addType) { | ||
return tokens; | ||
} | ||
const pushChar = (new_char) => { | ||
let was_declaring, | ||
declaring, | ||
assigning, | ||
result = [], | ||
prev; | ||
if (new_char != null) { | ||
buffer.value += new_char; | ||
char = new_char; | ||
for (i = 0; i < tokens.length; i++) { | ||
was_declaring = declaring; | ||
if (new_char === '\n') { | ||
current_line++; | ||
} | ||
} | ||
obj = { | ||
type : Fn.getTokenType(tokens[i]), | ||
value : tokens[i], | ||
line_start : line_nr, | ||
line_end : 0, | ||
}; | ||
escaped = false; | ||
}; | ||
if (obj.type === 'number2') { | ||
obj.type = 'number'; | ||
obj.value = obj.value.replaceAll('_', ''); | ||
const getNextChars = (amount) => { | ||
let result = char; | ||
for (let j = 1; j < amount; j++) { | ||
result += source_code[i + j]; | ||
} | ||
if (declaring) { | ||
if (obj.value == ';') { | ||
declaring = false; | ||
assigning = false; | ||
} else { | ||
if (assigning && obj.value == ',') { | ||
assigning = false; | ||
} else if (obj.value == '=') { | ||
assigning = true; | ||
return result; | ||
}; | ||
const createOperator = (chars, type) => { | ||
let skip = chars.length - 1; | ||
char = chars[skip]; | ||
i += skip; | ||
createBuffer(TOKEN_PUNCT, chars); | ||
buffer.name = type; | ||
}; | ||
const checkPunct = (char) => { | ||
let chars = getNextChars(4), | ||
type = operators[chars]; | ||
if (type) { | ||
createOperator(chars, type); | ||
return; | ||
} | ||
chars = getNextChars(3); | ||
type = operators[chars]; | ||
if (type) { | ||
createOperator(chars, type); | ||
return; | ||
} | ||
chars = getNextChars(2); | ||
type = operators[chars]; | ||
if (type) { | ||
createOperator(chars, type); | ||
return; | ||
} | ||
type = operators[char]; | ||
if (type) { | ||
createOperator(char, type); | ||
return; | ||
} | ||
}; | ||
const hasSlashBeforeEndOfLine = () => { | ||
let char, | ||
j = i + 1; | ||
while (j < length) { | ||
char = source_code[j]; | ||
j++; | ||
if (char === '\\') { | ||
j++; | ||
continue; | ||
} | ||
if (char === '\n') { | ||
return false; | ||
} | ||
if (char === '/') { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
const isValidNameChar = (char) => { | ||
return char == '_' || char == '$' || char.match(/[a-zA-Z0-9]/); | ||
}; | ||
for (i = 0; i < length; i++) { | ||
prev = char; | ||
char = source_code[i]; | ||
trim = char.trim(); | ||
next = source_code[i + 1]; | ||
is_punctuation = false; | ||
is_digit = false; | ||
switch (char) { | ||
case '.': | ||
case '~': | ||
case '!': | ||
case '%': | ||
case '/': | ||
case '*': | ||
case '-': | ||
case '+': | ||
case '>': | ||
case '<': | ||
case '=': | ||
case '&': | ||
case '^': | ||
case '|': | ||
case ',': | ||
case ';': | ||
case '?': | ||
case ':': | ||
case '(': | ||
case ')': | ||
case '{': | ||
case '}': | ||
case '[': | ||
case ']': | ||
is_punctuation = true; | ||
break; | ||
case '0': | ||
case '1': | ||
case '2': | ||
case '3': | ||
case '4': | ||
case '5': | ||
case '6': | ||
case '7': | ||
case '8': | ||
case '9': | ||
is_digit = true; | ||
break; | ||
} | ||
if (current_state) { | ||
check_next_state = false; | ||
if (current_state == TOKEN_WHITESPACE) { | ||
if (!trim) { | ||
pushChar(char); | ||
} else { | ||
check_next_state = true; | ||
} | ||
} else if (string_state) { | ||
if (obj.type != 'whitespace' && obj.type != 'name') { | ||
if (char === '\\' && !escaped) { | ||
pushChar(char); | ||
escaped = true; | ||
} else if (char == end_char && !escaped) { | ||
endState(char); | ||
} else { | ||
pushChar(char); | ||
} | ||
} else if (current_state == TOKEN_COMMENT_INLINE) { | ||
if (char == '\n') { | ||
check_next_state = true; | ||
} else { | ||
pushChar(char); | ||
} | ||
} else if (current_state == TOKEN_COMMENT_BLOCK) { | ||
if (char == '*' && next == '/') { | ||
i++; | ||
pushChar(char); | ||
pushChar(next); | ||
endState(); | ||
} else { | ||
pushChar(char); | ||
} | ||
} else if (current_state == TOKEN_NAME || current_state == TOKEN_INVALID) { | ||
if (!trim || is_punctuation) { | ||
if (assigning) { | ||
if (obj.type != 'punct' && obj.value != 'this') { | ||
assigning = false; | ||
} | ||
} else if (obj.value != '=' && obj.value != ',') { | ||
declaring = false; | ||
if (keywords.includes(buffer.value)) { | ||
buffer.type = TOKEN_KEYWORD; | ||
buffer.name = buffer.value; | ||
} | ||
check_next_state = true; | ||
} else { | ||
pushChar(char); | ||
} | ||
} | ||
} | ||
} else if (current_state == TOKEN_REGEXP) { | ||
if (char == '/' && !escaped) { | ||
current_state = TOKEN_REGEXP_FLAG | ||
} | ||
if (obj.type == 'keyword') { | ||
obj.name = obj.value; | ||
pushChar(char); | ||
} else if (current_state == TOKEN_NUMBER) { | ||
if (obj.value !== 'this') { | ||
if (obj.value == 'var' || obj.value == 'let' || obj.value == 'const') { | ||
declaring = true; | ||
if (char == '.') { | ||
if (has_dot) { | ||
check_next_state = true; | ||
} else { | ||
pushChar(char); | ||
has_dot = true; | ||
} | ||
} else if (is_digit || char == 'e' || char == 'E') { | ||
pushChar(char); | ||
} else if (char == '_' && prev != '_') { | ||
// Ignore | ||
} else { | ||
declaring = false; | ||
check_next_state = true; | ||
} | ||
} else if (current_state == TOKEN_REGEXP_FLAG) { | ||
switch (char) { | ||
case 'g': | ||
case 'i': | ||
case 'm': | ||
case 'u': | ||
case 'y': | ||
pushChar(char); | ||
break; | ||
default: | ||
check_next_state = true; | ||
}; | ||
} else { | ||
check_next_state = true; | ||
} | ||
} else if (operators[tokens[i]]) { | ||
obj.name = operators[tokens[i]]; | ||
} | ||
if (!check_next_state) { | ||
continue; | ||
} | ||
if (obj.value === '/') { | ||
i = checkTogenizeRegex(i, tokens, obj, prev, was_declaring, assigning); | ||
endState(); | ||
} | ||
// Replace the original string with the object | ||
result.push(obj); | ||
if (!trim) { | ||
createBuffer(TOKEN_WHITESPACE, char); | ||
} else if (char == '"') { | ||
createStringState(TOKEN_STRING_DOUBLE, char); | ||
} else if (char == "'") { | ||
createStringState(TOKEN_STRING_SINGLE, char); | ||
} else if (char == '`') { | ||
createStringState(TOKEN_STRING_BACK, char); | ||
} else if (char == '(' || char == ')') { | ||
createBuffer(TOKEN_PARENS, char); | ||
} else if (char == '{' || char == '}') { | ||
createBuffer(TOKEN_CURLY, char); | ||
} else if (char == '[' || char == ']') { | ||
createBuffer(TOKEN_SQUARE, char); | ||
} else if (is_digit) { | ||
createBuffer(TOKEN_NUMBER, char); | ||
if (obj.type == 'whitespace') { | ||
line_nr += Bound.String.count(obj.value, '\n'); | ||
// It technically isn't valid JavaScript either, | ||
// But it is even more wrong when 'a.0.1.b' is considered a number | ||
if (prev_usable_token?.value === '.' || prev_usable_token?.value === '?.') { | ||
endState(); | ||
} | ||
} else { | ||
prev = obj; | ||
if (char == '/') { | ||
if (next == '/') { | ||
i++; | ||
createBuffer(TOKEN_COMMENT_INLINE, '//'); | ||
continue; | ||
} else if (next == '*') { | ||
i++; | ||
char = '*'; // For next iteration's prev | ||
createBuffer(TOKEN_COMMENT_BLOCK, '/*'); | ||
continue; | ||
} else if (prev_usable_token?.type != TOKEN_NAME && prev_usable_token?.type != TOKEN_NUMBER && hasSlashBeforeEndOfLine()) { | ||
createBuffer(TOKEN_REGEXP, char); | ||
continue; | ||
} | ||
} | ||
if (is_punctuation) { | ||
checkPunct(char); | ||
} else if (isValidNameChar(char)) { | ||
createBuffer(TOKEN_NAME, char); | ||
} else { | ||
createBuffer(TOKEN_INVALID, char); | ||
} | ||
} | ||
obj.line_end = line_nr; | ||
} | ||
return result; | ||
}); | ||
endState(); | ||
/** | ||
* Fix regex literals in tokenized objects | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.0 | ||
* @version 0.7.0 | ||
* | ||
* @param {number} index The current index | ||
* @param {Array} tokens Array of all the tokens | ||
* @param {Object} obj The current object | ||
* @param {Object} prev The previous object | ||
* @param {boolean} declaring Are we currently declaring something? | ||
* | ||
* @return {number} | ||
*/ | ||
function checkTogenizeRegex(index, tokens, obj, prev, declaring, assigning) { | ||
let mapper; | ||
if (prev && (prev.type != 'punct' && prev.type != 'parens')) { | ||
if (!declaring || ((assigning && prev.type == 'name') || prev.type == 'string' || prev.type == 'number')) { | ||
return index; | ||
} | ||
} | ||
if (add_type) { | ||
mapper = entry => { | ||
switch (entry.type) { | ||
case TOKEN_WHITESPACE: | ||
entry.type = 'whitespace'; | ||
break; | ||
let matched = false, | ||
next = tokens[index + 1], | ||
temp = obj.value, | ||
str = obj.value, | ||
i; | ||
case TOKEN_KEYWORD: | ||
entry.type = 'keyword'; | ||
break; | ||
for (i = index + 1; i < tokens.length; i++) { | ||
temp += tokens[i]; | ||
case TOKEN_NAME: | ||
entry.type = 'name'; | ||
break; | ||
if (rx_regex.test(temp)) { | ||
matched = i; | ||
str = temp; | ||
} else { | ||
// If it matched before, that'll be correct | ||
if (matched) { | ||
i = matched; | ||
break; | ||
case TOKEN_STRING_DOUBLE: | ||
case TOKEN_STRING_SINGLE: | ||
case TOKEN_STRING_BACK: | ||
entry.type = 'string'; | ||
break; | ||
case TOKEN_COMMENT_INLINE: | ||
case TOKEN_COMMENT_BLOCK: | ||
entry.type = 'comment'; | ||
break; | ||
case TOKEN_NUMBER: | ||
entry.type = 'number'; | ||
break; | ||
case TOKEN_PARENS: | ||
entry.type = 'parens'; | ||
break; | ||
case TOKEN_CURLY: | ||
entry.type = 'curly'; | ||
break; | ||
case TOKEN_SQUARE: | ||
entry.type = 'square'; | ||
break; | ||
case TOKEN_PUNCT: | ||
entry.type = 'punct'; | ||
break; | ||
case TOKEN_REGEXP: | ||
case TOKEN_REGEXP_FLAG: | ||
entry.type = 'regexp'; | ||
break; | ||
case TOKEN_INVALID: | ||
entry.type = 'invalid'; | ||
break; | ||
} | ||
} | ||
} | ||
if (str.length > 1) { | ||
obj.value = str; | ||
obj.type = obj.name = 'regexp'; | ||
return i; | ||
return entry; | ||
}; | ||
} else { | ||
mapper = entry => entry.value; | ||
} | ||
return index; | ||
} | ||
return result.map(mapper); | ||
}); | ||
@@ -477,0 +653,0 @@ /** |
@@ -1617,3 +1617,2 @@ module.exports = function BlastInitLoader(modifyPrototype) { | ||
Blast._fn_token_prepare(); | ||
Blast.emit('pre-extra-files'); | ||
@@ -1620,0 +1619,0 @@ |
const PENDING = 0, | ||
RESOLVED = 1, | ||
REJECTED = 2; | ||
REJECTED = 2, | ||
CANCELLED = 3; | ||
@@ -9,5 +10,8 @@ const REJECTED_REASON = Symbol('rejected_reason'), | ||
ON_FULFILLED = Symbol('on_fulfilled'), | ||
SUB_PLEDGES = Symbol('sub_pledges'), | ||
ON_CANCELLED = Symbol('on_cancelled'), | ||
SUB_PLEDGES = Symbol('sub_pledges'), | ||
ON_REJECTED = Symbol('on_rejected'), | ||
DO_RESOLVE = Symbol('do_resolve'), | ||
ON_FINALLY = Symbol('on_finally'), | ||
DO_FINALLY = Symbol('do_finally'), | ||
DO_REJECT = Symbol('do_reject'), | ||
@@ -97,2 +101,11 @@ EXECUTOR = Symbol('executor'), | ||
/** | ||
* An array of tasks to perform when this pledge is cancelled | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.9.1 | ||
* @version 0.9.1 | ||
*/ | ||
[ON_CANCELLED]: null, | ||
/** | ||
* The eventual resolved value | ||
@@ -138,13 +151,2 @@ * | ||
/** | ||
* Property that could be a function to cancel the pledge | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.7.0 | ||
* @version 0.7.0 | ||
* | ||
* @type {Function} | ||
*/ | ||
cancel: null, | ||
/** | ||
* Warn when an error is not caught | ||
@@ -526,2 +528,107 @@ * | ||
/** | ||
* Cancel the pledge | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.9.1 | ||
* @version 0.9.1 | ||
*/ | ||
AbstractPledge.setMethod(function cancel() { | ||
if (!this.isPending()) { | ||
return; | ||
} | ||
this[STATE] = CANCELLED; | ||
// Always do the on-cancel tasks as swiftly as possible | ||
return Swift.all(this[ON_CANCELLED]).finally(() => this[DO_FINALLY]()); | ||
}); | ||
/** | ||
* Do the given task when this pledge is cancelled | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.9.1 | ||
* @version 0.9.1 | ||
*/ | ||
AbstractPledge.setMethod(function onCancelled(task) { | ||
if (typeof task != 'function') { | ||
return; | ||
} | ||
if (!this.isPending()) { | ||
if (this.isCancelled() && task) { | ||
task(); | ||
} | ||
return; | ||
} | ||
if (!this[ON_CANCELLED]) { | ||
this[ON_CANCELLED] = []; | ||
} | ||
this[ON_CANCELLED].push(next => Swift.done(task(), next)); | ||
}); | ||
/** | ||
* Do all the finally callbacks | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.9.1 | ||
* @version 0.9.1 | ||
*/ | ||
AbstractPledge.setMethod(DO_FINALLY, function doFinally() { | ||
while (this[ON_FINALLY]?.length) { | ||
this[ON_FINALLY].shift()(); | ||
} | ||
}); | ||
/** | ||
* Has this pledge been resolved? | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.9.1 | ||
* @version 0.9.1 | ||
*/ | ||
AbstractPledge.setMethod(function isResolved() { | ||
return this[STATE] === RESOLVED; | ||
}); | ||
/** | ||
* Has this pledge been rejected? | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.9.1 | ||
* @version 0.9.1 | ||
*/ | ||
AbstractPledge.setMethod(function isRejected() { | ||
return this[STATE] === REJECTED; | ||
}); | ||
/** | ||
* Has this pledge been cancelled? | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.9.1 | ||
* @version 0.9.1 | ||
*/ | ||
AbstractPledge.setMethod(function isCancelled() { | ||
return this[STATE] === CANCELLED; | ||
}); | ||
/** | ||
* Is this pledge still pending? | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.9.1 | ||
* @version 0.9.1 | ||
*/ | ||
AbstractPledge.setMethod(function isPending() { | ||
return this[STATE] === PENDING; | ||
}); | ||
/** | ||
* The BasePledge Class | ||
@@ -1082,3 +1189,3 @@ * | ||
* @since 0.5.6 | ||
* @version 0.5.6 | ||
* @version 0.9.1 | ||
* | ||
@@ -1091,4 +1198,17 @@ * @param {Function} on_finally | ||
var constructor = this.constructor; | ||
let constructor = this.constructor; | ||
if (this.isPending() || this.isCancelled()) { | ||
if (!this[ON_FINALLY]) { | ||
this[ON_FINALLY] = []; | ||
} | ||
// We keep this in an array in case the pledge gets cancelled | ||
this[ON_FINALLY].push(on_finally); | ||
if (this.isCancelled()) { | ||
return this[DO_FINALLY](); | ||
} | ||
} | ||
return this.then( | ||
@@ -1383,5 +1503,6 @@ function afterResolved(value) { | ||
} | ||
this[DO_FINALLY](); | ||
}); | ||
/** | ||
@@ -1403,2 +1524,3 @@ * Reject with the given reason | ||
this[DO_REJECT](reason); | ||
this[DO_FINALLY](); | ||
}); | ||
@@ -1405,0 +1527,0 @@ |
@@ -436,3 +436,3 @@ module.exports = function serverFunctions(Blast, extras) { | ||
properties: options.depropertize, | ||
return_tokens: true | ||
return_tokens: true, | ||
}); | ||
@@ -443,3 +443,4 @@ } | ||
tokens = Blast.destringifyCode(tokens, { | ||
return_tokens: true | ||
return_tokens : true, | ||
depropertize : options.depropertize, | ||
}); | ||
@@ -1324,5 +1325,12 @@ } | ||
remove_symbol_names = options.remove_symbol_names ?? true, | ||
previous_type, | ||
current_type, | ||
depropertize = !!options.depropertize, | ||
property_map = new Map(), | ||
string_map = new Map(), | ||
usage_map = new Map(), | ||
first_char, | ||
next_type, | ||
last_char, | ||
is_string, | ||
new_code = 'const ', | ||
@@ -1336,3 +1344,2 @@ replaced = 0, | ||
next, | ||
type, | ||
i; | ||
@@ -1343,5 +1350,6 @@ | ||
first_char = token[0]; | ||
is_string = false; | ||
if (first_char != '"' && first_char != "'") { | ||
continue; | ||
if (first_char == '"' || first_char == "'") { | ||
is_string = true; | ||
} | ||
@@ -1357,26 +1365,40 @@ | ||
if (last_char != first_char) { | ||
is_string = false; | ||
} | ||
if (is_string) { | ||
current_type = 'string'; | ||
} else if (!depropertize) { | ||
continue; | ||
} else { | ||
current_type = Fn.getTokenType(token); | ||
} | ||
previous = tokens[i - 1]; | ||
type = Fn.getTokenType(previous); | ||
previous_type = Fn.getTokenType(previous); | ||
if (type == 'name') { | ||
if (previous_type == 'name') { | ||
continue; | ||
} | ||
if (type == 'whitespace') { | ||
if (previous_type == 'whitespace') { | ||
previous = tokens[i - 2]; | ||
type = Fn.getTokenType(previous); | ||
previous_type = Fn.getTokenType(previous); | ||
} | ||
if (!is_string) { | ||
if (previous != '.' && previous != '?.') { | ||
continue; | ||
} | ||
} | ||
next = tokens[i + 1]; | ||
type = Fn.getTokenType(next); | ||
next_type = Fn.getTokenType(next); | ||
if (type == 'whitespace') { | ||
if (next_type == 'whitespace') { | ||
next = tokens[i + 2]; | ||
type = Fn.getTokenType(next); | ||
next_type = Fn.getTokenType(next); | ||
} | ||
if (type == 'name') { | ||
if (next_type == 'name') { | ||
continue; | ||
@@ -1404,3 +1426,5 @@ } | ||
if (first_char == '"' && !token.includes("'")) { | ||
if (!is_string) { | ||
token = "'" + token + "'"; | ||
} else if (first_char == '"' && !token.includes("'")) { | ||
token = "'" + token.slice(1, -1) + "'"; | ||
@@ -1411,2 +1435,3 @@ } | ||
// Always add at least an empty array of indexes to the string map | ||
if (!indexes) { | ||
@@ -1417,2 +1442,22 @@ indexes = []; | ||
if (is_string) { | ||
indexes.push(i); | ||
} else { | ||
indexes = property_map.get(token); | ||
if (!indexes) { | ||
indexes = []; | ||
property_map.set(token, indexes); | ||
} | ||
indexes.push(i); | ||
} | ||
indexes = usage_map.get(token); | ||
if (!indexes) { | ||
indexes = []; | ||
usage_map.set(token, indexes); | ||
} | ||
indexes.push(i); | ||
@@ -1423,4 +1468,6 @@ } | ||
for (let [string, indexes] of string_map) { | ||
for (let [string, string_indexes] of string_map) { | ||
indexes = usage_map.get(string); | ||
// Ignore strings that are only used once | ||
@@ -1436,5 +1483,6 @@ if (indexes.length < 2) { | ||
sorted.push({ | ||
string : string, | ||
indexes : indexes, | ||
count : indexes.length, | ||
string : string, | ||
string_indexes : string_indexes, | ||
property_indexes : property_map.get(string), | ||
count : indexes.length, | ||
}); | ||
@@ -1449,4 +1497,8 @@ } | ||
for (let {string, indexes} of sorted) { | ||
// Re-use the string map for mapping | ||
string_map = new Map(); | ||
options.string_map = string_map; | ||
for (let {string, string_indexes, property_indexes} of sorted) { | ||
if (replaced) { | ||
@@ -1461,6 +1513,21 @@ new_code += '\n, '; | ||
for (i = 0; i < indexes.length; i++) { | ||
index = indexes[i]; | ||
tokens[indexes[i]] = new_name; | ||
string_map.set(string, new_name); | ||
for (i = 0; i < string_indexes.length; i++) { | ||
index = string_indexes[i]; | ||
tokens[index] = new_name; | ||
} | ||
if (!property_indexes?.length) { | ||
continue; | ||
} | ||
for (i = 0; i < property_indexes.length; i++) { | ||
index = property_indexes[i]; | ||
tokens[index] = '[' + new_name + ']'; | ||
if (tokens[index - 1] === '.') { | ||
tokens[index - 1] = ''; | ||
} | ||
} | ||
} | ||
@@ -1467,0 +1534,0 @@ |
{ | ||
"name": "protoblast", | ||
"description": "Native object expansion library", | ||
"version": "0.9.0", | ||
"version": "0.9.1", | ||
"author": "Jelle De Loecker <jelle@elevenways.be>", | ||
@@ -6,0 +6,0 @@ "keywords": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
962601
39598