Skip to content

Commit 8caeb47

Browse files
sebastianhaenialexeagle
authored andcommitted
fix(@angular-devkit/schematics): fix generate mangling files containing wide characters
Executing a command like `ng generate component my-component` can sometimes lead to mangled Angular module files when inserting the component into `declaration` and adding the import. This happens if the file contains characters that are wider than one byte e.g. a copyright sign or an umlaut. Today it is expected to be able to use two byte long characters in code. The `UpdateBuffer` class operates using Buffer objects which use byte arrays internally. Using text node positions provided by the TypeScript library, these will not match up. This change looks up the textual position inside the Buffer and uses the correct index. Closes #7851, #7950
1 parent e16c8bb commit 8caeb47

File tree

3 files changed

+29
-7
lines changed

3 files changed

+29
-7
lines changed

packages/angular_devkit/schematics/src/tree/recorder.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ export class UpdateRecorderBase implements UpdateRecorder {
3030
if (c0 == 0xEF && c1 == 0xBB && c2 == 0xBF) {
3131
return new UpdateRecorderBom(entry);
3232
} else if (c0 === 0xFF && c1 == 0xFE) {
33-
return new UpdateRecorderBom(entry, 2);
33+
return new UpdateRecorderBom(entry);
3434
} else if (c0 === 0xFE && c1 == 0xFF) {
35-
return new UpdateRecorderBom(entry, 2);
35+
return new UpdateRecorderBom(entry);
3636
}
3737

3838
return new UpdateRecorderBase(entry);
@@ -70,7 +70,7 @@ export class UpdateRecorderBase implements UpdateRecorder {
7070

7171

7272
export class UpdateRecorderBom extends UpdateRecorderBase {
73-
constructor(entry: FileEntry, private _delta = 3) {
73+
constructor(entry: FileEntry, private _delta = 1) {
7474
super(entry);
7575
}
7676

packages/angular_devkit/schematics/src/utility/update-buffer.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -201,19 +201,31 @@ export class UpdateBuffer {
201201
}
202202

203203
protected _slice(start: number): [Chunk, Chunk] {
204-
this._assertIndex(start);
204+
// If start is longer than the content, use start, otherwise determine exact position in string.
205+
const index = start >= this._originalContent.length ? start : this._getTextPosition(start);
206+
207+
this._assertIndex(index);
205208

206209
// Find the chunk by going through the list.
207-
const h = this._linkedList.find(chunk => start <= chunk.end);
210+
const h = this._linkedList.find(chunk => index <= chunk.end);
208211
if (!h) {
209212
throw Error('Chunk cannot be found.');
210213
}
211214

212-
if (start == h.end && h.next !== null) {
215+
if (index == h.end && h.next !== null) {
213216
return [h, h.next];
214217
}
215218

216-
return [h, h.slice(start)];
219+
return [h, h.slice(index)];
220+
}
221+
222+
/**
223+
* Gets the position in the content based on the position in the string.
224+
* Some characters might be wider than one byte, thus we have to determine the position using
225+
* string functions.
226+
*/
227+
protected _getTextPosition(index: number): number {
228+
return Buffer.from(this._originalContent.toString().substring(0, index)).length;
217229
}
218230

219231
get length(): number {

packages/angular_devkit/schematics/src/utility/update-buffer_spec.ts

+10
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ describe('UpdateBuffer', () => {
5858
mb.insertLeft(6, Buffer.from('Awesome '));
5959
expect(mb.toString()).toBe('Hello Great Awesome Beautiful World');
6060
});
61+
62+
it('works with special characters', () => {
63+
const mb = new UpdateBuffer(Buffer.from('Ülaut'));
64+
65+
mb.insertLeft(1, Buffer.from('m'));
66+
expect(mb.toString()).toBe('Ümlaut');
67+
68+
mb.insertLeft(0, Buffer.from('Hello '));
69+
expect(mb.toString()).toBe('Hello Ümlaut');
70+
});
6171
});
6272

6373
describe('delete', () => {

0 commit comments

Comments
 (0)