@@ -28,7 +28,20 @@ class DartScriptUpdater extends RecursiveAstVisitor<void>
2828 final String existingScriptPath;
2929 final String newScriptPath;
3030
31- DartScriptUpdater (this .existingScriptPath, this .newScriptPath);
31+ /// Whether or not to update attributes on script/link tags (like type/crossorigin)
32+ /// while also updating the script path.
33+ final bool updateAttributes;
34+ final bool removeTag;
35+
36+ DartScriptUpdater (this .existingScriptPath, this .newScriptPath,
37+ {this .updateAttributes = true })
38+ : removeTag = false ;
39+
40+ /// Use this constructor to remove the whole tag instead of updating it.
41+ DartScriptUpdater .remove (this .existingScriptPath)
42+ : removeTag = true ,
43+ updateAttributes = false ,
44+ newScriptPath = 'will be ignored' ;
3245
3346 @override
3447 void visitSimpleStringLiteral (SimpleStringLiteral node) {
@@ -39,74 +52,107 @@ class DartScriptUpdater extends RecursiveAstVisitor<void>
3952 ...Script (pathSubpattern: existingScriptPath)
4053 .pattern
4154 .allMatches (stringValue),
42- ...Script (pathSubpattern: newScriptPath).pattern.allMatches (stringValue)
55+ ...? (! removeTag
56+ ? Script (pathSubpattern: newScriptPath)
57+ .pattern
58+ .allMatches (stringValue)
59+ : null )
4360 ];
4461 final relevantLinkTags = [
4562 ...Link (pathSubpattern: existingScriptPath)
4663 .pattern
4764 .allMatches (stringValue),
48- ...Link (pathSubpattern: newScriptPath).pattern.allMatches (stringValue)
65+ ...? (! removeTag
66+ ? Link (pathSubpattern: newScriptPath).pattern.allMatches (stringValue)
67+ : null )
4968 ];
5069
5170 // Do not update if neither the existingScriptPath nor newScriptPath are in the file.
5271 if (relevantScriptTags.isEmpty && relevantLinkTags.isEmpty) return ;
5372
54- // Add type="module" attribute to script tag.
55- for (final scriptTagMatch in relevantScriptTags) {
56- final scriptTag = scriptTagMatch.group (0 );
57- if (scriptTag == null ) continue ;
58- final typeAttributes = getAttributePattern ('type' ).allMatches (scriptTag);
59- if (typeAttributes.isNotEmpty) {
60- final attribute = typeAttributes.first;
61- final value = attribute.group (1 );
62- if (value == 'module' ) {
63- continue ;
73+ if (removeTag) {
74+ for (final tag in [...relevantScriptTags, ...relevantLinkTags]) {
75+ final tagEnd = node.offset + tag.end;
76+ final tagStart = node.offset + tag.start;
77+ final possibleCommaEnd = node.literal.next.toString () == ',' ? 1 : 0 ;
78+ final isTagSameAsNode =
79+ // Check if the only difference between [tag] and [node] is the quotes around [node].
80+ tagStart - node.offset <= 1 && node.end - tagEnd <= 1 ;
81+
82+ yieldPatch (
83+ '' ,
84+ // If [tag] spans the whole string literal in [node], then also include
85+ // the quotes and comma in the removal.
86+ isTagSameAsNode
87+ // Remove from the end of the previous token to take any preceding newline with it,
88+ // so that we don't leave behind an empty line.
89+ ? node.beginToken.previous? .end ?? node.offset
90+ : tagStart,
91+ isTagSameAsNode ? (node.end + possibleCommaEnd) : tagEnd,
92+ );
93+ }
94+ return ;
95+ }
96+
97+ if (updateAttributes) {
98+ // Add type="module" attribute to script tag.
99+ for (final scriptTagMatch in relevantScriptTags) {
100+ final scriptTag = scriptTagMatch.group (0 );
101+ if (scriptTag == null ) continue ;
102+ final typeAttributes =
103+ getAttributePattern ('type' ).allMatches (scriptTag);
104+ if (typeAttributes.isNotEmpty) {
105+ final attribute = typeAttributes.first;
106+ final value = attribute.group (1 );
107+ if (value == 'module' ) {
108+ continue ;
109+ } else {
110+ // If the value of the type attribute is not "module", overwrite it.
111+ yieldPatch (
112+ typeModuleAttribute,
113+ node.offset + scriptTagMatch.start + attribute.start,
114+ node.offset + scriptTagMatch.start + attribute.end,
115+ );
116+ }
64117 } else {
65- // If the value of the type attribute is not "module", overwrite it.
118+ // If the type attribute does not exist, add it.
119+ final srcAttribute = getAttributePattern ('src' ).allMatches (scriptTag);
66120 yieldPatch (
67- typeModuleAttribute,
68- node.offset + scriptTagMatch.start + attribute.start ,
69- node.offset + scriptTagMatch.start + attribute .end,
121+ ' ${ typeModuleAttribute }' ,
122+ node.offset + scriptTagMatch.start + srcAttribute.first.end ,
123+ node.offset + scriptTagMatch.start + srcAttribute.first .end,
70124 );
71125 }
72- } else {
73- // If the type attribute does not exist, add it.
74- final srcAttribute = getAttributePattern ('src' ).allMatches (scriptTag);
75- yieldPatch (
76- ' ${typeModuleAttribute }' ,
77- node.offset + scriptTagMatch.start + srcAttribute.first.end,
78- node.offset + scriptTagMatch.start + srcAttribute.first.end,
79- );
80126 }
81- }
82127
83- // Add crossorigin="" attribute to link tag.
84- for (final linkTagMatch in relevantLinkTags) {
85- final linkTag = linkTagMatch.group (0 );
86- if (linkTag == null ) continue ;
87- final crossOriginAttributes =
88- getAttributePattern ('crossorigin' ).allMatches (linkTag);
89- if (crossOriginAttributes.isNotEmpty) {
90- final attribute = crossOriginAttributes.first;
91- final value = attribute.group (1 );
92- if (value == '' ) {
93- continue ;
128+ // Add crossorigin="" attribute to link tag.
129+ for (final linkTagMatch in relevantLinkTags) {
130+ final linkTag = linkTagMatch.group (0 );
131+ if (linkTag == null ) continue ;
132+ final crossOriginAttributes =
133+ getAttributePattern ('crossorigin' ).allMatches (linkTag);
134+ if (crossOriginAttributes.isNotEmpty) {
135+ final attribute = crossOriginAttributes.first;
136+ final value = attribute.group (1 );
137+ if (value == '' ) {
138+ continue ;
139+ } else {
140+ // If the value of the crossorigin attribute is not "", overwrite it.
141+ yieldPatch (
142+ crossOriginAttribute,
143+ node.offset + linkTagMatch.start + attribute.start,
144+ node.offset + linkTagMatch.start + attribute.end,
145+ );
146+ }
94147 } else {
95- // If the value of the crossorigin attribute is not "", overwrite it.
148+ // If the crossorigin attribute does not exist, add it.
149+ final hrefAttribute = getAttributePattern ('href' ).allMatches (linkTag);
96150 yieldPatch (
97- crossOriginAttribute,
98- node.offset + linkTagMatch.start + attribute.start ,
99- node.offset + linkTagMatch.start + attribute .end,
151+ ' ${ crossOriginAttribute }' ,
152+ node.offset + linkTagMatch.start + hrefAttribute.first.end ,
153+ node.offset + linkTagMatch.start + hrefAttribute.first .end,
100154 );
101155 }
102- } else {
103- // If the crossorigin attribute does not exist, add it.
104- final hrefAttribute = getAttributePattern ('href' ).allMatches (linkTag);
105- yieldPatch (
106- ' ${crossOriginAttribute }' ,
107- node.offset + linkTagMatch.start + hrefAttribute.first.end,
108- node.offset + linkTagMatch.start + hrefAttribute.first.end,
109- );
110156 }
111157 }
112158
0 commit comments