Skip to content

Commit

Permalink
fix(@angular-devkit/schematics): do not generate an UpdateBuffer for …
Browse files Browse the repository at this point in the history
…created and overridden files

`UpdateBuffer` only supports UTF-8 encoded files, which causes schematics to emit corrupted binary like files such as images.

This commit also introduce an errors when the `UpdateRecorder` is used for non UTF-8 files.

Closes #25174

(cherry picked from commit 22c1cb6)
  • Loading branch information
alan-agius4 authored and clydin committed May 10, 2023
1 parent 70d224c commit 5a35970
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 24 deletions.
4 changes: 2 additions & 2 deletions goldens/public-api/angular_devkit/schematics/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,13 +495,13 @@ export class HostSink extends SimpleSinkBase {
// (undocumented)
_done(): Observable<void>;
// (undocumented)
protected _filesToCreate: Map<Path, UpdateBufferBase>;
protected _filesToCreate: Map<Path, Buffer>;
// (undocumented)
protected _filesToDelete: Set<Path>;
// (undocumented)
protected _filesToRename: Set<[Path, Path]>;
// (undocumented)
protected _filesToUpdate: Map<Path, UpdateBufferBase>;
protected _filesToUpdate: Map<Path, Buffer>;
// (undocumented)
protected _force: boolean;
// (undocumented)
Expand Down
7 changes: 1 addition & 6 deletions packages/angular/pwa/pwa/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,7 @@ export default function (options: PwaOptions): Rule {
return chain([
externalSchematic('@schematics/angular', 'service-worker', swOptions),
mergeWith(apply(url('./files/root'), [template({ ...options }), move(sourcePath)])),
mergeWith(
apply(url('./files/assets'), [
template({ ...options }),
move(posix.join(sourcePath, 'assets')),
]),
),
mergeWith(apply(url('./files/assets'), [move(posix.join(sourcePath, 'assets'))])),
...[...indexFiles].map((path) => updateIndexFile(path)),
]);
};
Expand Down
4 changes: 2 additions & 2 deletions packages/angular_devkit/schematics/src/sink/dryrun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ export class DryRunSink extends HostSink {
return;
}

this._subject.next({ kind: 'create', path, content: content.generate() });
this._subject.next({ kind: 'create', path, content });
});
this._filesToUpdate.forEach((content, path) => {
this._subject.next({ kind: 'update', path, content: content.generate() });
this._subject.next({ kind: 'update', path, content });
});

this._subject.complete();
Expand Down
20 changes: 9 additions & 11 deletions packages/angular_devkit/schematics/src/sink/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ import {
reduce,
} from 'rxjs';
import { CreateFileAction } from '../tree/action';
import { UpdateBufferBase } from '../utility/update-buffer';
import { SimpleSinkBase } from './sink';

export class HostSink extends SimpleSinkBase {
protected _filesToDelete = new Set<Path>();
protected _filesToRename = new Set<[Path, Path]>();
protected _filesToCreate = new Map<Path, UpdateBufferBase>();
protected _filesToUpdate = new Map<Path, UpdateBufferBase>();
protected _filesToCreate = new Map<Path, Buffer>();
protected _filesToUpdate = new Map<Path, Buffer>();

constructor(protected _host: virtualFs.Host, protected _force = false) {
super();
Expand Down Expand Up @@ -56,20 +55,23 @@ export class HostSink extends SimpleSinkBase {
}

protected _overwriteFile(path: Path, content: Buffer): Observable<void> {
this._filesToUpdate.set(path, UpdateBufferBase.create(content));
this._filesToUpdate.set(path, content);

return EMPTY;
}

protected _createFile(path: Path, content: Buffer): Observable<void> {
this._filesToCreate.set(path, UpdateBufferBase.create(content));
this._filesToCreate.set(path, content);

return EMPTY;
}

protected _renameFile(from: Path, to: Path): Observable<void> {
this._filesToRename.add([from, to]);

return EMPTY;
}

protected _deleteFile(path: Path): Observable<void> {
if (this._filesToCreate.has(path)) {
this._filesToCreate.delete(path);
Expand All @@ -91,14 +93,10 @@ export class HostSink extends SimpleSinkBase {
concatMap(([_, [path, to]]) => this._host.rename(path, to)),
),
observableFrom([...this._filesToCreate.entries()]).pipe(
concatMap(([path, buffer]) => {
return this._host.write(path, buffer.generate() as {} as virtualFs.FileBuffer);
}),
concatMap(([path, buffer]) => this._host.write(path, buffer)),
),
observableFrom([...this._filesToUpdate.entries()]).pipe(
concatMap(([path, buffer]) => {
return this._host.write(path, buffer.generate() as {} as virtualFs.FileBuffer);
}),
concatMap(([path, buffer]) => this._host.write(path, buffer)),
),
).pipe(reduce(() => {}));
}
Expand Down
2 changes: 1 addition & 1 deletion packages/angular_devkit/schematics/src/tree/recorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class UpdateRecorderBase implements UpdateRecorder {

constructor(entry: FileEntry) {
this._original = Buffer.from(entry.content);
this._content = UpdateBufferBase.create(entry.content);
this._content = UpdateBufferBase.create(entry.path, entry.content);
this._path = entry.path;
}

Expand Down
17 changes: 15 additions & 2 deletions packages/angular_devkit/schematics/src/utility/update-buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import { BaseException } from '@angular-devkit/core';
import MagicString from 'magic-string';
import { TextDecoder } from 'node:util';

export class IndexOutOfBoundException extends BaseException {
constructor(index: number, min: number, max = Infinity) {
Expand All @@ -32,11 +33,23 @@ export abstract class UpdateBufferBase {
/**
* Creates an UpdateBufferBase instance.
*
* @param contentPath The path of the update buffer instance.
* @param originalContent The original content of the update buffer instance.
* @returns An UpdateBufferBase instance.
*/
static create(originalContent: Buffer): UpdateBufferBase {
return new UpdateBuffer(originalContent);
static create(contentPath: string, originalContent: Buffer): UpdateBufferBase {
try {
// We only support utf8 encoding.
new TextDecoder('utf8', { fatal: true }).decode(originalContent);

return new UpdateBuffer(originalContent);
} catch (e) {
if (e instanceof TypeError) {
throw new Error(`Failed to decode "${contentPath}" as UTF-8 text.`);
}

throw e;
}
}
}

Expand Down

0 comments on commit 5a35970

Please sign in to comment.