Skip to content

Commit 854d184

Browse files
committed
fix(@angular-devkit/build-angular): support @angular/localize 10.1.0
Several utility functions within `@angular/localize` were updated in 10.1.0. This change ensures that this newer version will function with 10.1.0 of `@angular-devkit/build-angular`.
1 parent c576b11 commit 854d184

File tree

1 file changed

+80
-29
lines changed

1 file changed

+80
-29
lines changed

packages/angular_devkit/build_angular/src/utils/process-bundle.ts

Lines changed: 80 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import templateBuilder from '@babel/template';
1919
import { createHash } from 'crypto';
2020
import * as fs from 'fs';
2121
import * as path from 'path';
22+
import { lt as semverLt } from 'semver';
2223
import { RawSourceMap, SourceMapConsumer, SourceMapGenerator } from 'source-map';
2324
import { minify } from 'terser';
2425
import * as v8 from 'v8';
@@ -32,6 +33,8 @@ import {
3233
import { allowMangle, allowMinify, shouldBeautify } from './environment-options';
3334
import { I18nOptions } from './i18n-options';
3435

36+
type LocalizeUtilities = typeof import('@angular/localize/src/tools/src/source_file_utils');
37+
3538
const cacache = require('cacache');
3639
const deserialize = ((v8 as unknown) as { deserialize(buffer: Buffer): unknown }).deserialize;
3740

@@ -547,7 +550,6 @@ export async function createI18nPlugins(
547550
localeDataContent?: string,
548551
) {
549552
const plugins = [];
550-
// tslint:disable-next-line: no-implicit-dependencies
551553
const localizeDiag = await import('@angular/localize/src/tools/src/diagnostics');
552554

553555
const diagnostics = new localizeDiag.Diagnostics();
@@ -723,9 +725,7 @@ async function inlineLocalesDirect(ast: ParseResult, options: InlineOptions) {
723725

724726
const { default: generate } = await import('@babel/generator');
725727

726-
// tslint:disable-next-line: no-implicit-dependencies
727728
const utils = await import('@angular/localize/src/tools/src/source_file_utils');
728-
// tslint:disable-next-line: no-implicit-dependencies
729729
const localizeDiag = await import('@angular/localize/src/tools/src/diagnostics');
730730

731731
const diagnostics = new localizeDiag.Diagnostics();
@@ -829,21 +829,24 @@ function inlineCopyOnly(options: InlineOptions) {
829829
function findLocalizePositions(
830830
ast: ParseResult,
831831
options: InlineOptions,
832-
// tslint:disable-next-line: no-implicit-dependencies
833-
utils: typeof import('@angular/localize/src/tools/src/source_file_utils'),
832+
utils: LocalizeUtilities,
834833
): LocalizePosition[] {
835834
const positions: LocalizePosition[] = [];
835+
836+
// Workaround to ensure a path hub is present for traversal
837+
const { File } = require('@babel/core');
838+
const file = new File({}, { code: options.code, ast });
839+
836840
if (options.es5) {
837-
traverse(ast, {
838-
CallExpression(path: NodePath<types.CallExpression>) {
841+
traverse(file.ast, {
842+
CallExpression(path) {
839843
const callee = path.get('callee');
840844
if (
841845
callee.isIdentifier() &&
842846
callee.node.name === localizeName &&
843847
utils.isGlobalIdentifier(callee)
844848
) {
845-
const messageParts = utils.unwrapMessagePartsFromLocalizeCall(path);
846-
const expressions = utils.unwrapSubstitutionsFromLocalizeCall(path.node);
849+
const [messageParts, expressions] = unwrapLocalizeCall(path, utils);
847850
positions.push({
848851
// tslint:disable-next-line: no-non-null-assertion
849852
start: path.node.start!,
@@ -856,32 +859,80 @@ function findLocalizePositions(
856859
},
857860
});
858861
} else {
859-
const traverseFast = ((types as unknown) as {
860-
traverseFast: (node: types.Node, enter: (node: types.Node) => void) => void;
861-
}).traverseFast;
862-
863-
traverseFast(ast, node => {
864-
if (
865-
node.type === 'TaggedTemplateExpression' &&
866-
types.isIdentifier(node.tag) &&
867-
node.tag.name === localizeName
868-
) {
869-
const messageParts = utils.unwrapMessagePartsFromTemplateLiteral(node.quasi.quasis);
870-
positions.push({
871-
// tslint:disable-next-line: no-non-null-assertion
872-
start: node.start!,
873-
// tslint:disable-next-line: no-non-null-assertion
874-
end: node.end!,
875-
messageParts,
876-
expressions: node.quasi.expressions,
877-
});
878-
}
862+
traverse(file.ast, {
863+
TaggedTemplateExpression(path) {
864+
if (types.isIdentifier(path.node.tag) && path.node.tag.name === localizeName) {
865+
const [messageParts, expressions] = unwrapTemplateLiteral(path, utils);
866+
positions.push({
867+
// tslint:disable-next-line: no-non-null-assertion
868+
start: path.node.start!,
869+
// tslint:disable-next-line: no-non-null-assertion
870+
end: path.node.end!,
871+
messageParts,
872+
expressions,
873+
});
874+
}
875+
},
879876
});
880877
}
881878

882879
return positions;
883880
}
884881

882+
// TODO: Remove this for v11.
883+
// This check allows the CLI to support both FW 10.0 and 10.1
884+
let localizeOld: boolean | undefined;
885+
886+
function unwrapTemplateLiteral(
887+
path: NodePath<types.TemplateLiteral>,
888+
utils: LocalizeUtilities,
889+
): [TemplateStringsArray, types.Expression[]] {
890+
if (localizeOld === undefined) {
891+
const { version: localizeVersion } = require('@angular/localize/package.json');
892+
localizeOld = semverLt(localizeVersion, '10.1.0-rc.0', { includePrerelease: true });
893+
}
894+
895+
if (localizeOld) {
896+
// tslint:disable-next-line: no-any
897+
const messageParts = utils.unwrapMessagePartsFromTemplateLiteral(path.node.quasi.quasis as any);
898+
899+
return [(messageParts as unknown) as TemplateStringsArray, path.node.quasi.expressions];
900+
}
901+
902+
const [messageParts] = utils.unwrapMessagePartsFromTemplateLiteral(
903+
path.get('quasi').get('quasis'),
904+
);
905+
const [expressions] = utils.unwrapExpressionsFromTemplateLiteral(path.get('quasi'));
906+
907+
return [messageParts, expressions];
908+
}
909+
910+
function unwrapLocalizeCall(
911+
path: NodePath<types.CallExpression>,
912+
utils: LocalizeUtilities,
913+
): [TemplateStringsArray, types.Expression[]] {
914+
if (localizeOld === undefined) {
915+
const { version: localizeVersion } = require('@angular/localize/package.json');
916+
localizeOld = semverLt(localizeVersion, '10.1.0-rc.0', { includePrerelease: true });
917+
}
918+
919+
if (localizeOld) {
920+
const messageParts = utils.unwrapMessagePartsFromLocalizeCall(path);
921+
// tslint:disable-next-line: no-any
922+
const expressions = utils.unwrapSubstitutionsFromLocalizeCall(path.node as any);
923+
924+
return [
925+
(messageParts as unknown) as TemplateStringsArray,
926+
(expressions as unknown) as types.Expression[],
927+
];
928+
}
929+
930+
const [messageParts] = utils.unwrapMessagePartsFromLocalizeCall(path);
931+
const [expressions] = utils.unwrapSubstitutionsFromLocalizeCall(path);
932+
933+
return [messageParts, expressions];
934+
}
935+
885936
async function loadLocaleData(path: string, optimize: boolean, es5: boolean): Promise<string> {
886937
// The path is validated during option processing before the build starts
887938
const content = fs.readFileSync(path, 'utf8');

0 commit comments

Comments
 (0)