mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(core): Add a schematics to migrate provideHttpClient to keep using the HttpXhrBackend implementation.
Exisiting applications will be migrated to keep using the XHR backend to prevent any breaking changes. `withXhr()` is to the `provideHttpClient` provider function.
This commit is contained in:
committed by
Jessica Janiuk
parent
5c432fb8bb
commit
3bc095d508
@@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {FetchBackend} from './fetch';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A constant defining the default the default Http Backend.
|
|
||||||
* Extracted to a separate file to facilitate G3 patches.
|
|
||||||
*/
|
|
||||||
export const NG_DEFAULT_HTTP_BACKEND = FetchBackend;
|
|
||||||
@@ -8,11 +8,10 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
DestroyRef,
|
DestroyRef,
|
||||||
|
ɵformatRuntimeError as formatRuntimeError,
|
||||||
inject,
|
inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
InjectionToken,
|
|
||||||
NgZone,
|
NgZone,
|
||||||
ɵformatRuntimeError as formatRuntimeError,
|
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {Observable, Observer} from 'rxjs';
|
import {Observable, Observer} from 'rxjs';
|
||||||
import {RuntimeErrorCode} from './errors';
|
import {RuntimeErrorCode} from './errors';
|
||||||
@@ -35,14 +34,6 @@ import type {} from 'zone.js';
|
|||||||
|
|
||||||
const XSSI_PREFIX = /^\)\]\}',?\n/;
|
const XSSI_PREFIX = /^\)\]\}',?\n/;
|
||||||
|
|
||||||
/**
|
|
||||||
* An internal injection token to reference `FetchBackend` implementation
|
|
||||||
* in a tree-shakable way.
|
|
||||||
*/
|
|
||||||
export const FETCH_BACKEND = new InjectionToken<FetchBackend>(
|
|
||||||
typeof ngDevMode === 'undefined' || ngDevMode ? 'FETCH_BACKEND' : '',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses `fetch` to send requests to a backend server.
|
* Uses `fetch` to send requests to a backend server.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -15,9 +15,8 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import {HttpBackend, HttpHandler, HttpInterceptorHandler} from './backend';
|
import {HttpBackend, HttpHandler, HttpInterceptorHandler} from './backend';
|
||||||
import {NG_DEFAULT_HTTP_BACKEND} from './backend-default-value';
|
|
||||||
import {HttpClient} from './client';
|
import {HttpClient} from './client';
|
||||||
import {FETCH_BACKEND, FetchBackend} from './fetch';
|
import {FetchBackend} from './fetch';
|
||||||
import {HTTP_INTERCEPTOR_FNS, HttpInterceptorFn, legacyInterceptorFnFactory} from './interceptor';
|
import {HTTP_INTERCEPTOR_FNS, HttpInterceptorFn, legacyInterceptorFnFactory} from './interceptor';
|
||||||
import {
|
import {
|
||||||
jsonpCallbackContext,
|
jsonpCallbackContext,
|
||||||
@@ -27,7 +26,6 @@ import {
|
|||||||
} from './jsonp';
|
} from './jsonp';
|
||||||
import {HttpXhrBackend} from './xhr';
|
import {HttpXhrBackend} from './xhr';
|
||||||
import {XSRF_COOKIE_NAME, XSRF_ENABLED, XSRF_HEADER_NAME, xsrfInterceptorFn} from './xsrf';
|
import {XSRF_COOKIE_NAME, XSRF_ENABLED, XSRF_HEADER_NAME, xsrfInterceptorFn} from './xsrf';
|
||||||
import {NG_DEFAULT_HTTP_BACKEND} from './backend-default-value';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifies a particular kind of `HttpFeature`.
|
* Identifies a particular kind of `HttpFeature`.
|
||||||
@@ -113,13 +111,13 @@ export function provideHttpClient(
|
|||||||
|
|
||||||
const providers: Provider[] = [
|
const providers: Provider[] = [
|
||||||
HttpClient,
|
HttpClient,
|
||||||
NG_DEFAULT_HTTP_BACKEND,
|
FetchBackend,
|
||||||
HttpInterceptorHandler,
|
HttpInterceptorHandler,
|
||||||
{provide: HttpHandler, useExisting: HttpInterceptorHandler},
|
{provide: HttpHandler, useExisting: HttpInterceptorHandler},
|
||||||
{
|
{
|
||||||
provide: HttpBackend,
|
provide: HttpBackend,
|
||||||
useFactory: () => {
|
useFactory: () => {
|
||||||
return inject(FETCH_BACKEND, {optional: true}) ?? inject(NG_DEFAULT_HTTP_BACKEND);
|
return inject(FetchBackend);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -298,7 +296,6 @@ export function withRequestsMadeViaParent(): HttpFeature<HttpFeatureKind.Request
|
|||||||
export function withFetch(): HttpFeature<HttpFeatureKind.Fetch> {
|
export function withFetch(): HttpFeature<HttpFeatureKind.Fetch> {
|
||||||
return makeHttpFeature(HttpFeatureKind.Fetch, [
|
return makeHttpFeature(HttpFeatureKind.Fetch, [
|
||||||
FetchBackend,
|
FetchBackend,
|
||||||
{provide: FETCH_BACKEND, useExisting: FetchBackend},
|
|
||||||
{provide: HttpBackend, useExisting: FetchBackend},
|
{provide: HttpBackend, useExisting: FetchBackend},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,10 @@ bundle_entrypoints = [
|
|||||||
"router-testing-module-migration",
|
"router-testing-module-migration",
|
||||||
"packages/core/schematics/ng-generate/router-testing-module-migration/index.js",
|
"packages/core/schematics/ng-generate/router-testing-module-migration/index.js",
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"http-xhr-backend",
|
||||||
|
"packages/core/schematics/migrations/http-xhr-backend/index.js",
|
||||||
|
],
|
||||||
]
|
]
|
||||||
|
|
||||||
rollup.rollup(
|
rollup.rollup(
|
||||||
@@ -133,6 +137,7 @@ rollup.rollup(
|
|||||||
"//:node_modules/semver",
|
"//:node_modules/semver",
|
||||||
"//packages/core/schematics:tsconfig_build",
|
"//packages/core/schematics:tsconfig_build",
|
||||||
"//packages/core/schematics/migrations/change-detection-eager",
|
"//packages/core/schematics/migrations/change-detection-eager",
|
||||||
|
"//packages/core/schematics/migrations/http-xhr-backend",
|
||||||
"//packages/core/schematics/ng-generate/cleanup-unused-imports",
|
"//packages/core/schematics/ng-generate/cleanup-unused-imports",
|
||||||
"//packages/core/schematics/ng-generate/common-to-standalone-migration",
|
"//packages/core/schematics/ng-generate/common-to-standalone-migration",
|
||||||
"//packages/core/schematics/ng-generate/control-flow-migration",
|
"//packages/core/schematics/ng-generate/control-flow-migration",
|
||||||
|
|||||||
@@ -4,6 +4,11 @@
|
|||||||
"version": "22.0.0",
|
"version": "22.0.0",
|
||||||
"description": "Adds `ChangeDetectionStrategy.Eager` to all components.",
|
"description": "Adds `ChangeDetectionStrategy.Eager` to all components.",
|
||||||
"factory": "./bundles/change-detection-eager.cjs#migrate"
|
"factory": "./bundles/change-detection-eager.cjs#migrate"
|
||||||
|
},
|
||||||
|
"http-xhr-backend": {
|
||||||
|
"version": "22.0.0",
|
||||||
|
"description": "Adds 'withXhr' to 'provideHttpClient' function calls when the 'HttpXhrBackend' is used. For more information see: https://angular.dev/api/common/http/withXhr",
|
||||||
|
"factory": "./bundles/http-xhr-backend.cjs#migrate"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
load("//tools:defaults.bzl", "jasmine_test", "ts_project")
|
||||||
|
|
||||||
|
package(
|
||||||
|
default_visibility = [
|
||||||
|
"//packages/core/schematics:__pkg__",
|
||||||
|
"//packages/core/schematics/test:__pkg__",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
ts_project(
|
||||||
|
name = "http-xhr-backend",
|
||||||
|
srcs = glob(
|
||||||
|
["**/*.ts"],
|
||||||
|
exclude = ["*.spec.ts"],
|
||||||
|
),
|
||||||
|
deps = [
|
||||||
|
"//:node_modules/@angular-devkit/schematics",
|
||||||
|
"//:node_modules/typescript",
|
||||||
|
"//packages/compiler-cli/private",
|
||||||
|
"//packages/core/schematics/utils",
|
||||||
|
"//packages/core/schematics/utils/tsurge",
|
||||||
|
"//packages/core/schematics/utils/tsurge/helpers/angular_devkit",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
ts_project(
|
||||||
|
name = "test_lib",
|
||||||
|
testonly = True,
|
||||||
|
srcs = glob(["*.spec.ts"]),
|
||||||
|
deps = [
|
||||||
|
":http-xhr-backend",
|
||||||
|
"//:node_modules/typescript",
|
||||||
|
"//packages/compiler-cli",
|
||||||
|
"//packages/core/schematics/utils/tsurge",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
jasmine_test(
|
||||||
|
name = "test",
|
||||||
|
data = [":test_lib"],
|
||||||
|
)
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {absoluteFrom} from '@angular/compiler-cli';
|
||||||
|
import {initMockFileSystem} from '@angular/compiler-cli/private/testing';
|
||||||
|
import {runTsurgeMigration} from '../../utils/tsurge/testing';
|
||||||
|
import {XhrBackendMigration} from './migration';
|
||||||
|
|
||||||
|
describe('http fetch backend migration', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
initMockFileSystem('Native');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update an empty provideHttpClient', async () => {
|
||||||
|
const {fs} = await runTsurgeMigration(new XhrBackendMigration(), [
|
||||||
|
{
|
||||||
|
name: absoluteFrom('/index.ts'),
|
||||||
|
isProgramRootFile: true,
|
||||||
|
contents: `
|
||||||
|
import {AppConfig} from '@angular/core';
|
||||||
|
import {provideHttpClient} from '@angular/common/http';
|
||||||
|
|
||||||
|
const config: AppConfig = [
|
||||||
|
provideHttpClient(),
|
||||||
|
]
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const actual = fs.readFile(absoluteFrom('/index.ts'));
|
||||||
|
expect(actual).toContain('provideHttpClient(withXhr())');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update provideHttpClient without withFetch', async () => {
|
||||||
|
const {fs} = await runTsurgeMigration(new XhrBackendMigration(), [
|
||||||
|
{
|
||||||
|
name: absoluteFrom('/index.ts'),
|
||||||
|
isProgramRootFile: true,
|
||||||
|
contents: `
|
||||||
|
import {AppConfig} from '@angular/core';
|
||||||
|
import {provideHttpClient, withInterceptorsFromDi, withXsrfConfiguration} from '@angular/common/http';
|
||||||
|
|
||||||
|
const config: AppConfig = [
|
||||||
|
provideHttpClient(withInterceptorsFromDi(), withXsrfConfiguration({})),
|
||||||
|
]
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const actual = fs.readFile(absoluteFrom('/index.ts'));
|
||||||
|
expect(actual).toContain(
|
||||||
|
'provideHttpClient(withXhr(), withInterceptorsFromDi(), withXsrfConfiguration({}))',
|
||||||
|
);
|
||||||
|
expect(actual).toMatch(/import \{.*withXhr.*\}/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update provideHttpClient to remove withFetch', async () => {
|
||||||
|
const {fs} = await runTsurgeMigration(new XhrBackendMigration(), [
|
||||||
|
{
|
||||||
|
name: absoluteFrom('/index.ts'),
|
||||||
|
isProgramRootFile: true,
|
||||||
|
contents: `
|
||||||
|
import {AppConfig} from '@angular/core';
|
||||||
|
import {provideHttpClient, withFetch, withInterceptorsFromDi, withXsrfConfiguration} from '@angular/common/http';
|
||||||
|
|
||||||
|
const config: AppConfig = [
|
||||||
|
provideHttpClient(withFetch(), withInterceptorsFromDi(), withXsrfConfiguration({})),
|
||||||
|
]
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const actual = fs.readFile(absoluteFrom('/index.ts'));
|
||||||
|
expect(actual).toContain(
|
||||||
|
'provideHttpClient(withInterceptorsFromDi(), withXsrfConfiguration({}))',
|
||||||
|
);
|
||||||
|
expect(actual).not.toContain('withFetch');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update provideHttpClient to remove withFetch as only arg', async () => {
|
||||||
|
const {fs} = await runTsurgeMigration(new XhrBackendMigration(), [
|
||||||
|
{
|
||||||
|
name: absoluteFrom('/index.ts'),
|
||||||
|
isProgramRootFile: true,
|
||||||
|
contents: `
|
||||||
|
import {AppConfig} from '@angular/core';
|
||||||
|
import {provideHttpClient, withFetch, withInterceptorsFromDi, withXsrfConfiguration} from '@angular/common/http';
|
||||||
|
|
||||||
|
const config: AppConfig = [
|
||||||
|
provideHttpClient(withFetch()),
|
||||||
|
]
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const actual = fs.readFile(absoluteFrom('/index.ts'));
|
||||||
|
expect(actual).toContain('provideHttpClient()');
|
||||||
|
expect(actual).not.toContain('withFetch');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update provideHttpClient if withXhr is already present', async () => {
|
||||||
|
const {fs} = await runTsurgeMigration(new XhrBackendMigration(), [
|
||||||
|
{
|
||||||
|
name: absoluteFrom('/index.ts'),
|
||||||
|
isProgramRootFile: true,
|
||||||
|
contents: `
|
||||||
|
import {AppConfig} from '@angular/core';
|
||||||
|
import {provideHttpClient, withXhr, withInterceptorsFromDi, withXsrfConfiguration} from '@angular/common/http';
|
||||||
|
|
||||||
|
const config: AppConfig = [
|
||||||
|
provideHttpClient(withXhr(), withInterceptorsFromDi(), withXsrfConfiguration({})),
|
||||||
|
]
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const actual = fs.readFile(absoluteFrom('/index.ts'));
|
||||||
|
expect(actual).toContain(
|
||||||
|
'provideHttpClient(withXhr(), withInterceptorsFromDi(), withXsrfConfiguration({})),',
|
||||||
|
);
|
||||||
|
expect(actual).not.toContain('withFetch');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* @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.dev/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Rule} from '@angular-devkit/schematics';
|
||||||
|
import {runMigrationInDevkit} from '../../utils/tsurge/helpers/angular_devkit';
|
||||||
|
import {XhrBackendMigration} from './migration';
|
||||||
|
|
||||||
|
export function migrate(): Rule {
|
||||||
|
return async (tree) => {
|
||||||
|
await runMigrationInDevkit({
|
||||||
|
tree,
|
||||||
|
getMigration: () => new XhrBackendMigration(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {ImportManager} from '@angular/compiler-cli/private/migrations';
|
||||||
|
import ts from 'typescript';
|
||||||
|
import {
|
||||||
|
confirmAsSerializable,
|
||||||
|
ProgramInfo,
|
||||||
|
projectFile,
|
||||||
|
ProjectFile,
|
||||||
|
Replacement,
|
||||||
|
Serializable,
|
||||||
|
TextUpdate,
|
||||||
|
TsurgeFunnelMigration,
|
||||||
|
} from '../../utils/tsurge';
|
||||||
|
import {applyImportManagerChanges} from '../../utils/tsurge/helpers/apply_import_manager';
|
||||||
|
import {getImportSpecifier, getNamedImports} from '../../utils/typescript/imports';
|
||||||
|
|
||||||
|
const HTTP = '@angular/common/http';
|
||||||
|
const provideHttpClient = 'provideHttpClient';
|
||||||
|
|
||||||
|
const WITH_FETCH = 'withFetch';
|
||||||
|
const WITH_XHR = 'withXhr';
|
||||||
|
const CORE_PACKAGE = '@angular/core';
|
||||||
|
const HTTP_PACKAGE = '@angular/common/http';
|
||||||
|
const PROVIDE_HTTP_CLIENT = 'provideHttpClient';
|
||||||
|
|
||||||
|
export interface CompilationUnitData {
|
||||||
|
replacements: Replacement[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MigrationConfig {
|
||||||
|
/**
|
||||||
|
* Whether to migrate this component template to self-closing tags.
|
||||||
|
*/
|
||||||
|
shouldMigrate?: (containingFile: ProjectFile) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const provideHttpClientIdentifier = ts.factory.createIdentifier('provideHttpClient');
|
||||||
|
|
||||||
|
export class XhrBackendMigration extends TsurgeFunnelMigration<
|
||||||
|
CompilationUnitData,
|
||||||
|
CompilationUnitData
|
||||||
|
> {
|
||||||
|
constructor(private readonly config: MigrationConfig = {}) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
override async analyze(info: ProgramInfo): Promise<Serializable<CompilationUnitData>> {
|
||||||
|
const replacements: Replacement[] = [];
|
||||||
|
const importManager = new ImportManager();
|
||||||
|
|
||||||
|
for (const sourceFile of info.sourceFiles) {
|
||||||
|
const walk = (node: ts.Node): void => {
|
||||||
|
const file = projectFile(sourceFile, info);
|
||||||
|
if (this.config.shouldMigrate && !this.config.shouldMigrate(file)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const httpImports = getNamedImports(sourceFile, HTTP);
|
||||||
|
if (!httpImports) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const importSpecifier = getImportSpecifier(sourceFile, HTTP, provideHttpClient);
|
||||||
|
if (!importSpecifier) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.forEachChild(walk);
|
||||||
|
|
||||||
|
if (!ts.isCallExpression(node)) return;
|
||||||
|
if (!ts.isIdentifier(node.expression)) return;
|
||||||
|
if (node.expression.text !== 'provideHttpClient') return;
|
||||||
|
const withFetchNode = node.arguments.find((arg) => {
|
||||||
|
return (
|
||||||
|
ts.isCallExpression(arg) &&
|
||||||
|
ts.isIdentifier(arg.expression) &&
|
||||||
|
arg.expression.text === WITH_FETCH
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const withXhrNode = node.arguments.find((arg) => {
|
||||||
|
return (
|
||||||
|
ts.isCallExpression(arg) &&
|
||||||
|
ts.isIdentifier(arg.expression) &&
|
||||||
|
arg.expression.text === WITH_XHR
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!withFetchNode && !withXhrNode) {
|
||||||
|
replacements.push(
|
||||||
|
new Replacement(
|
||||||
|
projectFile(sourceFile, info),
|
||||||
|
new TextUpdate({
|
||||||
|
position: node.arguments.pos,
|
||||||
|
end: node.arguments.pos,
|
||||||
|
toInsert: node.arguments.length ? 'withXhr(), ' : 'withXhr()',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
importManager.addImport({
|
||||||
|
exportModuleSpecifier: HTTP_PACKAGE,
|
||||||
|
exportSymbolName: WITH_XHR,
|
||||||
|
requestedFile: sourceFile,
|
||||||
|
});
|
||||||
|
} else if (withFetchNode) {
|
||||||
|
const isLastArg = node.arguments[node.arguments.length - 1] === withFetchNode;
|
||||||
|
replacements.push(
|
||||||
|
new Replacement(
|
||||||
|
projectFile(sourceFile, info),
|
||||||
|
new TextUpdate({
|
||||||
|
position: withFetchNode.getStart(),
|
||||||
|
end: isLastArg ? withFetchNode.getEnd() : withFetchNode.getEnd() + 2, // +2 to remove the comma and space, could be improved
|
||||||
|
toInsert: '',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
importManager.removeImport(sourceFile, 'withFetch', HTTP_PACKAGE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
sourceFile.forEachChild(walk);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyImportManagerChanges(importManager, replacements, info.sourceFiles, info);
|
||||||
|
return confirmAsSerializable({replacements});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async combine(
|
||||||
|
unitA: CompilationUnitData,
|
||||||
|
unitB: CompilationUnitData,
|
||||||
|
): Promise<Serializable<CompilationUnitData>> {
|
||||||
|
const combined = [...unitA.replacements, ...unitB.replacements];
|
||||||
|
return confirmAsSerializable({replacements: combined});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async globalMeta(data: CompilationUnitData): Promise<Serializable<CompilationUnitData>> {
|
||||||
|
return confirmAsSerializable(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
override async stats(data: CompilationUnitData) {
|
||||||
|
return confirmAsSerializable({});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async migrate(data: CompilationUnitData) {
|
||||||
|
return {replacements: data.replacements};
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user