@emmetio/extract-abbreviation
Advanced tools
Comparing version 0.1.6 to 0.2.0
@@ -7,4 +7,5 @@ 'use strict'; | ||
class StreamReader { | ||
constructor(string) { | ||
constructor(string, start) { | ||
this.string = string; | ||
this.start = start || 0; | ||
this.pos = this.string.length; | ||
@@ -14,3 +15,3 @@ } | ||
sol() { | ||
return this.pos === 0; | ||
return this.pos === this.start; | ||
} | ||
@@ -29,2 +30,6 @@ | ||
eat(match) { | ||
if (this.sol()) { | ||
return false; | ||
} | ||
const ok = typeof match === 'function' | ||
@@ -262,3 +267,4 @@ ? match(this.peek()) | ||
syntax: 'markup', | ||
lookAhead: null | ||
lookAhead: null, | ||
prefix: '' | ||
}; | ||
@@ -278,3 +284,3 @@ | ||
* current caret position. So in order to properly expand abbreviation, user | ||
* must explicitly move caret right after auto-inserted braces. Whith this option | ||
* must explicitly move caret right after auto-inserted braces. With this option | ||
* enabled, parser will search for closing braces right after `pos`. Default is `true` | ||
@@ -284,2 +290,5 @@ * @param {String} [options.syntax] Name of context syntax of expanded abbreviation. | ||
* and `{}` are not supported thus not extracted. | ||
* @param {String} [options.prefix] A string that should precede abbreviation in | ||
* order to make it successfully extracted. If given, the abbreviation will be | ||
* extracted from the nearest `prefix` occurrence. | ||
* @return {Object} Object with `abbreviation` and its `location` in given line | ||
@@ -293,5 +302,5 @@ * if abbreviation can be extracted, `null` otherwise | ||
if (typeof options === 'boolean') { | ||
options = Object.assign(defaultOptions, { lookAhead: options }); | ||
options = Object.assign({}, defaultOptions, { lookAhead: options }); | ||
} else { | ||
options = Object.assign(defaultOptions, options); | ||
options = Object.assign({}, defaultOptions, options); | ||
} | ||
@@ -304,3 +313,8 @@ | ||
let c; | ||
const stream = new StreamReader(line); | ||
const start = getStartOffset(line, pos, options.prefix); | ||
if (start === -1) { | ||
return null; | ||
} | ||
const stream = new StreamReader(line, start); | ||
stream.pos = pos; | ||
@@ -336,3 +350,7 @@ const stack = []; | ||
abbreviation, | ||
location: pos - abbreviation.length | ||
location: pos - abbreviation.length, | ||
start: options.prefix | ||
? start - options.prefix.length | ||
: pos - abbreviation.length, | ||
end: pos | ||
}; | ||
@@ -344,3 +362,3 @@ } | ||
* Returns new `line` index which is right after characters beyound `pos` that | ||
* edditor will likely automatically close, e.g. }, ], and quotes | ||
* editor will likely automatically close, e.g. }, ], and quotes | ||
* @param {String} line | ||
@@ -364,2 +382,83 @@ * @param {Number} pos | ||
/** | ||
* Returns start offset (left limit) in `line` where we should stop looking for | ||
* abbreviation: it’s nearest to `pos` location of `prefix` token | ||
* @param {String} line | ||
* @param {Number} pos | ||
* @param {String} prefix | ||
* @return {Number} | ||
*/ | ||
function getStartOffset(line, pos, prefix) { | ||
if (!prefix) { | ||
return 0; | ||
} | ||
const stream = new StreamReader(line); | ||
const compiledPrefix = String(prefix).split('').map(code); | ||
stream.pos = pos; | ||
let result; | ||
while (!stream.sol()) { | ||
if (consumePair(stream, SQUARE_BRACE_R, SQUARE_BRACE_L) || consumePair(stream, CURLY_BRACE_R, CURLY_BRACE_L)) { | ||
continue; | ||
} | ||
result = stream.pos; | ||
if (consumeArray(stream, compiledPrefix)) { | ||
return result; | ||
} | ||
stream.pos--; | ||
} | ||
return -1; | ||
} | ||
/** | ||
* Consumes full character pair, if possible | ||
* @param {StreamReader} stream | ||
* @param {Number} close | ||
* @param {Number} open | ||
* @return {Boolean} | ||
*/ | ||
function consumePair(stream, close, open) { | ||
const start = stream.pos; | ||
if (stream.eat(close)) { | ||
while (!stream.sol()) { | ||
if (stream.eat(open)) { | ||
return true; | ||
} | ||
stream.pos--; | ||
} | ||
} | ||
stream.pos = start; | ||
return false; | ||
} | ||
/** | ||
* Consumes all character codes from given array, right-to-left, if possible | ||
* @param {StreamReader} stream | ||
* @param {Number[]} arr | ||
*/ | ||
function consumeArray(stream, arr) { | ||
const start = stream.pos; | ||
let consumed = false; | ||
for (let i = arr.length - 1; i >= 0 && !stream.sol(); i--) { | ||
if (!stream.eat(arr[i])) { | ||
break; | ||
} | ||
consumed = i === 0; | ||
} | ||
if (!consumed) { | ||
stream.pos = start; | ||
} | ||
return consumed; | ||
} | ||
function has(arr, value) { | ||
@@ -366,0 +465,0 @@ return arr.indexOf(value) !== -1; |
@@ -5,4 +5,5 @@ /** | ||
class StreamReader { | ||
constructor(string) { | ||
constructor(string, start) { | ||
this.string = string; | ||
this.start = start || 0; | ||
this.pos = this.string.length; | ||
@@ -12,3 +13,3 @@ } | ||
sol() { | ||
return this.pos === 0; | ||
return this.pos === this.start; | ||
} | ||
@@ -27,2 +28,6 @@ | ||
eat(match) { | ||
if (this.sol()) { | ||
return false; | ||
} | ||
const ok = typeof match === 'function' | ||
@@ -260,3 +265,4 @@ ? match(this.peek()) | ||
syntax: 'markup', | ||
lookAhead: null | ||
lookAhead: null, | ||
prefix: '' | ||
}; | ||
@@ -276,3 +282,3 @@ | ||
* current caret position. So in order to properly expand abbreviation, user | ||
* must explicitly move caret right after auto-inserted braces. Whith this option | ||
* must explicitly move caret right after auto-inserted braces. With this option | ||
* enabled, parser will search for closing braces right after `pos`. Default is `true` | ||
@@ -282,2 +288,5 @@ * @param {String} [options.syntax] Name of context syntax of expanded abbreviation. | ||
* and `{}` are not supported thus not extracted. | ||
* @param {String} [options.prefix] A string that should precede abbreviation in | ||
* order to make it successfully extracted. If given, the abbreviation will be | ||
* extracted from the nearest `prefix` occurrence. | ||
* @return {Object} Object with `abbreviation` and its `location` in given line | ||
@@ -291,5 +300,5 @@ * if abbreviation can be extracted, `null` otherwise | ||
if (typeof options === 'boolean') { | ||
options = Object.assign(defaultOptions, { lookAhead: options }); | ||
options = Object.assign({}, defaultOptions, { lookAhead: options }); | ||
} else { | ||
options = Object.assign(defaultOptions, options); | ||
options = Object.assign({}, defaultOptions, options); | ||
} | ||
@@ -302,3 +311,8 @@ | ||
let c; | ||
const stream = new StreamReader(line); | ||
const start = getStartOffset(line, pos, options.prefix); | ||
if (start === -1) { | ||
return null; | ||
} | ||
const stream = new StreamReader(line, start); | ||
stream.pos = pos; | ||
@@ -334,3 +348,7 @@ const stack = []; | ||
abbreviation, | ||
location: pos - abbreviation.length | ||
location: pos - abbreviation.length, | ||
start: options.prefix | ||
? start - options.prefix.length | ||
: pos - abbreviation.length, | ||
end: pos | ||
}; | ||
@@ -342,3 +360,3 @@ } | ||
* Returns new `line` index which is right after characters beyound `pos` that | ||
* edditor will likely automatically close, e.g. }, ], and quotes | ||
* editor will likely automatically close, e.g. }, ], and quotes | ||
* @param {String} line | ||
@@ -362,2 +380,83 @@ * @param {Number} pos | ||
/** | ||
* Returns start offset (left limit) in `line` where we should stop looking for | ||
* abbreviation: it’s nearest to `pos` location of `prefix` token | ||
* @param {String} line | ||
* @param {Number} pos | ||
* @param {String} prefix | ||
* @return {Number} | ||
*/ | ||
function getStartOffset(line, pos, prefix) { | ||
if (!prefix) { | ||
return 0; | ||
} | ||
const stream = new StreamReader(line); | ||
const compiledPrefix = String(prefix).split('').map(code); | ||
stream.pos = pos; | ||
let result; | ||
while (!stream.sol()) { | ||
if (consumePair(stream, SQUARE_BRACE_R, SQUARE_BRACE_L) || consumePair(stream, CURLY_BRACE_R, CURLY_BRACE_L)) { | ||
continue; | ||
} | ||
result = stream.pos; | ||
if (consumeArray(stream, compiledPrefix)) { | ||
return result; | ||
} | ||
stream.pos--; | ||
} | ||
return -1; | ||
} | ||
/** | ||
* Consumes full character pair, if possible | ||
* @param {StreamReader} stream | ||
* @param {Number} close | ||
* @param {Number} open | ||
* @return {Boolean} | ||
*/ | ||
function consumePair(stream, close, open) { | ||
const start = stream.pos; | ||
if (stream.eat(close)) { | ||
while (!stream.sol()) { | ||
if (stream.eat(open)) { | ||
return true; | ||
} | ||
stream.pos--; | ||
} | ||
} | ||
stream.pos = start; | ||
return false; | ||
} | ||
/** | ||
* Consumes all character codes from given array, right-to-left, if possible | ||
* @param {StreamReader} stream | ||
* @param {Number[]} arr | ||
*/ | ||
function consumeArray(stream, arr) { | ||
const start = stream.pos; | ||
let consumed = false; | ||
for (let i = arr.length - 1; i >= 0 && !stream.sol(); i--) { | ||
if (!stream.eat(arr[i])) { | ||
break; | ||
} | ||
consumed = i === 0; | ||
} | ||
if (!consumed) { | ||
stream.pos = start; | ||
} | ||
return consumed; | ||
} | ||
function has(arr, value) { | ||
@@ -364,0 +463,0 @@ return arr.indexOf(value) !== -1; |
{ | ||
"name": "@emmetio/extract-abbreviation", | ||
"version": "0.1.6", | ||
"version": "0.2.0", | ||
"description": "Extracts Emmet abbreviation from string", | ||
@@ -5,0 +5,0 @@ "main": "dist/extract-abbreviation.cjs.js", |
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
24059
803