refactor(compiler): use a named type for cooked/raw string objects (#38775)
Using an interface makes the code cleaner and more readable. This change also adds the `range` property to the type to be used for source-mapping. PR Close #38775
This commit is contained in:
parent
b0a43872a8
commit
6158dc16b4
@ -545,7 +545,7 @@ export class LocalizedString extends Expression {
|
|||||||
* @param meta The metadata to serialize
|
* @param meta The metadata to serialize
|
||||||
* @param messagePart The first part of the tagged string
|
* @param messagePart The first part of the tagged string
|
||||||
*/
|
*/
|
||||||
serializeI18nHead(): {cooked: string, raw: string} {
|
serializeI18nHead(): CookedRawString {
|
||||||
const MEANING_SEPARATOR = '|';
|
const MEANING_SEPARATOR = '|';
|
||||||
const ID_SEPARATOR = '@@';
|
const ID_SEPARATOR = '@@';
|
||||||
const LEGACY_ID_INDICATOR = '␟';
|
const LEGACY_ID_INDICATOR = '␟';
|
||||||
@ -562,7 +562,8 @@ export class LocalizedString extends Expression {
|
|||||||
metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`;
|
metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return createCookedRawString(metaBlock, this.messageParts[0].text);
|
return createCookedRawString(
|
||||||
|
metaBlock, this.messageParts[0].text, this.getMessagePartSourceSpan(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
getMessagePartSourceSpan(i: number): ParseSourceSpan|null {
|
getMessagePartSourceSpan(i: number): ParseSourceSpan|null {
|
||||||
@ -581,13 +582,24 @@ export class LocalizedString extends Expression {
|
|||||||
* @param placeholderName The placeholder name to serialize
|
* @param placeholderName The placeholder name to serialize
|
||||||
* @param messagePart The following message string after this placeholder
|
* @param messagePart The following message string after this placeholder
|
||||||
*/
|
*/
|
||||||
serializeI18nTemplatePart(partIndex: number): {cooked: string, raw: string} {
|
serializeI18nTemplatePart(partIndex: number): CookedRawString {
|
||||||
const placeholderName = this.placeHolderNames[partIndex - 1].text;
|
const placeholderName = this.placeHolderNames[partIndex - 1].text;
|
||||||
const messagePart = this.messageParts[partIndex];
|
const messagePart = this.messageParts[partIndex];
|
||||||
return createCookedRawString(placeholderName, messagePart.text);
|
return createCookedRawString(
|
||||||
|
placeholderName, messagePart.text, this.getMessagePartSourceSpan(partIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A structure to hold the cooked and raw strings of a template literal element, along with its
|
||||||
|
* source-span range.
|
||||||
|
*/
|
||||||
|
export interface CookedRawString {
|
||||||
|
cooked: string;
|
||||||
|
raw: string;
|
||||||
|
range: ParseSourceSpan|null;
|
||||||
|
}
|
||||||
|
|
||||||
const escapeSlashes = (str: string): string => str.replace(/\\/g, '\\\\');
|
const escapeSlashes = (str: string): string => str.replace(/\\/g, '\\\\');
|
||||||
const escapeStartingColon = (str: string): string => str.replace(/^:/, '\\:');
|
const escapeStartingColon = (str: string): string => str.replace(/^:/, '\\:');
|
||||||
const escapeColons = (str: string): string => str.replace(/:/g, '\\:');
|
const escapeColons = (str: string): string => str.replace(/:/g, '\\:');
|
||||||
@ -608,17 +620,20 @@ const escapeForMessagePart = (str: string): string =>
|
|||||||
* @param metaBlock Any metadata that should be prepended to the string
|
* @param metaBlock Any metadata that should be prepended to the string
|
||||||
* @param messagePart The message part of the string
|
* @param messagePart The message part of the string
|
||||||
*/
|
*/
|
||||||
function createCookedRawString(metaBlock: string, messagePart: string) {
|
function createCookedRawString(
|
||||||
|
metaBlock: string, messagePart: string, range: ParseSourceSpan|null): CookedRawString {
|
||||||
if (metaBlock === '') {
|
if (metaBlock === '') {
|
||||||
return {
|
return {
|
||||||
cooked: messagePart,
|
cooked: messagePart,
|
||||||
raw: escapeForMessagePart(escapeStartingColon(escapeSlashes(messagePart)))
|
raw: escapeForMessagePart(escapeStartingColon(escapeSlashes(messagePart))),
|
||||||
|
range,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
cooked: `:${metaBlock}:${messagePart}`,
|
cooked: `:${metaBlock}:${messagePart}`,
|
||||||
raw: escapeForMessagePart(
|
raw: escapeForMessagePart(
|
||||||
`:${escapeColons(escapeSlashes(metaBlock))}:${escapeSlashes(messagePart)}`)
|
`:${escapeColons(escapeSlashes(metaBlock))}:${escapeSlashes(messagePart)}`),
|
||||||
|
range,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,76 +223,107 @@ describe('Utils', () => {
|
|||||||
|
|
||||||
it('serializeI18nHead()', () => {
|
it('serializeI18nHead()', () => {
|
||||||
expect(o.localizedString(meta(), [literal('')], [], []).serializeI18nHead())
|
expect(o.localizedString(meta(), [literal('')], [], []).serializeI18nHead())
|
||||||
.toEqual({cooked: '', raw: ''});
|
.toEqual({cooked: '', raw: '', range: jasmine.any(ParseSourceSpan)});
|
||||||
expect(o.localizedString(meta('', '', 'desc'), [literal('')], [], []).serializeI18nHead())
|
expect(o.localizedString(meta('', '', 'desc'), [literal('')], [], []).serializeI18nHead())
|
||||||
.toEqual({cooked: ':desc:', raw: ':desc:'});
|
.toEqual({cooked: ':desc:', raw: ':desc:', range: jasmine.any(ParseSourceSpan)});
|
||||||
expect(o.localizedString(meta('id', '', 'desc'), [literal('')], [], []).serializeI18nHead())
|
expect(o.localizedString(meta('id', '', 'desc'), [literal('')], [], []).serializeI18nHead())
|
||||||
.toEqual({cooked: ':desc@@id:', raw: ':desc@@id:'});
|
.toEqual({cooked: ':desc@@id:', raw: ':desc@@id:', range: jasmine.any(ParseSourceSpan)});
|
||||||
expect(
|
expect(
|
||||||
o.localizedString(meta('', 'meaning', 'desc'), [literal('')], [], []).serializeI18nHead())
|
o.localizedString(meta('', 'meaning', 'desc'), [literal('')], [], []).serializeI18nHead())
|
||||||
.toEqual({cooked: ':meaning|desc:', raw: ':meaning|desc:'});
|
.toEqual({
|
||||||
|
cooked: ':meaning|desc:',
|
||||||
|
raw: ':meaning|desc:',
|
||||||
|
range: jasmine.any(ParseSourceSpan)
|
||||||
|
});
|
||||||
expect(o.localizedString(meta('id', 'meaning', 'desc'), [literal('')], [], [])
|
expect(o.localizedString(meta('id', 'meaning', 'desc'), [literal('')], [], [])
|
||||||
.serializeI18nHead())
|
.serializeI18nHead())
|
||||||
.toEqual({cooked: ':meaning|desc@@id:', raw: ':meaning|desc@@id:'});
|
.toEqual({
|
||||||
|
cooked: ':meaning|desc@@id:',
|
||||||
|
raw: ':meaning|desc@@id:',
|
||||||
|
range: jasmine.any(ParseSourceSpan)
|
||||||
|
});
|
||||||
expect(o.localizedString(meta('id', '', ''), [literal('')], [], []).serializeI18nHead())
|
expect(o.localizedString(meta('id', '', ''), [literal('')], [], []).serializeI18nHead())
|
||||||
.toEqual({cooked: ':@@id:', raw: ':@@id:'});
|
.toEqual({cooked: ':@@id:', raw: ':@@id:', range: jasmine.any(ParseSourceSpan)});
|
||||||
|
|
||||||
// Escaping colons (block markers)
|
// Escaping colons (block markers)
|
||||||
expect(o.localizedString(meta('id:sub_id', 'meaning', 'desc'), [literal('')], [], [])
|
expect(o.localizedString(meta('id:sub_id', 'meaning', 'desc'), [literal('')], [], [])
|
||||||
.serializeI18nHead())
|
.serializeI18nHead())
|
||||||
.toEqual({cooked: ':meaning|desc@@id:sub_id:', raw: ':meaning|desc@@id\\:sub_id:'});
|
.toEqual({
|
||||||
|
cooked: ':meaning|desc@@id:sub_id:',
|
||||||
|
raw: ':meaning|desc@@id\\:sub_id:',
|
||||||
|
range: jasmine.any(ParseSourceSpan)
|
||||||
|
});
|
||||||
expect(o.localizedString(meta('id', 'meaning:sub_meaning', 'desc'), [literal('')], [], [])
|
expect(o.localizedString(meta('id', 'meaning:sub_meaning', 'desc'), [literal('')], [], [])
|
||||||
.serializeI18nHead())
|
.serializeI18nHead())
|
||||||
.toEqual(
|
.toEqual({
|
||||||
{cooked: ':meaning:sub_meaning|desc@@id:', raw: ':meaning\\:sub_meaning|desc@@id:'});
|
cooked: ':meaning:sub_meaning|desc@@id:',
|
||||||
|
raw: ':meaning\\:sub_meaning|desc@@id:',
|
||||||
|
range: jasmine.any(ParseSourceSpan)
|
||||||
|
});
|
||||||
expect(o.localizedString(meta('id', 'meaning', 'desc:sub_desc'), [literal('')], [], [])
|
expect(o.localizedString(meta('id', 'meaning', 'desc:sub_desc'), [literal('')], [], [])
|
||||||
.serializeI18nHead())
|
.serializeI18nHead())
|
||||||
.toEqual({cooked: ':meaning|desc:sub_desc@@id:', raw: ':meaning|desc\\:sub_desc@@id:'});
|
.toEqual({
|
||||||
|
cooked: ':meaning|desc:sub_desc@@id:',
|
||||||
|
raw: ':meaning|desc\\:sub_desc@@id:',
|
||||||
|
range: jasmine.any(ParseSourceSpan)
|
||||||
|
});
|
||||||
expect(o.localizedString(meta('id', 'meaning', 'desc'), [literal('message source')], [], [])
|
expect(o.localizedString(meta('id', 'meaning', 'desc'), [literal('message source')], [], [])
|
||||||
.serializeI18nHead())
|
.serializeI18nHead())
|
||||||
.toEqual({
|
.toEqual({
|
||||||
cooked: ':meaning|desc@@id:message source',
|
cooked: ':meaning|desc@@id:message source',
|
||||||
raw: ':meaning|desc@@id:message source'
|
raw: ':meaning|desc@@id:message source',
|
||||||
|
range: jasmine.any(ParseSourceSpan)
|
||||||
});
|
});
|
||||||
expect(o.localizedString(meta('id', 'meaning', 'desc'), [literal(':message source')], [], [])
|
expect(o.localizedString(meta('id', 'meaning', 'desc'), [literal(':message source')], [], [])
|
||||||
.serializeI18nHead())
|
.serializeI18nHead())
|
||||||
.toEqual({
|
.toEqual({
|
||||||
cooked: ':meaning|desc@@id::message source',
|
cooked: ':meaning|desc@@id::message source',
|
||||||
raw: ':meaning|desc@@id::message source'
|
raw: ':meaning|desc@@id::message source',
|
||||||
|
range: jasmine.any(ParseSourceSpan)
|
||||||
});
|
});
|
||||||
expect(o.localizedString(meta('', '', ''), [literal('message source')], [], [])
|
expect(o.localizedString(meta('', '', ''), [literal('message source')], [], [])
|
||||||
.serializeI18nHead())
|
.serializeI18nHead())
|
||||||
.toEqual({cooked: 'message source', raw: 'message source'});
|
.toEqual({
|
||||||
|
cooked: 'message source',
|
||||||
|
raw: 'message source',
|
||||||
|
range: jasmine.any(ParseSourceSpan)
|
||||||
|
});
|
||||||
expect(o.localizedString(meta('', '', ''), [literal(':message source')], [], [])
|
expect(o.localizedString(meta('', '', ''), [literal(':message source')], [], [])
|
||||||
.serializeI18nHead())
|
.serializeI18nHead())
|
||||||
.toEqual({cooked: ':message source', raw: '\\:message source'});
|
.toEqual({
|
||||||
|
cooked: ':message source',
|
||||||
|
raw: '\\:message source',
|
||||||
|
range: jasmine.any(ParseSourceSpan)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('serializeI18nPlaceholderBlock()', () => {
|
it('serializeI18nPlaceholderBlock()', () => {
|
||||||
expect(o.localizedString(meta('', '', ''), [literal(''), literal('')], [literal('')], [])
|
expect(o.localizedString(meta('', '', ''), [literal(''), literal('')], [literal('')], [])
|
||||||
.serializeI18nTemplatePart(1))
|
.serializeI18nTemplatePart(1))
|
||||||
.toEqual({cooked: '', raw: ''});
|
.toEqual({cooked: '', raw: '', range: jasmine.any(ParseSourceSpan)});
|
||||||
expect(o.localizedString(
|
expect(o.localizedString(
|
||||||
meta('', '', ''), [literal(''), literal('')],
|
meta('', '', ''), [literal(''), literal('')],
|
||||||
[new o.LiteralPiece('abc', {} as any)], [])
|
[new o.LiteralPiece('abc', {} as any)], [])
|
||||||
.serializeI18nTemplatePart(1))
|
.serializeI18nTemplatePart(1))
|
||||||
.toEqual({cooked: ':abc:', raw: ':abc:'});
|
.toEqual({cooked: ':abc:', raw: ':abc:', range: jasmine.any(ParseSourceSpan)});
|
||||||
expect(
|
expect(
|
||||||
o.localizedString(meta('', '', ''), [literal(''), literal('message')], [literal('')], [])
|
o.localizedString(meta('', '', ''), [literal(''), literal('message')], [literal('')], [])
|
||||||
.serializeI18nTemplatePart(1))
|
.serializeI18nTemplatePart(1))
|
||||||
.toEqual({cooked: 'message', raw: 'message'});
|
.toEqual({cooked: 'message', raw: 'message', range: jasmine.any(ParseSourceSpan)});
|
||||||
expect(o.localizedString(
|
expect(o.localizedString(
|
||||||
meta('', '', ''), [literal(''), literal('message')], [literal('abc')], [])
|
meta('', '', ''), [literal(''), literal('message')], [literal('abc')], [])
|
||||||
.serializeI18nTemplatePart(1))
|
.serializeI18nTemplatePart(1))
|
||||||
.toEqual({cooked: ':abc:message', raw: ':abc:message'});
|
.toEqual(
|
||||||
|
{cooked: ':abc:message', raw: ':abc:message', range: jasmine.any(ParseSourceSpan)});
|
||||||
expect(
|
expect(
|
||||||
o.localizedString(meta('', '', ''), [literal(''), literal(':message')], [literal('')], [])
|
o.localizedString(meta('', '', ''), [literal(''), literal(':message')], [literal('')], [])
|
||||||
.serializeI18nTemplatePart(1))
|
.serializeI18nTemplatePart(1))
|
||||||
.toEqual({cooked: ':message', raw: '\\:message'});
|
.toEqual({cooked: ':message', raw: '\\:message', range: jasmine.any(ParseSourceSpan)});
|
||||||
expect(o.localizedString(
|
expect(o.localizedString(
|
||||||
meta('', '', ''), [literal(''), literal(':message')], [literal('abc')], [])
|
meta('', '', ''), [literal(''), literal(':message')], [literal('abc')], [])
|
||||||
.serializeI18nTemplatePart(1))
|
.serializeI18nTemplatePart(1))
|
||||||
.toEqual({cooked: ':abc::message', raw: ':abc::message'});
|
.toEqual(
|
||||||
|
{cooked: ':abc::message', raw: ':abc::message', range: jasmine.any(ParseSourceSpan)});
|
||||||
});
|
});
|
||||||
|
|
||||||
function meta(customId?: string, meaning?: string, description?: string): I18nMeta {
|
function meta(customId?: string, meaning?: string, description?: string): I18nMeta {
|
||||||
@ -563,4 +594,4 @@ function literal(text: string, span: any = jasmine.any(ParseSourceSpan)): o.Lite
|
|||||||
|
|
||||||
function placeholder(name: string, span: any = jasmine.any(ParseSourceSpan)): o.PlaceholderPiece {
|
function placeholder(name: string, span: any = jasmine.any(ParseSourceSpan)): o.PlaceholderPiece {
|
||||||
return new o.PlaceholderPiece(name, span);
|
return new o.PlaceholderPiece(name, span);
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user