message: refactor(localize): allow ParsedMessage to hold additional location data
  In preparation for supporting `equiv-text` placeholder information in
  extracted translation files, this commit adds these optional properties
  to the `ParsedMessage` interface and updates `parseMessage()` to
  be able to store them.
  PR Close
diff: @@ -48,6 +48,7 @@ export interface SourceLocation {
  start: {line: number, column: number};
  end: {line: number, column: number};
  file: AbsoluteFsPath;
  + text?: string;
  }
  /**
  @@ -118,10 +119,18 @@ export interface ParsedMessage extends MessageMetadata {
  * A mapping of placeholder names to substitution values.
  */
  substitutions: Record<string, any>;
  + /**
  + * An optional mapping of placeholder names to source locations
  + */
  + substitutionLocations?: Record<string, SourceLocation|undefined>;
  /**
  * The static parts of the message.
  */
  messageParts: string[];
  + /**
  + * An optional mapping of message parts to source locations
  + */
  + messagePartLocations?: (SourceLocation|undefined)[];
  /**
  * The names of the placeholders that will be replaced with substitutions.
  */
  @@ -135,9 +144,11 @@ export interface ParsedMessage extends MessageMetadata {
  * See `ParsedMessage` for an example.
  */
  export function parseMessage(
  - messageParts: TemplateStringsArray, expressions?: readonly any[],
  - location?: SourceLocation): ParsedMessage {
  + messageParts: TemplateStringsArray, expressions?: readonly any[], location?: SourceLocation,
  + messagePartLocations?: (SourceLocation|undefined)[],
  + expressionLocations: (SourceLocation|undefined)[] = []): ParsedMessage {
  const substitutions: {[placeholderName: string]: any} = {};
  + const substitutionLocations: {[placeholderName: string]: SourceLocation|undefined} = {};
  const metadata = parseMetadata(messageParts[0], messageParts.raw[0]);
  const cleanedMessageParts: string[] = [metadata.text];
  const placeholderNames: string[] = [];
  @@ -148,6 +159,7 @@ export function parseMessage(
  messageString += `{$${placeholderName}}${messagePart}`;
  if (expressions !== undefined) {
  substitutions[placeholderName] = expressions[i - 1];
  + substitutionLocations[placeholderName] = expressionLocations[i - 1];
  }
  placeholderNames.push(placeholderName);
  cleanedMessageParts.push(messagePart);
  @@ -158,11 +170,13 @@ export function parseMessage(
  id: messageId,
  legacyIds,
  substitutions,
  + substitutionLocations,
  text: messageString,
  customId: metadata.customId,
  meaning: metadata.meaning || '',
  description: metadata.description || '',
  messageParts: cleanedMessageParts,
  + messagePartLocations,
  placeholderNames,
  location,
  };
  