3
3
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4
4
//
5
5
6
+ using System ;
6
7
using System . Collections . Generic ;
7
8
using System . Management . Automation . Language ;
9
+ using Microsoft . PowerShell . EditorServices . Utility ;
8
10
9
11
namespace Microsoft . PowerShell . EditorServices
10
12
{
@@ -13,14 +15,21 @@ namespace Microsoft.PowerShell.EditorServices
13
15
/// </summary>
14
16
internal class FindDotSourcedVisitor : AstVisitor
15
17
{
16
- /// <summary>
17
- /// A hash set of the dot sourced files (because we don't want duplicates)
18
- /// </summary>
18
+ private readonly string _psScriptRoot ;
19
+
20
+ /// <summary>
21
+ /// A hash set of the dot sourced files (because we don't want duplicates)
22
+ /// </summary>
19
23
public HashSet < string > DotSourcedFiles { get ; private set ; }
20
24
21
- public FindDotSourcedVisitor ( )
25
+ /// <summary>
26
+ /// Creates a new instance of the FindDotSourcedVisitor class.
27
+ /// </summary>
28
+ /// <param name="psScriptRoot">Pre-calculated value of $PSScriptRoot</param>
29
+ public FindDotSourcedVisitor ( string psScriptRoot )
22
30
{
23
- this . DotSourcedFiles = new HashSet < string > ( ) ;
31
+ DotSourcedFiles = new HashSet < string > ( StringComparer . CurrentCultureIgnoreCase ) ;
32
+ _psScriptRoot = psScriptRoot ;
24
33
}
25
34
26
35
/// <summary>
@@ -32,15 +41,50 @@ public FindDotSourcedVisitor()
32
41
/// or a decision to continue if it wasn't found</returns>
33
42
public override AstVisitAction VisitCommand ( CommandAst commandAst )
34
43
{
35
- if ( commandAst . InvocationOperator . Equals ( TokenKind . Dot ) &&
36
- commandAst . CommandElements [ 0 ] is StringConstantExpressionAst )
44
+ CommandElementAst commandElementAst = commandAst . CommandElements [ 0 ] ;
45
+ if ( commandAst . InvocationOperator . Equals ( TokenKind . Dot ) )
37
46
{
38
- // Strip any quote characters off of the string
39
- string fileName = commandAst . CommandElements [ 0 ] . Extent . Text . Trim ( '\' ' , '"' ) ;
40
- DotSourcedFiles . Add ( fileName ) ;
47
+ string path ;
48
+ switch ( commandElementAst )
49
+ {
50
+ case StringConstantExpressionAst stringConstantExpressionAst :
51
+ path = stringConstantExpressionAst . Value ;
52
+ break ;
53
+
54
+ case ExpandableStringExpressionAst expandableStringExpressionAst :
55
+ path = GetPathFromExpandableStringExpression ( expandableStringExpressionAst ) ;
56
+ break ;
57
+
58
+ default :
59
+ path = null ;
60
+ break ;
61
+ }
62
+
63
+ if ( ! string . IsNullOrWhiteSpace ( path ) )
64
+ {
65
+ DotSourcedFiles . Add ( PathUtils . NormalizePathSeparators ( path ) ) ;
66
+ }
41
67
}
42
68
43
69
return base . VisitCommand ( commandAst ) ;
44
70
}
71
+
72
+ private string GetPathFromExpandableStringExpression ( ExpandableStringExpressionAst expandableStringExpressionAst )
73
+ {
74
+ var path = expandableStringExpressionAst . Value ;
75
+ foreach ( var nestedExpression in expandableStringExpressionAst . NestedExpressions )
76
+ {
77
+ // If the string contains the variable $PSScriptRoot, we replace it with the corresponding value.
78
+ if ( ! ( nestedExpression is VariableExpressionAst variableAst
79
+ && variableAst . VariablePath . UserPath . Equals ( "PSScriptRoot" , StringComparison . OrdinalIgnoreCase ) ) )
80
+ {
81
+ return null ; // We return null instead of a partially evaluated ExpandableStringExpression.
82
+ }
83
+
84
+ path = path . Replace ( variableAst . ToString ( ) , _psScriptRoot ) ;
85
+ }
86
+
87
+ return path ;
88
+ }
45
89
}
46
90
}
0 commit comments