feat(i18n): xmb serializer

This commit is contained in:
Victor Berchet
2016-07-15 09:42:33 -07:00
parent 48f230a951
commit cc5cfe87c3
17 changed files with 995 additions and 189 deletions

View File

@ -0,0 +1,93 @@
/**
* @license
* Copyright Google Inc. 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
*/
export interface IVisitor {
visitTag(tag: Tag): any;
visitText(text: Text): any;
visitDeclaration(decl: Declaration): any;
}
class _Visitor implements IVisitor {
visitTag(tag: Tag): string {
const strAttrs = this._serializeAttributes(tag.attrs);
if (tag.children.length == 0) {
return `<${tag.name}${strAttrs}/>`;
}
const strChildren = tag.children.map(node => node.visit(this));
return `<${tag.name}${strAttrs}>${strChildren.join('')}</${tag.name}>`;
}
visitText(text: Text): string { return text.value; }
visitDeclaration(decl: Declaration): string {
return `<? xml${this._serializeAttributes(decl.attrs)} ?>`;
}
private _serializeAttributes(attrs: {[k: string]: string}) {
const strAttrs = Object.getOwnPropertyNames(attrs)
.map((name: string) => `${name}="${attrs[name]}"`)
.join(' ');
return strAttrs.length > 0 ? ' ' + strAttrs : '';
}
}
const _visitor = new _Visitor();
export function serialize(nodes: Node[]): string {
return nodes.map((node: Node): string => node.visit(_visitor)).join('');
}
export interface Node { visit(visitor: IVisitor): any; }
export class Declaration implements Node {
public attrs: {[k: string]: string} = {};
constructor(unescapedAttrs: {[k: string]: string}) {
Object.getOwnPropertyNames(unescapedAttrs).forEach((k: string) => {
this.attrs[k] = _escapeXml(unescapedAttrs[k]);
});
}
visit(visitor: IVisitor): any { return visitor.visitDeclaration(this); }
}
export class Tag implements Node {
public attrs: {[k: string]: string} = {};
constructor(
public name: string, unescapedAttrs: {[k: string]: string} = {},
public children: Node[] = []) {
Object.getOwnPropertyNames(unescapedAttrs).forEach((k: string) => {
this.attrs[k] = _escapeXml(unescapedAttrs[k]);
});
}
visit(visitor: IVisitor): any { return visitor.visitTag(this); }
}
export class Text implements Node {
value: string;
constructor(unescapedValue: string) { this.value = _escapeXml(unescapedValue); };
visit(visitor: IVisitor): any { return visitor.visitText(this); }
}
const _ESCAPED_CHARS: [RegExp, string][] = [
[/&/g, '&amp;'],
[/"/g, '&quot;'],
[/'/g, '&apos;'],
[/</g, '&lt;'],
[/>/g, '&gt;'],
];
function _escapeXml(text: string): string {
return _ESCAPED_CHARS.reduce(
(text: string, entry: [RegExp, string]) => text.replace(entry[0], entry[1]), text);
}