Skip to content

Commit fe2a4e1

Browse files
authored
fix: improve shadow_scope (#242)
1 parent f04a793 commit fe2a4e1

File tree

4 files changed

+110
-31
lines changed

4 files changed

+110
-31
lines changed

.grit/patterns/js/test_scope_shadow.md renamed to .grit/patterns/js/_test_scope_shadow.md

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,16 @@
22
tags: [utility, test]
33
---
44

5-
## Test shadow scope
6-
7-
This tests the `shadows_identifier` pattern by finding all cases where a variable is shadowed.
5+
## Shadow Identifiers
86

7+
This tests the `scope_for_identifier` pattern by finding all cases where a variable is shadowed.
98

109
```grit
1110
language js
1211
13-
// Implementation
14-
pattern shadows_identifier($name) {
15-
or {
16-
statement_block($statements) where {
17-
$statements <: some variable($declarations) where {
18-
$declarations <: contains variable_declarator(name=$name)
19-
}
20-
},
21-
arrow_function($parameters) where {
22-
$parameters <: contains $name
23-
},
24-
function_declaration($parameters) where {
25-
$parameters <: contains $name
26-
},
27-
for_in_statement() as $statement where {
28-
$statement <: contains $name
29-
},
30-
for_statement() as $statement where {
31-
$statement <: contains $name
32-
},
33-
`try { $_ } catch($catch) { $_ }` where {
34-
$catch <: contains $name
35-
},
36-
}
37-
}
38-
3912
// Test case
4013
file($body) where {
41-
$body <: contains bubble shadows_identifier(`x`) as $scope where {
14+
$body <: contains bubble identifier_scope(`x`) as $scope where {
4215
$scope <: contains `x` => `shadowed`
4316
}
4417
}
@@ -68,6 +41,28 @@ function notShadowingVar() {
6841
shadowingExample();
6942
```
7043

44+
## Anonymous function variable definition
45+
46+
```js
47+
var shadowingExample = function (x) {
48+
console.log(x);
49+
};
50+
var notShadowingVar = function (y) {
51+
console.log(y);
52+
};
53+
shadowingExample();
54+
```
55+
56+
```js
57+
var shadowingExample = function (shadowed) {
58+
console.log(shadowed);
59+
};
60+
var notShadowingVar = function (y) {
61+
console.log(y);
62+
};
63+
shadowingExample();
64+
```
65+
7166
## If statement
7267

7368
```js

.grit/patterns/js/replace_wildcard_imports.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pattern replace_wildcard_import() {
3030
`import * as $alias from $src` as $import where {
3131
$refs = [],
3232
$kept_refs = [],
33-
$program <: contains used_alias($alias, $refs, $kept_refs) until shadows_identifier(name=$alias),
33+
$program <: contains used_alias($alias, $refs, $kept_refs) until identifier_scope(name=$alias),
3434
$refs = distinct($refs),
3535
$joined_refs = join($refs, `, `),
3636
// Try the different scenarios

.grit/patterns/js/shadow_scope.grit

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
pattern identifier_scope($name) {
3+
or {
4+
statement_block($statements) where {
5+
$statements <: some variable($declarations) where {
6+
$declarations <: contains variable_declarator(name=$name)
7+
}
8+
},
9+
function($parameters) where {
10+
$parameters <: contains $name
11+
},
12+
arrow_function($parameters) where {
13+
$parameters <: contains $name
14+
},
15+
function_declaration($parameters) where {
16+
$parameters <: contains $name
17+
},
18+
for_in_statement() as $statement where {
19+
$statement <: contains $name
20+
},
21+
for_statement() as $statement where {
22+
$statement <: contains $name
23+
},
24+
`try { $_ } catch($catch) { $_ }` where {
25+
$catch <: contains $name
26+
},
27+
}
28+
}

.grit/patterns/js/variable_scoping.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
tags:
3+
- docs
4+
- full-examples
5+
---
6+
7+
# Variable Scoping with `identifier_scope`
8+
9+
Default Grit patterns are not generally aware of variable scoping, but you can use the `identifier_scope` pattern to find (or exclude) [scopes](https://developer.mozilla.org/en-US/docs/Glossary/Scope) where an identifier has been _locally_ defined.
10+
11+
This is most often used when you want to target an import from a shared module but exclude scopes where the identifier is shadowed locally.
12+
13+
For example, this pattern would rename `t` from the `translation` library to `translate` unless `t` is shadowed locally:
14+
15+
```grit
16+
language js
17+
18+
`t` as $t => `translate` where {
19+
$t <: imported_from(from=`"translation"`),
20+
$t <: not within identifier_scope(name=`t`)
21+
}
22+
```
23+
24+
Here is a simple example file where `t` is shadowed locally:
25+
26+
```js
27+
import { t } from 'translation';
28+
29+
console.log(t('hello world'));
30+
31+
function normal() {
32+
console.log(t('hello world'));
33+
}
34+
35+
// t is an argument to this function, so the global t is not used and we should *not* rename it here.
36+
function shadowed(t) {
37+
console.log(t('hello world'));
38+
}
39+
```
40+
41+
When we rewrite it, the shadowed `t` is not renamed:
42+
43+
```js
44+
import { translate } from 'translation';
45+
46+
console.log(translate('hello world'));
47+
48+
function normal() {
49+
console.log(translate('hello world'));
50+
}
51+
52+
// t is an argument to this function, so the global t is not used and we should *not* rename it here.
53+
function shadowed(t) {
54+
console.log(t('hello world'));
55+
}
56+
```

0 commit comments

Comments
 (0)