@angular-devkit/schematics
Version:
Angular Schematics - Library
325 lines (324 loc) • 11.3 kB
JavaScript
"use strict";
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpdateBuffer2 = exports.UpdateBuffer = exports.UpdateBufferBase = exports.Chunk = exports.ContentCannotBeRemovedException = exports.IndexOutOfBoundException = void 0;
const core_1 = require("@angular-devkit/core");
const magic_string_1 = __importDefault(require("magic-string"));
const environment_options_1 = require("./environment-options");
const linked_list_1 = require("./linked-list");
class IndexOutOfBoundException extends core_1.BaseException {
constructor(index, min, max = Infinity) {
super(`Index ${index} outside of range [${min}, ${max}].`);
}
}
exports.IndexOutOfBoundException = IndexOutOfBoundException;
/** @deprecated Since v13.0 */
class ContentCannotBeRemovedException extends core_1.BaseException {
constructor() {
super(`User tried to remove content that was marked essential.`);
}
}
exports.ContentCannotBeRemovedException = ContentCannotBeRemovedException;
/**
* A Chunk description, including left/right content that has been inserted.
* If _left/_right is null, this means that content was deleted. If the _content is null,
* it means the content itself was deleted.
*
* @see UpdateBuffer
* @deprecated Since v13.0
*/
class Chunk {
constructor(start, end, originalContent) {
this.start = start;
this.end = end;
this.originalContent = originalContent;
this._left = Buffer.alloc(0);
this._right = Buffer.alloc(0);
this._assertLeft = false;
this._assertRight = false;
this.next = null;
this._content = originalContent.slice(start, end);
}
get length() {
return ((this._left ? this._left.length : 0) +
(this._content ? this._content.length : 0) +
(this._right ? this._right.length : 0));
}
toString(encoding = 'utf-8') {
return ((this._left ? this._left.toString(encoding) : '') +
(this._content ? this._content.toString(encoding) : '') +
(this._right ? this._right.toString(encoding) : ''));
}
slice(start) {
if (start < this.start || start > this.end) {
throw new IndexOutOfBoundException(start, this.start, this.end);
}
// Update _content to the new indices.
const newChunk = new Chunk(start, this.end, this.originalContent);
// If this chunk has _content, reslice the original _content. We move the _right so we are not
// losing any data here. If this chunk has been deleted, the next chunk should also be deleted.
if (this._content) {
this._content = this.originalContent.slice(this.start, start);
}
else {
newChunk._content = this._content;
if (this._right === null) {
newChunk._left = null;
}
}
this.end = start;
// Move _right to the new chunk.
newChunk._right = this._right;
this._right = this._right && Buffer.alloc(0);
// Update essentials.
if (this._assertRight) {
newChunk._assertRight = true;
this._assertRight = false;
}
// Update the linked list.
newChunk.next = this.next;
this.next = newChunk;
return newChunk;
}
append(buffer, essential) {
if (!this._right) {
if (essential) {
throw new ContentCannotBeRemovedException();
}
return;
}
const outro = this._right;
this._right = Buffer.alloc(outro.length + buffer.length);
outro.copy(this._right, 0);
buffer.copy(this._right, outro.length);
if (essential) {
this._assertRight = true;
}
}
prepend(buffer, essential) {
if (!this._left) {
if (essential) {
throw new ContentCannotBeRemovedException();
}
return;
}
const intro = this._left;
this._left = Buffer.alloc(intro.length + buffer.length);
intro.copy(this._left, 0);
buffer.copy(this._left, intro.length);
if (essential) {
this._assertLeft = true;
}
}
assert(left, _content, right) {
if (left && this._assertLeft) {
throw new ContentCannotBeRemovedException();
}
if (right && this._assertRight) {
throw new ContentCannotBeRemovedException();
}
}
remove(left, content, right) {
if (left) {
if (this._assertLeft) {
throw new ContentCannotBeRemovedException();
}
this._left = null;
}
if (content) {
this._content = null;
}
if (right) {
if (this._assertRight) {
throw new ContentCannotBeRemovedException();
}
this._right = null;
}
}
copy(target, start) {
if (this._left) {
this._left.copy(target, start);
start += this._left.length;
}
if (this._content) {
this._content.copy(target, start);
start += this._content.length;
}
if (this._right) {
this._right.copy(target, start);
start += this._right.length;
}
return start;
}
}
exports.Chunk = Chunk;
/**
* Base class for an update buffer implementation that allows buffers to be inserted to the _right
* or _left, or deleted, while keeping indices to the original buffer.
*/
class UpdateBufferBase {
constructor(_originalContent) {
this._originalContent = _originalContent;
}
/**
* Creates an UpdateBufferBase instance. Depending on the NG_UPDATE_BUFFER_V2
* environment variable, will either create an UpdateBuffer or an UpdateBuffer2
* instance.
*
* See: https://github.com/angular/angular-cli/issues/21110
*
* @param originalContent The original content of the update buffer instance.
* @returns An UpdateBufferBase instance.
*/
static create(originalContent) {
return environment_options_1.updateBufferV2Enabled
? new UpdateBuffer2(originalContent)
: new UpdateBuffer(originalContent);
}
}
exports.UpdateBufferBase = UpdateBufferBase;
/**
* An utility class that allows buffers to be inserted to the _right or _left, or deleted, while
* keeping indices to the original buffer.
*
* The constructor takes an original buffer, and keeps it into a linked list of chunks, smaller
* buffers that keep track of _content inserted to the _right or _left of it.
*
* Since the Node Buffer structure is non-destructive when slicing, we try to use slicing to create
* new chunks, and always keep chunks pointing to the original content.
*
* @deprecated Since v13.0
*/
class UpdateBuffer extends UpdateBufferBase {
constructor(originalContent) {
super(originalContent);
this._linkedList = new linked_list_1.LinkedList(new Chunk(0, originalContent.length, originalContent));
}
_assertIndex(index) {
if (index < 0 || index > this._originalContent.length) {
throw new IndexOutOfBoundException(index, 0, this._originalContent.length);
}
}
_slice(start) {
let index;
if (start >= this._originalContent.length) {
index = start;
}
else if (start < 0) {
index = this._originalContent.length + start;
}
else {
index = this._getTextPosition(start);
}
this._assertIndex(index);
// Find the chunk by going through the list.
const h = this._linkedList.find((chunk) => index <= chunk.end);
if (!h) {
throw Error('Chunk cannot be found.');
}
if (index == h.end && h.next !== null) {
return [h, h.next];
}
return [h, h.slice(index)];
}
/**
* Gets the position in the content based on the position in the string.
* Some characters might be wider than one byte, thus we have to determine the position using
* string functions.
*/
_getTextPosition(index) {
return Buffer.from(this._originalContent.toString().substring(0, index)).length;
}
get length() {
return this._linkedList.reduce((acc, chunk) => acc + chunk.length, 0);
}
get original() {
return this._originalContent;
}
toString(encoding = 'utf-8') {
return this._linkedList.reduce((acc, chunk) => acc + chunk.toString(encoding), '');
}
generate() {
const result = Buffer.allocUnsafe(this.length);
let i = 0;
this._linkedList.forEach((chunk) => {
chunk.copy(result, i);
i += chunk.length;
});
return result;
}
insertLeft(index, content, assert = false) {
this._slice(index)[0].append(content, assert);
}
insertRight(index, content, assert = false) {
this._slice(index)[1].prepend(content, assert);
}
remove(index, length) {
if (length === 0) {
return;
}
const end = index + length;
const first = this._slice(index)[1];
const last = this._slice(end)[1];
let curr;
for (curr = first; curr && curr !== last; curr = curr.next) {
curr.assert(curr !== first, curr !== last, curr === first);
}
for (curr = first; curr && curr !== last; curr = curr.next) {
curr.remove(curr !== first, curr !== last, curr === first);
}
if (curr) {
curr.remove(true, false, false);
}
}
}
exports.UpdateBuffer = UpdateBuffer;
/**
* An utility class that allows buffers to be inserted to the _right or _left, or deleted, while
* keeping indices to the original buffer.
*/
class UpdateBuffer2 extends UpdateBufferBase {
constructor() {
super(...arguments);
this._mutatableContent = new magic_string_1.default(this._originalContent.toString());
}
_assertIndex(index) {
if (index < 0 || index > this._originalContent.length) {
throw new IndexOutOfBoundException(index, 0, this._originalContent.length);
}
}
get length() {
return this._mutatableContent.length();
}
get original() {
return this._originalContent;
}
toString() {
return this._mutatableContent.toString();
}
generate() {
return Buffer.from(this.toString());
}
insertLeft(index, content) {
this._assertIndex(index);
this._mutatableContent.appendLeft(index, content.toString());
}
insertRight(index, content) {
this._assertIndex(index);
this._mutatableContent.appendRight(index, content.toString());
}
remove(index, length) {
this._assertIndex(index);
this._mutatableContent.remove(index, index + length);
}
}
exports.UpdateBuffer2 = UpdateBuffer2;