Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

Commit f8884ab

Browse files
committed
fix(@angular-devkit/schematics): add support for BOM to UpdateRecorder
Fixes angular/angular-cli#10644
1 parent 6ce9f83 commit f8884ab

File tree

3 files changed

+103
-1
lines changed

3 files changed

+103
-1
lines changed

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

+36
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,23 @@ export class UpdateRecorderBase implements UpdateRecorder {
2121
this._path = entry.path;
2222
}
2323

24+
static createFromFileEntry(entry: FileEntry): UpdateRecorderBase {
25+
const c0 = entry.content.readUInt8(0, true);
26+
const c1 = entry.content.readUInt8(1, true);
27+
const c2 = entry.content.readUInt8(2, true);
28+
29+
// Check if we're BOM.
30+
if (c0 == 0xEF && c1 == 0xBB && c2 == 0xBF) {
31+
return new UpdateRecorderBom(entry);
32+
} else if (c0 === 0xFF && c1 == 0xFE) {
33+
return new UpdateRecorderBom(entry, 2);
34+
} else if (c0 === 0xFE && c1 == 0xFF) {
35+
return new UpdateRecorderBom(entry, 2);
36+
}
37+
38+
return new UpdateRecorderBase(entry);
39+
}
40+
2441
get path() { return this._path; }
2542

2643
// These just record changes.
@@ -50,3 +67,22 @@ export class UpdateRecorderBase implements UpdateRecorder {
5067
return this._content.generate();
5168
}
5269
}
70+
71+
72+
export class UpdateRecorderBom extends UpdateRecorderBase {
73+
constructor(entry: FileEntry, private _delta = 3) {
74+
super(entry);
75+
}
76+
77+
insertLeft(index: number, content: Buffer | string) {
78+
return super.insertLeft(index + this._delta, content);
79+
}
80+
81+
insertRight(index: number, content: Buffer | string) {
82+
return super.insertRight(index + this._delta, content);
83+
}
84+
85+
remove(index: number, length: number) {
86+
return super.remove(index + this._delta, length);
87+
}
88+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import { normalize } from '@angular-devkit/core';
9+
import { SimpleFileEntry } from './entry';
10+
import { UpdateRecorderBase, UpdateRecorderBom } from './recorder';
11+
12+
describe('UpdateRecorderBase', () => {
13+
it('works for simple files', () => {
14+
const buffer = new Buffer('Hello World');
15+
const entry = new SimpleFileEntry(normalize('/some/path'), buffer);
16+
17+
const recorder = new UpdateRecorderBase(entry);
18+
recorder.insertLeft(5, ' beautiful');
19+
const result = recorder.apply(buffer);
20+
expect(result.toString()).toBe('Hello beautiful World');
21+
});
22+
23+
it('works for simple files (2)', () => {
24+
const buffer = new Buffer('Hello World');
25+
const entry = new SimpleFileEntry(normalize('/some/path'), buffer);
26+
27+
const recorder = new UpdateRecorderBase(entry);
28+
recorder.insertRight(5, ' beautiful');
29+
const result = recorder.apply(buffer);
30+
expect(result.toString()).toBe('Hello beautiful World');
31+
});
32+
33+
it('can create the proper recorder', () => {
34+
const e = new SimpleFileEntry(normalize('/some/path'), new Buffer('hello'));
35+
expect(UpdateRecorderBase.createFromFileEntry(e) instanceof UpdateRecorderBase).toBe(true);
36+
expect(UpdateRecorderBase.createFromFileEntry(e) instanceof UpdateRecorderBom).toBe(false);
37+
});
38+
39+
it('can create the proper recorder (bom)', () => {
40+
const eBom = new SimpleFileEntry(normalize('/some/path'), new Buffer('\uFEFFhello'));
41+
expect(UpdateRecorderBase.createFromFileEntry(eBom) instanceof UpdateRecorderBase).toBe(true);
42+
expect(UpdateRecorderBase.createFromFileEntry(eBom) instanceof UpdateRecorderBom).toBe(true);
43+
});
44+
45+
it('supports empty files', () => {
46+
const e = new SimpleFileEntry(normalize('/some/path'), new Buffer(''));
47+
expect(UpdateRecorderBase.createFromFileEntry(e) instanceof UpdateRecorderBase).toBe(true);
48+
});
49+
50+
it('supports empty files (bom)', () => {
51+
const eBom = new SimpleFileEntry(normalize('/some/path'), new Buffer('\uFEFF'));
52+
expect(UpdateRecorderBase.createFromFileEntry(eBom) instanceof UpdateRecorderBase).toBe(true);
53+
});
54+
});
55+
56+
describe('UpdateRecorderBom', () => {
57+
it('works for simple files', () => {
58+
const buffer = new Buffer('\uFEFFHello World');
59+
const entry = new SimpleFileEntry(normalize('/some/path'), buffer);
60+
61+
const recorder = new UpdateRecorderBom(entry);
62+
recorder.insertLeft(5, ' beautiful');
63+
const result = recorder.apply(buffer);
64+
expect(result.toString()).toBe('\uFEFFHello beautiful World');
65+
});
66+
});

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ export class VirtualTree implements Tree {
186186
throw new FileDoesNotExistException(path);
187187
}
188188

189-
return new UpdateRecorderBase(entry);
189+
return UpdateRecorderBase.createFromFileEntry(entry);
190190
}
191191

192192
commitUpdate(record: UpdateRecorder) {

0 commit comments

Comments
 (0)