├── .gitignore ├── CHANGELOG.md ├── analysis_options.yaml ├── AUTHORS ├── .travis.yml ├── pubspec.yaml ├── LICENSE ├── README.md ├── CONTRIBUTING.md └── tool └── generate.dart /.gitignore: -------------------------------------------------------------------------------- 1 | .packages 2 | .pub/ 3 | .dart_tool/ 4 | build/ 5 | pubspec.lock 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.1 2 | 3 | * Fix the homepage URL. 4 | 5 | ## 1.0.0 6 | 7 | * Initial version. 8 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | errors: 4 | deprecated_member_use: ignore 5 | 6 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Below is a list of people and organizations that have contributed 2 | # to the project. Names should be added to the list like so: 3 | # 4 | # Name/Organization 5 | 6 | Google Inc. 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: dart 2 | 3 | dart: 4 | - dev 5 | 6 | dart_task: 7 | - dartanalyzer 8 | 9 | # Only building master means that we don't run two builds for each pull request. 10 | branches: 11 | only: [master, dart1, dart2] 12 | 13 | cache: 14 | directories: 15 | - $HOME/.pub-cache 16 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart2_constant 2 | version: 1.0.1-dev 3 | description: A polyfill for Dart 2 constant names. 4 | author: Dart Team 5 | homepage: https://github.com/dart-lang/dart2_constant 6 | 7 | environment: 8 | sdk: '>=1.24.0 <2.0.0' 9 | 10 | dev_dependencies: 11 | args: "^1.0.0" 12 | analyzer: ">=0.30.0 <0.32.0" 13 | dart_style: "^1.0.0" 14 | path: "^1.0.0" 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017, the Dart project authors. All rights reserved. 2 | Redistribution and use in source and binary forms, with or without 3 | modification, are permitted provided that the following conditions are 4 | met: 5 | 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above 9 | copyright notice, this list of conditions and the following 10 | disclaimer in the documentation and/or other materials provided 11 | with the distribution. 12 | * Neither the name of Google Inc. nor the names of its 13 | contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This package is a polyfill for the core library constant names that are changing 2 | from Dart 1 to Dart 2. 3 | 4 | In Dart 1, all core library constants were in `SCREAMING_CAPS`. In Dart 2, 5 | they're being changed to `camelCase`. This package makes it possible for 6 | packages to support both Dart 1 and Dart 2 by providing `camelCase` constants 7 | that work on all versions of Dart. 8 | 9 | This package has a library for each library `dart:` library that contained 10 | constants in Dart 1. These libraries contain only constants, using the Dart 2 11 | names. They should be imported using a prefix so as to avoid colliding with core 12 | library names: 13 | 14 | ```dart 15 | import 'package:dart2_constant/convert.dart' as convert; 16 | 17 | String decodeUtf8(List bytes) => convert.utf8.decode(bytes); 18 | ``` 19 | 20 | Note that this even supports constants that haven't yet migrated in the core 21 | libraries, such as those in `dart:io` and `dart:html`. These are provided for 22 | compatibility with future SDK changes. 23 | 24 | ## How It Works 25 | 26 | Each version of `dart2_constant` has two releases, one tagged `+dart1` that's 27 | only compatible SDKs that have old-style constants and one tagged `+dart2` 28 | that's only compatible with SDKs that have new-style constants. As long as you 29 | depend on `dart2_constant`, pub's version solver will make sure your users get 30 | a version of it that works for them. 31 | 32 | ## See Also 33 | 34 | The [`dart2_fix`][] package can be used to automatically migrate constant 35 | references from Dart 1 style to Dart 2 style. It doesn't [currently][] support 36 | migrating to `dart2_constant` references, though. 37 | 38 | [`dart2_fix`]: https://pub.dartlang.org/packages/dart2_fix 39 | [currently]: https://github.com/dart-lang/dart2_fix/issues/18 40 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at 2 | the end). 3 | 4 | ### Before you contribute 5 | 6 | Before we can use your code, you must sign the 7 | [Google Individual Contributor License Agreement][CLA] (CLA), which you can do 8 | online. The CLA is necessary mainly because you own the copyright to your 9 | changes, even after your contribution becomes part of our codebase, so we need 10 | your permission to use and distribute your code. We also need to be sure of 11 | various other things—for instance that you'll tell us if you know that your code 12 | infringes on other people's patents. You don't have to sign the CLA until after 13 | you've submitted your code for review and a member has approved it, but you must 14 | do it before we can put your code into our codebase. 15 | 16 | Before you start working on a larger contribution, you should get in touch with 17 | us first through the issue tracker with your idea so that we can help out and 18 | possibly guide you. Coordinating up front makes it much easier to avoid 19 | frustration later on. 20 | 21 | [CLA]: https://cla.developers.google.com/about/google-individual 22 | 23 | ### Code reviews 24 | 25 | All submissions, including submissions by project members, require review. We 26 | recommend [forking the repository][fork], making changes in your fork, and 27 | [sending us a pull request][pr] so we can review the changes and merge them into 28 | this repository. 29 | 30 | [fork]: https://help.github.com/articles/about-forks/ 31 | [pr]: https://help.github.com/articles/creating-a-pull-request/ 32 | 33 | Functional changes will require tests to be added or changed. The tests live in 34 | the `test/` directory, and are run with `pub run test`. If you need to create 35 | new tests, use the existing tests as a guideline for what they should look like. 36 | 37 | Before you send your pull request, make sure all the tests pass! 38 | 39 | ### File headers 40 | 41 | All files in the project must start with the following header. 42 | 43 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 44 | // for details. All rights reserved. Use of this source code is governed by a 45 | // BSD-style license that can be found in the LICENSE file. 46 | 47 | ### The small print 48 | 49 | Contributions made by corporations are covered by a different agreement than the 50 | one above, the 51 | [Software Grant and Corporate Contributor License Agreement][CCLA]. 52 | 53 | [CCLA]: https://developers.google.com/open-source/cla/corporate 54 | -------------------------------------------------------------------------------- /tool/generate.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:io'; 6 | 7 | import 'package:args/args.dart'; 8 | import 'package:analyzer/dart/element/element.dart'; 9 | import 'package:analyzer/file_system/physical_file_system.dart'; 10 | import 'package:analyzer/src/dart/sdk/sdk.dart'; 11 | import 'package:analyzer/src/generated/engine.dart'; 12 | import 'package:analyzer/src/generated/source.dart'; 13 | import 'package:dart_style/dart_style.dart'; 14 | import 'package:path/path.dart' as p; 15 | 16 | void main(List args) { 17 | var parser = new ArgParser(); 18 | parser.addFlag("dart1", 19 | help: "Generate output for Dart 1.", negatable: false); 20 | var options = parser.parse(args); 21 | 22 | if (options.rest.length != 1) { 23 | print("dart tool/generate.dart path/to/dart1/sdk"); 24 | print(""); 25 | print(parser.usage); 26 | exitCode = 1; 27 | return; 28 | } 29 | 30 | var dart1Dir = options.rest.single; 31 | if (!new File("$dart1Dir/version").existsSync()) { 32 | print("It looks like $dart1Dir isn't a Dart SDK."); 33 | exitCode = 1; 34 | return; 35 | } 36 | 37 | var generateDart1 = options["dart1"] as bool; 38 | print("Generating constants for Dart ${generateDart1 ? 1 : 2}."); 39 | 40 | new Directory("lib").createSync(recursive: true); 41 | 42 | var dart1 = _createContext(dart1Dir); 43 | var dart2 = _createContext(p.dirname(p.dirname(Platform.resolvedExecutable))); 44 | 45 | for (var lib in dart1.sourceFactory.dartSdk.sdkLibraries) { 46 | var url = Uri.parse(lib.shortName); 47 | var name = url.path; 48 | if (name.startsWith("_")) continue; 49 | 50 | var buffer = new StringBuffer(); 51 | var dart1Library = _library(dart1, url); 52 | var dart2Library = _library(dart2, url); 53 | for (var unit in [dart1Library.definingCompilationUnit] 54 | ..addAll(dart1Library.parts)) { 55 | for (var variable in unit.topLevelVariables) { 56 | if (!_isCapsConstant(variable)) continue; 57 | 58 | var newName = _camelCase(variable.displayName); 59 | var useNewName = !generateDart1 && _find(dart2Library, newName) != null; 60 | if (!useNewName && _find(dart2Library, variable.displayName) == null) { 61 | continue; 62 | } 63 | 64 | buffer.write("const $newName = $name."); 65 | buffer.write(useNewName ? newName : variable.displayName); 66 | buffer.writeln(";"); 67 | } 68 | 69 | for (var type in unit.types) { 70 | if (type.isPrivate) continue; 71 | 72 | // HttpHeaders has constant names where camel-case members already exist 73 | // (CONTENT_LENGTH etc). I don't want to guess what the migration for 74 | // these will be so I'm just not converting them. 75 | if (name == "io" && type.displayName == "HttpHeaders") continue; 76 | 77 | var dart2Type = _find(dart2Library, type.displayName); 78 | if (dart2Type == null) continue; 79 | 80 | var constants = type.fields 81 | .where((field) => field.isStatic && _isCapsConstant(field)) 82 | .toList(); 83 | if (constants.isEmpty) continue; 84 | 85 | buffer.writeln("abstract class ${type.displayName} {"); 86 | for (var constant in constants) { 87 | var newName = _camelCase(constant.displayName); 88 | var useNewName = !generateDart1 && _find(dart2Type, newName) != null; 89 | if (!useNewName && _find(dart2Type, constant.displayName) == null) { 90 | continue; 91 | } 92 | 93 | buffer.write("static const $newName = $name.${type.displayName}."); 94 | buffer.write(useNewName ? newName : constant.displayName); 95 | buffer.writeln(";"); 96 | } 97 | buffer.writeln("}"); 98 | } 99 | } 100 | if (buffer.isEmpty) continue; 101 | 102 | new File("lib/$name.dart").writeAsStringSync(""" 103 | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file 104 | // for details. All rights reserved. Use of this source code is governed by a 105 | // BSD-style license that can be found in the LICENSE file. 106 | 107 | import '$url' as $name; 108 | 109 | ${new DartFormatter().format(buffer.toString())}"""); 110 | } 111 | } 112 | 113 | /// Returns an analysis context for the sdk at [sdkDir]. 114 | AnalysisContext _createContext(String sdkDir) { 115 | var sdk = new FolderBasedDartSdk(PhysicalResourceProvider.INSTANCE, 116 | PhysicalResourceProvider.INSTANCE.getFolder(sdkDir)); 117 | var uriResolver = new DartUriResolver(sdk); 118 | var context = AnalysisEngine.instance.createAnalysisContext(); 119 | context.analysisOptions = new AnalysisOptionsImpl()..strongMode = true; 120 | context.sourceFactory = new SourceFactory([uriResolver]); 121 | return context; 122 | } 123 | 124 | /// Returns the library with the given [url] from [context]. 125 | LibraryElement _library(AnalysisContext context, Uri url) => 126 | context.computeLibraryElement(context.sourceFactory.forUri(url.toString())); 127 | 128 | // Returns the field, variable, or class named [name] in [element], or `null`. 129 | Element _find(Element element, String name) { 130 | if (element is LibraryElement) { 131 | return _find(element.definingCompilationUnit, name) ?? 132 | element.parts 133 | .map((part) => _find(part, name)) 134 | .firstWhere((part) => part != null, orElse: () => null) ?? 135 | element.exportedLibraries 136 | .map((library) => _find(library, name)) 137 | .firstWhere((library) => library != null, orElse: () => null); 138 | } else if (element is CompilationUnitElement) { 139 | return element.topLevelVariables.firstWhere( 140 | (variable) => variable.displayName == name, 141 | orElse: () => null) ?? 142 | element.types 143 | .firstWhere((type) => type.displayName == name, orElse: () => null); 144 | } else if (element is ClassElement) { 145 | return element.fields 146 | .firstWhere((field) => field.displayName == name, orElse: () => null); 147 | } else { 148 | return null; 149 | } 150 | } 151 | 152 | /// Constants to skip because they're not being migrated or because they 153 | /// conflict with keywords. 154 | final _skip = ["DEFAULT_BUFFER_SIZE", "DEFAULT", "CONTINUE"]; 155 | 156 | /// Returns whether [variable] is a screaming-caps constant that should be 157 | /// polyfilled to be camel-case. 158 | bool _isCapsConstant(VariableElement variable) { 159 | if (!variable.isConst) return false; 160 | if (_skip.contains(variable.displayName)) return false; 161 | if (!variable.displayName.contains(new RegExp("^[A-Z]"))) return false; 162 | return true; 163 | } 164 | 165 | /// Special-case identifiers whose camel-casing doesn't follow the normal logic. 166 | final _specialCases = { 167 | "BASE64URL": "base64Url", 168 | "SQRT1_2": "sqrt1_2", 169 | "BIG_ENDIAN": "big", 170 | "LITTLE_ENDIAN": "little", 171 | "HOST_ENDIAN": "host" 172 | }; 173 | 174 | /// Converts a screaming-caps string [caps] to camel-case. 175 | String _camelCase(String caps) { 176 | var specialCase = _specialCases[caps]; 177 | if (specialCase != null) return specialCase; 178 | 179 | return caps.replaceAllMapped(new RegExp("(_)?([A-Z0-9])"), 180 | (match) => match[1] == null ? match[2].toLowerCase() : match[2]); 181 | } 182 | --------------------------------------------------------------------------------