6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
9
- import * as compiler from '@angular/compiler' ;
9
+ import {
10
+ ParsedTemplate ,
11
+ TmplAstElement ,
12
+ TmplAstNode ,
13
+ parseTemplate as parseTemplateUsingCompiler ,
14
+ } from '@angular/compiler' ;
10
15
11
16
/**
12
17
* Traverses the given tree of nodes and runs the given callbacks for each Element node encountered.
@@ -20,14 +25,14 @@ import * as compiler from '@angular/compiler';
20
25
* @param postorderCallback A function that gets run for each Element node in a postorder traversal.
21
26
*/
22
27
export function visitElements (
23
- nodes : compiler . TmplAstNode [ ] ,
24
- preorderCallback : ( node : compiler . TmplAstElement ) => void = ( ) => { } ,
25
- postorderCallback : ( node : compiler . TmplAstElement ) => void = ( ) => { } ,
28
+ nodes : TmplAstNode [ ] ,
29
+ preorderCallback : ( node : TmplAstElement ) => void = ( ) => { } ,
30
+ postorderCallback : ( node : TmplAstElement ) => void = ( ) => { } ,
26
31
) : void {
27
32
nodes . reverse ( ) ;
28
33
for ( let i = 0 ; i < nodes . length ; i ++ ) {
29
34
const node = nodes [ i ] ;
30
- if ( node instanceof compiler . TmplAstElement ) {
35
+ if ( node instanceof TmplAstElement ) {
31
36
preorderCallback ( node ) ;
32
37
visitElements ( node . children , preorderCallback , postorderCallback ) ;
33
38
postorderCallback ( node ) ;
@@ -45,8 +50,8 @@ export function visitElements(
45
50
* @param filePath URL to use for source mapping of the parsed template
46
51
* @returns the updated template html.
47
52
*/
48
- export function parseTemplate ( template : string , templateUrl : string = '' ) : compiler . ParsedTemplate {
49
- return compiler . parseTemplate ( template , templateUrl , {
53
+ export function parseTemplate ( template : string , templateUrl : string = '' ) : ParsedTemplate {
54
+ return parseTemplateUsingCompiler ( template , templateUrl , {
50
55
preserveWhitespaces : true ,
51
56
preserveLineEndings : true ,
52
57
leadingTriviaChars : [ ] ,
@@ -61,7 +66,7 @@ export function parseTemplate(template: string, templateUrl: string = ''): compi
61
66
* @param tag A new tag name.
62
67
* @returns an updated html document.
63
68
*/
64
- export function replaceStartTag ( html : string , node : compiler . TmplAstElement , tag : string ) : string {
69
+ export function replaceStartTag ( html : string , node : TmplAstElement , tag : string ) : string {
65
70
return replaceAt ( html , node . startSourceSpan . start . offset + 1 , node . name , tag ) ;
66
71
}
67
72
@@ -73,7 +78,7 @@ export function replaceStartTag(html: string, node: compiler.TmplAstElement, tag
73
78
* @param tag A new tag name.
74
79
* @returns an updated html document.
75
80
*/
76
- export function replaceEndTag ( html : string , node : compiler . TmplAstElement , tag : string ) : string {
81
+ export function replaceEndTag ( html : string , node : TmplAstElement , tag : string ) : string {
77
82
if ( ! node . endSourceSpan ) {
78
83
return html ;
79
84
}
@@ -91,10 +96,32 @@ export function replaceEndTag(html: string, node: compiler.TmplAstElement, tag:
91
96
*/
92
97
export function addAttribute (
93
98
html : string ,
94
- node : compiler . TmplAstElement ,
99
+ node : TmplAstElement ,
95
100
name : string ,
96
101
value : string ,
97
102
) : string {
103
+ const existingAttr = node . attributes . find ( currentAttr => currentAttr . name === name ) ;
104
+
105
+ if ( existingAttr ) {
106
+ // If the attribute has a value already, replace it.
107
+ if ( existingAttr . valueSpan ) {
108
+ return (
109
+ html . slice ( 0 , existingAttr . valueSpan . start . offset ) +
110
+ value +
111
+ html . slice ( existingAttr . valueSpan . end . offset )
112
+ ) ;
113
+ } else if ( existingAttr . keySpan ) {
114
+ // Otherwise add a value to a value-less attribute. Note that the `keySpan` null check is
115
+ // only necessary for the compiler. Technically an attribute should always have a key.
116
+ return (
117
+ html . slice ( 0 , existingAttr . keySpan . end . offset ) +
118
+ `="${ value } "` +
119
+ html . slice ( existingAttr . keySpan . end . offset )
120
+ ) ;
121
+ }
122
+ }
123
+
124
+ // Otherwise insert a new attribute.
98
125
const index = node . startSourceSpan . start . offset + node . name . length + 1 ;
99
126
const prefix = html . slice ( 0 , index ) ;
100
127
const suffix = html . slice ( index ) ;
0 commit comments