-
Notifications
You must be signed in to change notification settings - Fork 15
Fix the conversion of private names to public names #275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 8 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
23d0b2b
Fix private variable detection to not match multiple dash
Tofandel ebb3b65
Make _isPrivate match Sass semantics
nex3 6deefe5
Properly deprivatize names that start with multiple underscores
nex3 13f065d
Fix prefix removal without a trailing dash
nex3 00940e2
Code review
nex3 e7b6547
Merge branch 'main' into private-to-public
jathak 91640f3
Merge some changes from https://github.com/sass/migrator/pull/276
jathak 2bcb831
Use generic "private" prefix instead of generated variable counter
jathak 4f9e7b1
Style changes
nex3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
|
||
import 'package:args/args.dart'; | ||
import 'package:collection/collection.dart'; | ||
import 'package:charcode/charcode.dart'; | ||
import 'package:path/path.dart' as p; | ||
import 'package:sass_api/sass_api.dart'; | ||
import 'package:source_span/source_span.dart'; | ||
|
@@ -263,7 +264,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor { | |
var forwardsByUrl = <Uri, Map<String, Set<MemberDeclaration>>>{}; | ||
var hiddenByUrl = <Uri, Set<MemberDeclaration>>{}; | ||
for (var declaration in references.globalDeclarations) { | ||
var private = declaration.name.startsWith('-'); | ||
var private = _isPrivate(declaration.name); | ||
|
||
// Whether this member will be exposed by the regular entrypoint. | ||
var visibleAtEntrypoint = !private && | ||
|
@@ -352,19 +353,39 @@ class _ModuleMigrationVisitor extends MigrationVisitor { | |
if (declaration.isForwarded) return; | ||
|
||
var name = declaration.name; | ||
if (name.startsWith('-') && | ||
references.referencedOutsideDeclaringStylesheet(declaration)) { | ||
// Remove leading `-` since private members can't be accessed outside | ||
// the module they're declared in. | ||
name = name.substring(1); | ||
} | ||
name = _unprefix(name); | ||
name = _unprefix(name, | ||
// Private members can't be accessed outside the module they're | ||
// declared in. | ||
forcePublic: | ||
references.referencedOutsideDeclaringStylesheet(declaration)); | ||
if (name != declaration.name) { | ||
renamedMembers[declaration] = name; | ||
if (_upstreamStylesheets.isEmpty) _needsImportOnly = true; | ||
} | ||
} | ||
|
||
/// Returns whether [identifier] is a private member name. | ||
/// | ||
/// Assumes [identifier] is a valid CSS identifier. | ||
bool _isPrivate(String identifier) { | ||
return identifier.startsWith('-') || identifier.startsWith('_'); | ||
} | ||
|
||
/// Converts a private identifier to a public one. | ||
String _privateToPublic(String identifier) { | ||
if (_isPrivate(identifier)) { | ||
for (var i = 0; i < identifier.length; i++) { | ||
var char = identifier.codeUnitAt(i); | ||
if (char != $dash && char != $underscore) { | ||
return identifier.substring(i); | ||
} | ||
} | ||
|
||
return 'private$identifier'; | ||
} | ||
return identifier; | ||
} | ||
|
||
/// Returns whether the member named [name] should be forwarded in the | ||
/// entrypoint. | ||
/// | ||
|
@@ -1025,8 +1046,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor { | |
newName = declaration.name.substring(importOnlyPrefix.length); | ||
} | ||
|
||
if (_shouldForward(declaration.name) && | ||
!declaration.name.startsWith('-')) { | ||
if (_shouldForward(declaration.name) && !_isPrivate(declaration.name)) { | ||
var subprefix = ""; | ||
if (importOnlyPrefix != null) { | ||
var prefix = _prefixFor(declaration.name); | ||
|
@@ -1036,7 +1056,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor { | |
} | ||
if (declaration.name != newName) _needsImportOnly = true; | ||
shownByPrefix.putIfAbsent(subprefix, () => {}).add(declaration); | ||
} else if (!newName.startsWith('-')) { | ||
} else if (!_isPrivate(newName)) { | ||
hidden.add(declaration); | ||
} | ||
} | ||
|
@@ -1076,8 +1096,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor { | |
if (declaration is ImportOnlyMemberDeclaration) { | ||
name = name.substring(declaration.importOnlyPrefix.length); | ||
} | ||
if (name.startsWith('-')) name = name.substring(1); | ||
name = _unprefix(name); | ||
name = _unprefix(name, forcePublic: true); | ||
if (subprefix.isNotEmpty) name = '$subprefix$name'; | ||
if (declaration.member is VariableDeclaration) name = '\$$name'; | ||
allHidden.add(name); | ||
|
@@ -1205,7 +1224,7 @@ class _ModuleMigrationVisitor extends MigrationVisitor { | |
void _renameReference(FileSpan span, MemberDeclaration declaration) { | ||
var newName = renamedMembers[declaration]; | ||
if (newName != null) { | ||
if (newName.startsWith('-') && | ||
if (_isPrivate(newName) && | ||
declaration.name.endsWith(newName.substring(1))) { | ||
addPatch(patchDelete(span, | ||
start: 1, end: declaration.name.length - newName.length + 1)); | ||
|
@@ -1225,14 +1244,36 @@ class _ModuleMigrationVisitor extends MigrationVisitor { | |
|
||
/// If [name] starts with any of [prefixesToRemove], returns it with the | ||
/// longest matching prefix removed. | ||
/// If forcePublic is true, any leading dash or underscore will be removed. | ||
/// | ||
/// Otherwise, returns [name] unaltered. | ||
String _unprefix(String name) { | ||
var isPrivate = name.startsWith('-'); | ||
var unprivateName = isPrivate ? name.substring(1) : name; | ||
var prefix = _prefixFor(unprivateName); | ||
if (prefix == null) return name; | ||
return (isPrivate ? '-' : '') + unprivateName.substring(prefix.length); | ||
/// | ||
/// If [forcePublic] is true, this will ensure that the name is always a | ||
/// public identifier. | ||
String _unprefix(String name, {bool forcePublic = false}) { | ||
bool isPrivate; | ||
String withoutPrefix; | ||
|
||
// Allow users to pass prefixes that either do or do not include leading | ||
// dashes/underscores. As usual, the longest prefix wins, so we check for | ||
// ones that do include them first. | ||
var prefix = _prefixFor(name); | ||
if (prefix != null) { | ||
isPrivate = false; | ||
withoutPrefix = name.substring(prefix.length); | ||
} else { | ||
isPrivate = _isPrivate(name); | ||
var unprivateName = isPrivate ? _privateToPublic(name) : name; | ||
prefix = _prefixFor(unprivateName); | ||
if (prefix == null) | ||
return isPrivate && forcePublic ? unprivateName : name; | ||
withoutPrefix = unprivateName.substring(prefix.length); | ||
} | ||
|
||
if (_isPrivate(withoutPrefix)) { | ||
withoutPrefix = _privateToPublic(withoutPrefix); | ||
} | ||
return (isPrivate && !forcePublic ? '-' : '') + withoutPrefix; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought because of this line, here we return '-' but we should return the original private prefix. But from testing, it seems there is some magic running after that already and it keeps the original private prefix somehow |
||
} | ||
|
||
/// Returns the namespace that built-in module [module] is loaded under. | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
test/migrators/module/remove_prefix_flag/pseudoprivate_multi_dash.hrx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<==> arguments | ||
--migrate-deps --remove-prefix=lib- | ||
|
||
<==> input/entrypoint.scss | ||
@import "dependency"; | ||
|
||
a { | ||
background: $--lib-pseudoprivate; | ||
} | ||
|
||
<==> input/_dependency.scss | ||
$--lib-pseudoprivate: blue; | ||
|
||
<==> output/entrypoint.scss | ||
@use "dependency"; | ||
|
||
a { | ||
background: dependency.$pseudoprivate; | ||
} | ||
|
||
<==> output/_dependency.scss | ||
$pseudoprivate: blue; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<==> arguments | ||
--migrate-deps --remove-prefix=--app- | ||
<==> input/entrypoint.scss | ||
@import "library"; | ||
a { | ||
color: $--app-var; | ||
background: $__app-var2; | ||
} | ||
|
||
<==> input/_library.scss | ||
$--app-red: red; | ||
$--app-var: $--app-red; | ||
$__app-var2: blue; | ||
|
||
<==> output/entrypoint.scss | ||
@use "library"; | ||
a { | ||
color: library.$var; | ||
background: library.$var2; | ||
} | ||
|
||
<==> output/_library.scss | ||
$red: red; | ||
$var: $red; | ||
$var2: blue; |
36 changes: 36 additions & 0 deletions
36
test/migrators/module/remove_prefix_flag/with_leading_dash.hrx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<==> arguments | ||
--remove-prefix=--lib- | ||
|
||
<==> input/entrypoint.scss | ||
$--lib-a: 5; | ||
$--lib_b: $--lib-a + 2; | ||
|
||
@function --lib-fn($--lib-local) { | ||
@return $--lib-local; | ||
} | ||
|
||
@mixin --lib-mixin { | ||
--lib-property: --lib-value; | ||
} | ||
|
||
--lib-selector { | ||
property: --lib-fn(0); | ||
@include --lib-mixin; | ||
} | ||
|
||
<==> output/entrypoint.scss | ||
$a: 5; | ||
$b: $a + 2; | ||
|
||
@function fn($--lib-local) { | ||
@return $--lib-local; | ||
} | ||
|
||
@mixin mixin { | ||
--lib-property: --lib-value; | ||
} | ||
|
||
--lib-selector { | ||
property: fn(0); | ||
@include mixin; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<==> arguments | ||
--remove-prefix=lib | ||
|
||
<==> input/entrypoint.scss | ||
$lib-a: 5; | ||
$lib_b: $lib-a + 2; | ||
|
||
@function lib-fn($lib-local) { | ||
@return $lib-local; | ||
} | ||
|
||
@mixin lib-mixin { | ||
lib-property: lib-value; | ||
} | ||
|
||
lib-selector { | ||
lib-property: lib-fn(0); | ||
@include lib-mixin; | ||
} | ||
|
||
<==> output/entrypoint.scss | ||
$a: 5; | ||
$b: $a + 2; | ||
|
||
@function fn($lib-local) { | ||
@return $lib-local; | ||
} | ||
|
||
@mixin mixin { | ||
lib-property: lib-value; | ||
} | ||
|
||
lib-selector { | ||
lib-property: fn(0); | ||
@include mixin; | ||
} | ||
|
||
<==> output/entrypoint.import.scss | ||
@forward "entrypoint" as lib-*; |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<==> arguments | ||
--migrate-deps | ||
<==> input/entrypoint.scss | ||
@import "library"; | ||
a { | ||
color: $-var; | ||
} | ||
|
||
<==> input/_library.scss | ||
$-red: red; | ||
$-var: $-red; | ||
|
||
<==> output/entrypoint.scss | ||
@use "library"; | ||
a { | ||
color: library.$var; | ||
} | ||
|
||
<==> output/_library.scss | ||
$-red: red; | ||
$var: $-red; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<==> arguments | ||
--migrate-deps | ||
<==> input/entrypoint.scss | ||
@import "library"; | ||
a { | ||
color: $---; | ||
} | ||
|
||
<==> input/_library.scss | ||
$---: red; | ||
|
||
<==> output/entrypoint.scss | ||
@use "library"; | ||
a { | ||
color: library.$private---; | ||
} | ||
|
||
<==> output/_library.scss | ||
$private---: red; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<==> arguments | ||
--migrate-deps | ||
<==> input/entrypoint.scss | ||
@import "library"; | ||
a { | ||
color: $--var; | ||
} | ||
|
||
<==> input/_library.scss | ||
$--red: red; | ||
$--var: $--red; | ||
|
||
<==> output/entrypoint.scss | ||
@use "library"; | ||
a { | ||
color: library.$var; | ||
} | ||
|
||
<==> output/_library.scss | ||
$--red: red; | ||
$var: $--red; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case maybe it's better to only run substring(1), otherwise multiple dashes will get replaced to 1 dash still
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
_privateToPublic()
should handle multiple dashes gracefully.