610 lines
17 KiB
JavaScript
610 lines
17 KiB
JavaScript
import { d as _inherits, e as _createSuper, a as _classCallCheck, _ as _createClass, g as _get, h as _getPrototypeOf, b as _objectWithoutProperties, i as _set } from '../_rollupPluginBabelHelpers-b054ecd2.js';
|
|
import { DIRECTION } from '../core/utils.js';
|
|
import ChangeDetails from '../core/change-details.js';
|
|
import Masked from './base.js';
|
|
import PatternInputDefinition, { DEFAULT_INPUT_DEFINITIONS } from './pattern/input-definition.js';
|
|
import PatternFixedDefinition from './pattern/fixed-definition.js';
|
|
import ChunksTailDetails from './pattern/chunk-tail-details.js';
|
|
import PatternCursor from './pattern/cursor.js';
|
|
import createMask from './factory.js';
|
|
import IMask from '../core/holder.js';
|
|
import './regexp.js';
|
|
import '../core/continuous-tail-details.js';
|
|
|
|
var _excluded = ["_blocks"];
|
|
|
|
/**
|
|
Pattern mask
|
|
@param {Object} opts
|
|
@param {Object} opts.blocks
|
|
@param {Object} opts.definitions
|
|
@param {string} opts.placeholderChar
|
|
@param {boolean} opts.lazy
|
|
*/
|
|
var MaskedPattern = /*#__PURE__*/function (_Masked) {
|
|
_inherits(MaskedPattern, _Masked);
|
|
|
|
var _super = _createSuper(MaskedPattern);
|
|
|
|
/** */
|
|
|
|
/** */
|
|
|
|
/** Single char for empty input */
|
|
|
|
/** Show placeholder only when needed */
|
|
function MaskedPattern() {
|
|
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
|
|
_classCallCheck(this, MaskedPattern);
|
|
|
|
// TODO type $Shape<MaskedPatternOptions>={} does not work
|
|
opts.definitions = Object.assign({}, DEFAULT_INPUT_DEFINITIONS, opts.definitions);
|
|
return _super.call(this, Object.assign({}, MaskedPattern.DEFAULTS, opts));
|
|
}
|
|
/**
|
|
@override
|
|
@param {Object} opts
|
|
*/
|
|
|
|
|
|
_createClass(MaskedPattern, [{
|
|
key: "_update",
|
|
value: function _update() {
|
|
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
opts.definitions = Object.assign({}, this.definitions, opts.definitions);
|
|
|
|
_get(_getPrototypeOf(MaskedPattern.prototype), "_update", this).call(this, opts);
|
|
|
|
this._rebuildMask();
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_rebuildMask",
|
|
value: function _rebuildMask() {
|
|
var _this = this;
|
|
|
|
var defs = this.definitions;
|
|
this._blocks = [];
|
|
this._stops = [];
|
|
this._maskedBlocks = {};
|
|
var pattern = this.mask;
|
|
if (!pattern || !defs) return;
|
|
var unmaskingBlock = false;
|
|
var optionalBlock = false;
|
|
|
|
for (var i = 0; i < pattern.length; ++i) {
|
|
if (this.blocks) {
|
|
var _ret = function () {
|
|
var p = pattern.slice(i);
|
|
var bNames = Object.keys(_this.blocks).filter(function (bName) {
|
|
return p.indexOf(bName) === 0;
|
|
}); // order by key length
|
|
|
|
bNames.sort(function (a, b) {
|
|
return b.length - a.length;
|
|
}); // use block name with max length
|
|
|
|
var bName = bNames[0];
|
|
|
|
if (bName) {
|
|
// $FlowFixMe no ideas
|
|
var maskedBlock = createMask(Object.assign({
|
|
parent: _this,
|
|
lazy: _this.lazy,
|
|
eager: _this.eager,
|
|
placeholderChar: _this.placeholderChar,
|
|
overwrite: _this.overwrite
|
|
}, _this.blocks[bName]));
|
|
|
|
if (maskedBlock) {
|
|
_this._blocks.push(maskedBlock); // store block index
|
|
|
|
|
|
if (!_this._maskedBlocks[bName]) _this._maskedBlocks[bName] = [];
|
|
|
|
_this._maskedBlocks[bName].push(_this._blocks.length - 1);
|
|
}
|
|
|
|
i += bName.length - 1;
|
|
return "continue";
|
|
}
|
|
}();
|
|
|
|
if (_ret === "continue") continue;
|
|
}
|
|
|
|
var char = pattern[i];
|
|
var isInput = (char in defs);
|
|
|
|
if (char === MaskedPattern.STOP_CHAR) {
|
|
this._stops.push(this._blocks.length);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (char === '{' || char === '}') {
|
|
unmaskingBlock = !unmaskingBlock;
|
|
continue;
|
|
}
|
|
|
|
if (char === '[' || char === ']') {
|
|
optionalBlock = !optionalBlock;
|
|
continue;
|
|
}
|
|
|
|
if (char === MaskedPattern.ESCAPE_CHAR) {
|
|
++i;
|
|
char = pattern[i];
|
|
if (!char) break;
|
|
isInput = false;
|
|
}
|
|
|
|
var def = isInput ? new PatternInputDefinition({
|
|
parent: this,
|
|
lazy: this.lazy,
|
|
eager: this.eager,
|
|
placeholderChar: this.placeholderChar,
|
|
mask: defs[char],
|
|
isOptional: optionalBlock
|
|
}) : new PatternFixedDefinition({
|
|
char: char,
|
|
eager: this.eager,
|
|
isUnmasking: unmaskingBlock
|
|
});
|
|
|
|
this._blocks.push(def);
|
|
}
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "state",
|
|
get: function get() {
|
|
return Object.assign({}, _get(_getPrototypeOf(MaskedPattern.prototype), "state", this), {
|
|
_blocks: this._blocks.map(function (b) {
|
|
return b.state;
|
|
})
|
|
});
|
|
},
|
|
set: function set(state) {
|
|
var _blocks = state._blocks,
|
|
maskedState = _objectWithoutProperties(state, _excluded);
|
|
|
|
this._blocks.forEach(function (b, bi) {
|
|
return b.state = _blocks[bi];
|
|
});
|
|
|
|
_set(_getPrototypeOf(MaskedPattern.prototype), "state", maskedState, this, true);
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "reset",
|
|
value: function reset() {
|
|
_get(_getPrototypeOf(MaskedPattern.prototype), "reset", this).call(this);
|
|
|
|
this._blocks.forEach(function (b) {
|
|
return b.reset();
|
|
});
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "isComplete",
|
|
get: function get() {
|
|
return this._blocks.every(function (b) {
|
|
return b.isComplete;
|
|
});
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "isFilled",
|
|
get: function get() {
|
|
return this._blocks.every(function (b) {
|
|
return b.isFilled;
|
|
});
|
|
}
|
|
}, {
|
|
key: "isFixed",
|
|
get: function get() {
|
|
return this._blocks.every(function (b) {
|
|
return b.isFixed;
|
|
});
|
|
}
|
|
}, {
|
|
key: "isOptional",
|
|
get: function get() {
|
|
return this._blocks.every(function (b) {
|
|
return b.isOptional;
|
|
});
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "doCommit",
|
|
value: function doCommit() {
|
|
this._blocks.forEach(function (b) {
|
|
return b.doCommit();
|
|
});
|
|
|
|
_get(_getPrototypeOf(MaskedPattern.prototype), "doCommit", this).call(this);
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "unmaskedValue",
|
|
get: function get() {
|
|
return this._blocks.reduce(function (str, b) {
|
|
return str += b.unmaskedValue;
|
|
}, '');
|
|
},
|
|
set: function set(unmaskedValue) {
|
|
_set(_getPrototypeOf(MaskedPattern.prototype), "unmaskedValue", unmaskedValue, this, true);
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "value",
|
|
get: function get() {
|
|
// TODO return _value when not in change?
|
|
return this._blocks.reduce(function (str, b) {
|
|
return str += b.value;
|
|
}, '');
|
|
},
|
|
set: function set(value) {
|
|
_set(_getPrototypeOf(MaskedPattern.prototype), "value", value, this, true);
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "appendTail",
|
|
value: function appendTail(tail) {
|
|
return _get(_getPrototypeOf(MaskedPattern.prototype), "appendTail", this).call(this, tail).aggregate(this._appendPlaceholder());
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "_appendEager",
|
|
value: function _appendEager() {
|
|
var _this$_mapPosToBlock;
|
|
|
|
var details = new ChangeDetails();
|
|
var startBlockIndex = (_this$_mapPosToBlock = this._mapPosToBlock(this.value.length)) === null || _this$_mapPosToBlock === void 0 ? void 0 : _this$_mapPosToBlock.index;
|
|
if (startBlockIndex == null) return details; // TODO test if it works for nested pattern masks
|
|
|
|
if (this._blocks[startBlockIndex].isFilled) ++startBlockIndex;
|
|
|
|
for (var bi = startBlockIndex; bi < this._blocks.length; ++bi) {
|
|
var d = this._blocks[bi]._appendEager();
|
|
|
|
if (!d.inserted) break;
|
|
details.aggregate(d);
|
|
}
|
|
|
|
return details;
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "_appendCharRaw",
|
|
value: function _appendCharRaw(ch) {
|
|
var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
|
|
var blockIter = this._mapPosToBlock(this.value.length);
|
|
|
|
var details = new ChangeDetails();
|
|
if (!blockIter) return details;
|
|
|
|
for (var bi = blockIter.index;; ++bi) {
|
|
var _flags$_beforeTailSta;
|
|
|
|
var _block = this._blocks[bi];
|
|
if (!_block) break;
|
|
|
|
var blockDetails = _block._appendChar(ch, Object.assign({}, flags, {
|
|
_beforeTailState: (_flags$_beforeTailSta = flags._beforeTailState) === null || _flags$_beforeTailSta === void 0 ? void 0 : _flags$_beforeTailSta._blocks[bi]
|
|
}));
|
|
|
|
var skip = blockDetails.skip;
|
|
details.aggregate(blockDetails);
|
|
if (skip || blockDetails.rawInserted) break; // go next char
|
|
}
|
|
|
|
return details;
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "extractTail",
|
|
value: function extractTail() {
|
|
var _this2 = this;
|
|
|
|
var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length;
|
|
var chunkTail = new ChunksTailDetails();
|
|
if (fromPos === toPos) return chunkTail;
|
|
|
|
this._forEachBlocksInRange(fromPos, toPos, function (b, bi, bFromPos, bToPos) {
|
|
var blockChunk = b.extractTail(bFromPos, bToPos);
|
|
blockChunk.stop = _this2._findStopBefore(bi);
|
|
blockChunk.from = _this2._blockStartPos(bi);
|
|
if (blockChunk instanceof ChunksTailDetails) blockChunk.blockIndex = bi;
|
|
chunkTail.extend(blockChunk);
|
|
});
|
|
|
|
return chunkTail;
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "extractInput",
|
|
value: function extractInput() {
|
|
var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length;
|
|
var flags = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
if (fromPos === toPos) return '';
|
|
var input = '';
|
|
|
|
this._forEachBlocksInRange(fromPos, toPos, function (b, _, fromPos, toPos) {
|
|
input += b.extractInput(fromPos, toPos, flags);
|
|
});
|
|
|
|
return input;
|
|
}
|
|
}, {
|
|
key: "_findStopBefore",
|
|
value: function _findStopBefore(blockIndex) {
|
|
var stopBefore;
|
|
|
|
for (var si = 0; si < this._stops.length; ++si) {
|
|
var stop = this._stops[si];
|
|
if (stop <= blockIndex) stopBefore = stop;else break;
|
|
}
|
|
|
|
return stopBefore;
|
|
}
|
|
/** Appends placeholder depending on laziness */
|
|
|
|
}, {
|
|
key: "_appendPlaceholder",
|
|
value: function _appendPlaceholder(toBlockIndex) {
|
|
var _this3 = this;
|
|
|
|
var details = new ChangeDetails();
|
|
if (this.lazy && toBlockIndex == null) return details;
|
|
|
|
var startBlockIter = this._mapPosToBlock(this.value.length);
|
|
|
|
if (!startBlockIter) return details;
|
|
var startBlockIndex = startBlockIter.index;
|
|
var endBlockIndex = toBlockIndex != null ? toBlockIndex : this._blocks.length;
|
|
|
|
this._blocks.slice(startBlockIndex, endBlockIndex).forEach(function (b) {
|
|
if (!b.lazy || toBlockIndex != null) {
|
|
// $FlowFixMe `_blocks` may not be present
|
|
var args = b._blocks != null ? [b._blocks.length] : [];
|
|
|
|
var bDetails = b._appendPlaceholder.apply(b, args);
|
|
|
|
_this3._value += bDetails.inserted;
|
|
details.aggregate(bDetails);
|
|
}
|
|
});
|
|
|
|
return details;
|
|
}
|
|
/** Finds block in pos */
|
|
|
|
}, {
|
|
key: "_mapPosToBlock",
|
|
value: function _mapPosToBlock(pos) {
|
|
var accVal = '';
|
|
|
|
for (var bi = 0; bi < this._blocks.length; ++bi) {
|
|
var _block2 = this._blocks[bi];
|
|
var blockStartPos = accVal.length;
|
|
accVal += _block2.value;
|
|
|
|
if (pos <= accVal.length) {
|
|
return {
|
|
index: bi,
|
|
offset: pos - blockStartPos
|
|
};
|
|
}
|
|
}
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_blockStartPos",
|
|
value: function _blockStartPos(blockIndex) {
|
|
return this._blocks.slice(0, blockIndex).reduce(function (pos, b) {
|
|
return pos += b.value.length;
|
|
}, 0);
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "_forEachBlocksInRange",
|
|
value: function _forEachBlocksInRange(fromPos) {
|
|
var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length;
|
|
var fn = arguments.length > 2 ? arguments[2] : undefined;
|
|
|
|
var fromBlockIter = this._mapPosToBlock(fromPos);
|
|
|
|
if (fromBlockIter) {
|
|
var toBlockIter = this._mapPosToBlock(toPos); // process first block
|
|
|
|
|
|
var isSameBlock = toBlockIter && fromBlockIter.index === toBlockIter.index;
|
|
var fromBlockStartPos = fromBlockIter.offset;
|
|
var fromBlockEndPos = toBlockIter && isSameBlock ? toBlockIter.offset : this._blocks[fromBlockIter.index].value.length;
|
|
fn(this._blocks[fromBlockIter.index], fromBlockIter.index, fromBlockStartPos, fromBlockEndPos);
|
|
|
|
if (toBlockIter && !isSameBlock) {
|
|
// process intermediate blocks
|
|
for (var bi = fromBlockIter.index + 1; bi < toBlockIter.index; ++bi) {
|
|
fn(this._blocks[bi], bi, 0, this._blocks[bi].value.length);
|
|
} // process last block
|
|
|
|
|
|
fn(this._blocks[toBlockIter.index], toBlockIter.index, 0, toBlockIter.offset);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "remove",
|
|
value: function remove() {
|
|
var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length;
|
|
|
|
var removeDetails = _get(_getPrototypeOf(MaskedPattern.prototype), "remove", this).call(this, fromPos, toPos);
|
|
|
|
this._forEachBlocksInRange(fromPos, toPos, function (b, _, bFromPos, bToPos) {
|
|
removeDetails.aggregate(b.remove(bFromPos, bToPos));
|
|
});
|
|
|
|
return removeDetails;
|
|
}
|
|
/**
|
|
@override
|
|
*/
|
|
|
|
}, {
|
|
key: "nearestInputPos",
|
|
value: function nearestInputPos(cursorPos) {
|
|
var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DIRECTION.NONE;
|
|
if (!this._blocks.length) return 0;
|
|
var cursor = new PatternCursor(this, cursorPos);
|
|
|
|
if (direction === DIRECTION.NONE) {
|
|
// -------------------------------------------------
|
|
// NONE should only go out from fixed to the right!
|
|
// -------------------------------------------------
|
|
if (cursor.pushRightBeforeInput()) return cursor.pos;
|
|
cursor.popState();
|
|
if (cursor.pushLeftBeforeInput()) return cursor.pos;
|
|
return this.value.length;
|
|
} // FORCE is only about a|* otherwise is 0
|
|
|
|
|
|
if (direction === DIRECTION.LEFT || direction === DIRECTION.FORCE_LEFT) {
|
|
// try to break fast when *|a
|
|
if (direction === DIRECTION.LEFT) {
|
|
cursor.pushRightBeforeFilled();
|
|
if (cursor.ok && cursor.pos === cursorPos) return cursorPos;
|
|
cursor.popState();
|
|
} // forward flow
|
|
|
|
|
|
cursor.pushLeftBeforeInput();
|
|
cursor.pushLeftBeforeRequired();
|
|
cursor.pushLeftBeforeFilled(); // backward flow
|
|
|
|
if (direction === DIRECTION.LEFT) {
|
|
cursor.pushRightBeforeInput();
|
|
cursor.pushRightBeforeRequired();
|
|
if (cursor.ok && cursor.pos <= cursorPos) return cursor.pos;
|
|
cursor.popState();
|
|
if (cursor.ok && cursor.pos <= cursorPos) return cursor.pos;
|
|
cursor.popState();
|
|
}
|
|
|
|
if (cursor.ok) return cursor.pos;
|
|
if (direction === DIRECTION.FORCE_LEFT) return 0;
|
|
cursor.popState();
|
|
if (cursor.ok) return cursor.pos;
|
|
cursor.popState();
|
|
if (cursor.ok) return cursor.pos; // cursor.popState();
|
|
// if (
|
|
// cursor.pushRightBeforeInput() &&
|
|
// // TODO HACK for lazy if has aligned left inside fixed and has came to the start - use start position
|
|
// (!this.lazy || this.extractInput())
|
|
// ) return cursor.pos;
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (direction === DIRECTION.RIGHT || direction === DIRECTION.FORCE_RIGHT) {
|
|
// forward flow
|
|
cursor.pushRightBeforeInput();
|
|
cursor.pushRightBeforeRequired();
|
|
if (cursor.pushRightBeforeFilled()) return cursor.pos;
|
|
if (direction === DIRECTION.FORCE_RIGHT) return this.value.length; // backward flow
|
|
|
|
cursor.popState();
|
|
if (cursor.ok) return cursor.pos;
|
|
cursor.popState();
|
|
if (cursor.ok) return cursor.pos;
|
|
return this.nearestInputPos(cursorPos, DIRECTION.LEFT);
|
|
}
|
|
|
|
return cursorPos;
|
|
}
|
|
/** Get block by name */
|
|
|
|
}, {
|
|
key: "maskedBlock",
|
|
value: function maskedBlock(name) {
|
|
return this.maskedBlocks(name)[0];
|
|
}
|
|
/** Get all blocks by name */
|
|
|
|
}, {
|
|
key: "maskedBlocks",
|
|
value: function maskedBlocks(name) {
|
|
var _this4 = this;
|
|
|
|
var indices = this._maskedBlocks[name];
|
|
if (!indices) return [];
|
|
return indices.map(function (gi) {
|
|
return _this4._blocks[gi];
|
|
});
|
|
}
|
|
}]);
|
|
|
|
return MaskedPattern;
|
|
}(Masked);
|
|
MaskedPattern.DEFAULTS = {
|
|
lazy: true,
|
|
placeholderChar: '_'
|
|
};
|
|
MaskedPattern.STOP_CHAR = '`';
|
|
MaskedPattern.ESCAPE_CHAR = '\\';
|
|
MaskedPattern.InputDefinition = PatternInputDefinition;
|
|
MaskedPattern.FixedDefinition = PatternFixedDefinition;
|
|
IMask.MaskedPattern = MaskedPattern;
|
|
|
|
export { MaskedPattern as default };
|