diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8332adb72..dad46b4b1 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@18fe527fa8b29f134bb91f32f1a5dc5abb15ed7f + uses: github/codeql-action/init@678fc3afe258fb2e0cdc165ccf77b85719de7b3c with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -44,7 +44,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@18fe527fa8b29f134bb91f32f1a5dc5abb15ed7f + uses: github/codeql-action/autobuild@678fc3afe258fb2e0cdc165ccf77b85719de7b3c # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -58,4 +58,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@18fe527fa8b29f134bb91f32f1a5dc5abb15ed7f + uses: github/codeql-action/analyze@678fc3afe258fb2e0cdc165ccf77b85719de7b3c diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index d9b73e2be..5433fd1ee 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -49,6 +49,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@18fe527fa8b29f134bb91f32f1a5dc5abb15ed7f + uses: github/codeql-action/upload-sarif@678fc3afe258fb2e0cdc165ccf77b85719de7b3c with: sarif_file: results.sarif diff --git a/Dockerfile b/Dockerfile index 88146a415..0fd9cebe8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3-slim-bullseye@sha256:ed50d5719f8ecd0bae4d26bc91672f130463d7be05b67433ab595af39da1a95d as base +FROM ruby:3-slim-bullseye@sha256:5d413e301f37cbe63a54dadded2f347496165c1de0dbe342d1f0f0d47e25b2be as base ENV DEBIAN_FRONTEND=noninteractive ENV TZ=US/Pacific diff --git a/examples/analysis/analyzer-results-dev.txt b/examples/analysis/analyzer-results-dev.txt index ff7e794b1..9f03156b0 100644 --- a/examples/analysis/analyzer-results-dev.txt +++ b/examples/analysis/analyzer-results-dev.txt @@ -1,7 +1,7 @@ Analyzing analysis... error - lib/strict_modes.dart:15:7 - The argument type 'dynamic' can't be assigned to the parameter type 'List'. - argument_type_not_assignable - info - lib/lint.dart:9:19 - Avoid empty statements. - empty_statements + info - lib/lint.dart:9:19 - Unnecessary empty statement. Try removing the empty statement or restructuring the code. - empty_statements info - lib/lint.dart:17:7 - Close instances of `dart.core.Sink`. - close_sinks info - lib/strict_modes.dart:22:17 - The type argument(s) of 'Map' can't be inferred. Use explicit type argument(s) for 'Map'. - inference_failure_on_collection_literal info - lib/strict_modes.dart:33:3 - The generic type 'List' should have explicit type arguments but doesn't. Use explicit type arguments for 'List'. - strict_raw_type diff --git a/examples/misc/lib/articles/io/io_file_system_test.dart b/examples/misc/lib/articles/io/io_file_system_test.dart deleted file mode 100644 index e8671aa99..000000000 --- a/examples/misc/lib/articles/io/io_file_system_test.dart +++ /dev/null @@ -1,8 +0,0 @@ -// #docregion -import 'dart:convert'; -import 'dart:io'; - -void main() async { - var file = File(Platform.script.toFilePath()); - print(await (file.readAsString(encoding: ascii))); -} diff --git a/examples/misc/lib/articles/io/io_http_server_file_test.dart b/examples/misc/lib/articles/io/io_http_server_file_test.dart deleted file mode 100644 index d783cfb51..000000000 --- a/examples/misc/lib/articles/io/io_http_server_file_test.dart +++ /dev/null @@ -1,43 +0,0 @@ -// #docregion -import 'dart:io'; - -Future runServer(String basePath) async { - final server = await HttpServer.bind('127.0.0.1', 8082); - await for (final request in server) { - await handleRequest(basePath, request); - } -} - -Future handleRequest(String basePath, HttpRequest request) async { - final String path = request.uri.toFilePath(); - // PENDING: Do more security checks here. - final String resultPath = path == '/' ? '/index.html' : path; - final File file = File('$basePath$resultPath'); - if (await file.exists()) { - try { - await request.response.addStream(file.openRead()); - } catch (exception) { - print('Error happened: $exception'); - await sendInternalError(request.response); - } - } else { - await sendNotFound(request.response); - } -} - -Future sendInternalError(HttpResponse response) async { - response.statusCode = HttpStatus.internalServerError; - await response.close(); -} - -Future sendNotFound(HttpResponse response) async { - response.statusCode = HttpStatus.notFound; - await response.close(); -} - -void main() async { - // Compute base path for the request based on the location of the - // script, and then start the server. - final script = File(Platform.script.toFilePath()); - await runServer(script.parent.path); -} diff --git a/examples/misc/lib/articles/io/io_http_server_test.dart b/examples/misc/lib/articles/io/io_http_server_test.dart deleted file mode 100644 index de6f4be2a..000000000 --- a/examples/misc/lib/articles/io/io_http_server_test.dart +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -import 'dart:io'; - -void main() async { - final server = await HttpServer.bind('127.0.0.1', 8082); - await for (final request in server) { - request.response.write('Hello, world'); - await request.response.close(); - } -} diff --git a/examples/misc/lib/articles/io/io_process_stdio_test.dart b/examples/misc/lib/articles/io/io_process_stdio_test.dart deleted file mode 100644 index 6f7ecebfb..000000000 --- a/examples/misc/lib/articles/io/io_process_stdio_test.dart +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import 'dart:io'; - -void main() async { - final output = File('output.txt').openWrite(); - Process process = await Process.start('ls', ['-l']); - - // Wait for the process to finish; get the exit code. - final exitCode = (await Future.wait([ - process.stdout.pipe(output), // Send stdout to file. - process.stderr.drain(), // Discard stderr. - process.exitCode - ]))[2]; - - print('exit code: $exitCode'); -} diff --git a/examples/misc/lib/articles/io/io_process_test.dart b/examples/misc/lib/articles/io/io_process_test.dart deleted file mode 100644 index 78b688d2b..000000000 --- a/examples/misc/lib/articles/io/io_process_test.dart +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -import 'dart:io'; - -void main() async { - // List all files in the current directory, - // in UNIX-like operating systems. - ProcessResult results = await Process.run('ls', ['-l']); - print(results.stdout); -} diff --git a/examples/misc/lib/articles/io/io_process_transform_test.dart b/examples/misc/lib/articles/io/io_process_transform_test.dart deleted file mode 100644 index eaccf49ce..000000000 --- a/examples/misc/lib/articles/io/io_process_transform_test.dart +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion -import 'dart:convert'; -import 'dart:io'; - -void main() async { - final process = await Process.start('ls', ['-l']); - final lineStream = process.stdout - .transform(const Utf8Decoder()) - .transform(const LineSplitter()); - - await for (final line in lineStream) { - print(line); - } - - await process.stderr.drain(); - print('exit code: ${await process.exitCode}'); -} diff --git a/examples/misc/lib/articles/io/io_random_access_test.dart b/examples/misc/lib/articles/io/io_random_access_test.dart deleted file mode 100644 index 277ebf0df..000000000 --- a/examples/misc/lib/articles/io/io_random_access_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// #docregion -import 'dart:io'; - -void main() async { - final semicolon = ';'.codeUnitAt(0); - final result = []; - - final script = File(Platform.script.toFilePath()); - RandomAccessFile file = await script.open(mode: FileMode.read); - - // Deal with each byte. - while (true) { - final byte = await file.readByte(); - result.add(byte); - if (byte == semicolon) { - print(String.fromCharCodes(result)); - await file.close(); - break; - } - } -} diff --git a/examples/misc/lib/articles/io/io_stream_test.dart b/examples/misc/lib/articles/io/io_stream_test.dart deleted file mode 100644 index 15827aec4..000000000 --- a/examples/misc/lib/articles/io/io_stream_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -// #docregion -import 'dart:io'; - -void main() async { - final result = []; - - Stream> stream = File(Platform.script.toFilePath()).openRead(); - final semicolon = ';'.codeUnitAt(0); - - await for (final data in stream) { - for (int i = 0; i < data.length; i++) { - result.add(data[i]); - if (data[i] == semicolon) { - print(String.fromCharCodes(result)); - return; - } - } - } -} diff --git a/examples/misc/lib/articles/io/io_timer_test.dart b/examples/misc/lib/articles/io/io_timer_test.dart deleted file mode 100644 index 7e2b4a5f2..000000000 --- a/examples/misc/lib/articles/io/io_timer_test.dart +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import 'dart:async'; - -void main() { - Timer(const Duration(seconds: 1), () => print('timer')); - print('end of main'); -} diff --git a/examples/misc/lib/effective_dart/usage_bad.dart b/examples/misc/lib/effective_dart/usage_bad.dart index 7ce04ccc6..028c02148 100644 --- a/examples/misc/lib/effective_dart/usage_bad.dart +++ b/examples/misc/lib/effective_dart/usage_bad.dart @@ -6,6 +6,7 @@ // ignore_for_file: avoid_function_literals_in_foreach_calls, prefer_function_declarations_over_variables // ignore_for_file: prefer_adjacent_string_concatenation, prefer_is_not_empty, prefer_interpolation_to_compose_strings // ignore_for_file: unnecessary_this, always_declare_return_types, no_leading_underscores_for_local_identifiers +// ignore_for_file: deprecated_colon_for_default_value import 'dart:async'; import 'dart:io'; import 'dart:math'; diff --git a/examples/misc/lib/effective_dart/usage_good.dart b/examples/misc/lib/effective_dart/usage_good.dart index d35ca042d..8c89282bb 100644 --- a/examples/misc/lib/effective_dart/usage_good.dart +++ b/examples/misc/lib/effective_dart/usage_good.dart @@ -1,7 +1,7 @@ // ignore_for_file: type_annotate_public_apis, unused_element, unused_local_variable // ignore_for_file: prefer_function_declarations_over_variables, strict_raw_type, // ignore_for_file: prefer_initializing_formals, prefer_typing_uninitialized_variables -// ignore_for_file: use_super_parameters +// ignore_for_file: use_super_parameters, dead_code import 'dart:async'; import 'dart:io'; import 'dart:math'; diff --git a/examples/misc/lib/language_tour/functions.dart b/examples/misc/lib/language_tour/functions.dart index 190a85689..3d283cb4f 100644 --- a/examples/misc/lib/language_tour/functions.dart +++ b/examples/misc/lib/language_tour/functions.dart @@ -55,21 +55,6 @@ void miscDeclAnalyzedButNotTested() { // #enddocregion named-parameter-default-values } - { - // #docregion list-map-default-function-param - void doStuff( - {List list = const [1, 2, 3], - Map gifts = const { - 'first': 'paper', - 'second': 'cotton', - 'third': 'leather' - }}) { - print('list: $list'); - print('gifts: $gifts'); - } - // #enddocregion list-map-default-function-param - } - { // #docregion function-as-param void printElement(int element) { @@ -95,3 +80,9 @@ class Scrollbar extends Widget { const Scrollbar({super.key, required Widget child}); // #enddocregion required-named-parameters } + +class ScrollbarTwo extends Widget { + // #docregion required-named-parameters-nullable + const ScrollbarTwo({super.key, required Widget? child}); + // #enddocregion required-named-parameters-nullable +} diff --git a/examples/misc/lib/language_tour/metadata/misc.dart b/examples/misc/lib/language_tour/metadata/misc.dart index b61a2b228..7585221cd 100644 --- a/examples/misc/lib/language_tour/metadata/misc.dart +++ b/examples/misc/lib/language_tour/metadata/misc.dart @@ -1,6 +1,8 @@ import 'todo.dart'; -@Todo('seth', 'make this do something') +// #docregion +@Todo('Dash', 'Implement this function') void doSomething() { - print('do something'); + print('Do something'); } +// #enddocregion diff --git a/examples/misc/lib/language_tour/metadata/todo.dart b/examples/misc/lib/language_tour/metadata/todo.dart index 0a23b8a65..a8531d119 100644 --- a/examples/misc/lib/language_tour/metadata/todo.dart +++ b/examples/misc/lib/language_tour/metadata/todo.dart @@ -1,5 +1,3 @@ -library todo; - class Todo { final String who; final String what; diff --git a/examples/misc/test/library_tour/io_test.dart b/examples/misc/test/library_tour/io_test.dart index b2a623ed3..545dae4c7 100644 --- a/examples/misc/test/library_tour/io_test.dart +++ b/examples/misc/test/library_tour/io_test.dart @@ -58,7 +58,7 @@ void main() { } // #enddocregion try-catch - expect(main, prints(startsWith('FileSystemException'))); + expect(main, prints(contains('Cannot open file'))); }); test('read-from-stream', () { diff --git a/firebase.json b/firebase.json index b788c60f1..6e424e7df 100644 --- a/firebase.json +++ b/firebase.json @@ -55,6 +55,7 @@ { "source": "/articles/language/optional-types", "destination": "/faq#types", "type": 301 }, { "source": "/articles/libraries", "destination": "/articles", "type": 301 }, { "source": "/articles/libraries/converters-and-codecs", "destination": "/articles/archive/converters-and-codecs", "type": 301 }, + { "source": "/articles/libraries/dart-io", "destination": "/guides/libraries/library-tour#dartio", "type": 301 }, { "source": "/articles/libraries/zones", "destination": "/articles/archive/zones", "type": 301 }, { "source": "/articles/m*{,/**}", "destination": "/articles", "type": 301 }, { "source": "/articles/m1-language-changes{,/**}", "destination": "/guides/language/spec", "type": 301 }, @@ -138,6 +139,7 @@ { "source": "/go/analysis-server-protocol", "destination": "https://htmlpreview.github.io/?https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server/doc/api.html", "type": 301 }, { "source": "/go/cloud", "destination": "/server/google-cloud?utm_source=go-link&utm_medium=referral&utm_campaign=go-cloud", "type": 301 }, + { "source": "/go/content-hashes", "destination": "https://github.com/dart-lang/site-www/issues/4361", "type": 301 }, { "source": "/go/core-lints", "destination": "https://github.com/dart-lang/lints", "type": 301 }, { "source": "/go/dart-fix", "destination": "/tools/dart-fix", "type": 301 }, { "source": "/go/dartdoc-options-file", "destination": "https://github.com/dart-lang/dartdoc#dartdoc_optionsyaml", "type": 301 }, diff --git a/pubspec.yaml b/pubspec.yaml index 1f8867a93..2229df82d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,13 +3,13 @@ name: site_www homepage: https://dart.dev environment: - sdk: '>=2.18.1 <3.0.0' + sdk: '>=2.18.4 <3.0.0' dev_dependencies: - build_runner: ^2.1.0 + build_runner: ^2.3.2 code_excerpt_updater: path: site-shared/packages/code_excerpt_updater code_excerpter: path: site-shared/packages/code_excerpter linkcheck: ^2.0.19 - lints: ^2.0.0 + lints: ^2.0.1 diff --git a/site-shared b/site-shared index cbd9b3909..61dcf5820 160000 --- a/site-shared +++ b/site-shared @@ -1 +1 @@ -Subproject commit cbd9b3909699a817cb945a8faeec9b0730cb4fd7 +Subproject commit 61dcf58208e249511261ec796c4005a8f4e049b2 diff --git a/src/_articles/libraries/dart-io.md b/src/_articles/libraries/dart-io.md deleted file mode 100644 index 20b38449e..000000000 --- a/src/_articles/libraries/dart-io.md +++ /dev/null @@ -1,389 +0,0 @@ ---- -title: "An introduction to the dart:io library" -title: "介绍 dart:io 库的使用方式" -description: An introduction to the Dart I/O library, which is aimed at code that runs in Flutter and the standalone Dart VM. -description: 介绍 Dart 的输入和输出库。 -original-date: 2012-03-01 -date: 2021-06-03 -category: libraries ---- - -_Written by Mads Ager
-March 2012 (updated June 2021)_ - -The [dart:io]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/dart-io-library.html) library -is aimed at code that runs in Flutter and the standalone Dart VM. -In this article we will give you a feel for -what is currently possible with dart:io -by going through a couple of examples. - -{{site.alert.note}} - When writing a Flutter app, use - [Flutter-specific APIs]({{site.flutter-api}}) - instead of dart:io whenever possible. For example, use the - [Flutter asset support]({{site.flutter-docs}}/development/ui/assets-and-images) to load - images and other assets into your app. -{{site.alert.end}} - -Dart is a single-threaded programming language. -If an operation blocks the Dart thread, -the application makes no progress before that operation completes. -For scalability it is therefore crucial that no I/O operations block. -Instead of blocking on I/O operations, -dart:io uses an asynchronous programming model inspired by -[node.js,](https://nodejs.org) -[EventMachine,](https://github.com/eventmachine/eventmachine/wiki) and -[Twisted.](https://twisted.org/) - -## The Dart VM and the event loop - -Before we dive into asynchronous I/O operations, -it might be useful to explain how the standalone Dart VM operates. - -When executing a server-side application, -the Dart VM runs in an event loop with -an associated event queue of pending asynchronous operations. -The VM terminates when it has executed the current code to completion -and no more pending operations are in the queue. - -One simple way to add an event to the event queue is to -schedule a function to be called in the future. -You can do this by creating a -[Timer]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-async/Timer-class.html) object. -The following example registers a timer with the event queue -and then drops off the end of `main()`. -Because a pending operation is in the event queue, -the VM does not terminate at that point. -After one second, -the timer fires and the code in the argument callback executes. -Once that code executes to completion, -no more pending operations are in the event queue -and the VM terminates. - - -```dart -import 'dart:async'; - -void main() { - Timer(const Duration(seconds: 1), () => print('timer')); - print('end of main'); -} -``` - -Running this example at the command line, we get: - -```terminal -$ dart run timer.dart -end of main -timer -``` - -Had we made the timer repeating by using the -[Timer.periodic]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-async/Timer/Timer.periodic.html) constructor, -the VM would not terminate -and would continue to print out 'timer' every second. - -## File system access - -The dart:io library provides access to files and directories through the -[File]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/File-class.html) and -[Directory]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/Directory-class.html) classes. - -The following example prints its own source code. -To determine the location of the source code being executed, -we use the -[Platform]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/Platform-class.html) -class. - - - -```dart -import 'dart:convert'; -import 'dart:io'; - -void main() async { - var file = File(Platform.script.toFilePath()); - print(await (file.readAsString(encoding: ascii))); -} -``` - -Notice that the `readAsString()` method is asynchronous; -it returns a [Future]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-async/Future-class.html) -that returns the contents of the file -once the file has been read from the underlying system. -This asynchronicity allows the Dart thread to perform other work -while waiting for the I/O operation to complete. - -To illustrate more detailed file operations, -let's change the example to read the contents -only up to the first semicolon and then to print that. -You could do this in two ways: -either open the file for random access, -or open a -[Stream]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-async/Stream-class.html) -for the file and stream in the data. - -Here is a version that opens the file for random access operations. -The code opens the file for reading and then reads one byte at a time -until it encounters the char code for `;`. - - -```dart -import 'dart:io'; - -void main() async { - final semicolon = ';'.codeUnitAt(0); - final result = []; - - final script = File(Platform.script.toFilePath()); - RandomAccessFile file = await script.open(mode: FileMode.read); - - // Deal with each byte. - while (true) { - final byte = await file.readByte(); - result.add(byte); - if (byte == semicolon) { - print(String.fromCharCodes(result)); - await file.close(); - break; - } - } -} -``` - -When you see a use of `async` or `await`, you are seeing a Future in action. -Both the `open()` and `readByte()` methods return a Future object. - -This code is, of course, -a very simple use of random-access operations. -Operations are available for writing, -seeking to a given position, truncating, and so on. - -Let's implement a version using a stream. -The following code opens the file for reading presenting the content -as a stream of lists of bytes. Like all streams in Dart you listen on -this stream (using `await for`) and the data is given in chunks. - - -```dart -import 'dart:io'; - -void main() async { - final result = []; - - Stream> stream = File(Platform.script.toFilePath()).openRead(); - final semicolon = ';'.codeUnitAt(0); - - await for (final data in stream) { - for (int i = 0; i < data.length; i++) { - result.add(data[i]); - if (data[i] == semicolon) { - print(String.fromCharCodes(result)); - return; - } - } - } -} -``` - -The stream subscription is implicitly handled by `await for`. -Exiting the `await for` statement—using `break`, `return`, -or an uncaught exception—cancels the subscription. - -`Stream>` is used in multiple places in dart:io: -when working with stdin, files, sockets, HTTP connections, and so on. -Similarly, [IOSink]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/IOSink-class.html) objects -are used to stream data to -stdout, files, sockets, HTTP connections, and so on. - -## Interacting with processes - -For the simple case, use -[Process.run()]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/Process/run.html) -to run a process -and collect its output. Use `run()` when you don't -need interactive control over the process. - - -```dart -import 'dart:io'; - -void main() async { - // List all files in the current directory, - // in UNIX-like operating systems. - ProcessResult results = await Process.run('ls', ['-l']); - print(results.stdout); -} -``` - -You can also start a process by creating a -[Process]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/Process-class.html) object -using -[Process.start().]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/Process/start.html) - -Once you have a Process object you can interact with the process -by writing data to its stdin sink, -reading data from its stderr and stdout streams, -and killing the process. -When the process exits, the `exitCode` future completes with -the exit code of the process. - -The following example runs `ls -l` in a separate process -and prints the output and the exit code for the process to stdout. -Since we are interested in getting lines, -we use a -[Utf8Decoder]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-convert/Utf8Decoder-class.html) -(which decodes chunks of bytes into strings) followed by a -[LineSplitter]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-convert/LineSplitter-class.html) -(which splits the strings at line boundaries). - - -```dart -import 'dart:convert'; -import 'dart:io'; - -void main() async { - final process = await Process.start('ls', ['-l']); - final lineStream = process.stdout - .transform(const Utf8Decoder()) - .transform(const LineSplitter()); - - await for (final line in lineStream) { - print(line); - } - - await process.stderr.drain(); - print('exit code: ${await process.exitCode}'); -} -``` - -Notice that `exitCode` can complete before all of the lines of output -have been processed. Also note -that we do not explicitly close the process. In order to -not leak resources we have to listen to both the stderr and stdout -streams. We use `await for` to listen to stdout, -and `stderr.drain()` to listen to (and discard) stderr. - -Instead of printing the output to stdout, -we can use the streaming classes -to pipe the output of the process to a file. - - -```dart -import 'dart:io'; - -void main() async { - final output = File('output.txt').openWrite(); - Process process = await Process.start('ls', ['-l']); - - // Wait for the process to finish; get the exit code. - final exitCode = (await Future.wait([ - process.stdout.pipe(output), // Send stdout to file. - process.stderr.drain(), // Discard stderr. - process.exitCode - ]))[2]; - - print('exit code: $exitCode'); -} -``` - - -## Writing web servers - -dart:io makes it easy to write HTTP servers and clients. -To write a simple web server, -all you have to do is create an -[HttpServer]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/HttpServer-class.html) -and hook up a listener (using `await for`) to its stream of `HttpRequest`s. - -Here is a simple web server -that just answers 'Hello, world' to any request. - - -```dart -import 'dart:io'; - -void main() async { - final server = await HttpServer.bind('127.0.0.1', 8082); - await for (final request in server) { - request.response.write('Hello, world'); - await request.response.close(); - } -} -``` - -Running this application -and pointing your browser to 'http://127.0.0.1:8082' -gives you 'Hello, world' as expected. - -Let's add a bit more and actually serve files. -The base path for every file that we serve will be -the location of the script. -If no path is specified in a request we will serve index.html. -For a request with a path, -we will attempt to find the file and serve it. -If the file is not found we will respond with a '404 Not Found' status. -We make use of the streaming interface -to pipe all the data read from a file directly to the response stream. - -```dart -import 'dart:io'; - -Future runServer(String basePath) async { - final server = await HttpServer.bind('127.0.0.1', 8082); - await for (final request in server) { - await handleRequest(basePath, request); - } -} - -Future handleRequest(String basePath, HttpRequest request) async { - final String path = request.uri.toFilePath(); - // PENDING: Do more security checks here. - final String resultPath = path == '/' ? '/index.html' : path; - final File file = File('$basePath$resultPath'); - if (await file.exists()) { - try { - await request.response.addStream(file.openRead()); - } catch (exception) { - print('Error happened: $exception'); - await sendInternalError(request.response); - } - } else { - await sendNotFound(request.response); - } -} - -Future sendInternalError(HttpResponse response) async { - response.statusCode = HttpStatus.internalServerError; - await response.close(); -} - -Future sendNotFound(HttpResponse response) async { - response.statusCode = HttpStatus.notFound; - await response.close(); -} - -void main() async { - // Compute base path for the request based on the location of the - // script, and then start the server. - final script = File(Platform.script.toFilePath()); - await runServer(script.parent.path); -} -``` - -Writing HTTP clients is very similar to using the -[HttpClient]({{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-io/HttpClient-class.html) -class. - - -## Feature requests welcome - -The dart:io library is already capable of performing a lot of tasks. -For example, the [pub.dev site]({{site.pub}}) uses dart:io. - -Please give dart:io a spin and let us know what you think. -Feature requests are very welcome! -When you file a bug or feature request, -use [dartbug.com.](https://dartbug.com) -To find reported issues, search for the -[library-io label.](https://github.com/dart-lang/sdk/issues?q=label%3Alibrary-io) diff --git a/src/_data/books-dart-null-safe.yml b/src/_data/books-dart-null-safe.yml index 6315d9221..418101dab 100644 --- a/src/_data/books-dart-null-safe.yml +++ b/src/_data/books-dart-null-safe.yml @@ -1,11 +1,17 @@ -- title: 'Dart Apprentice' +- title: 'Dart Apprentice: Fundamentals' authors: - Jonathan Sande - - Matt Galloway - publisher: raywenderlich - cover: dart-apprentice.png - link: "https://www.raywenderlich.com/books/dart-apprentice" - desc: "Dart Apprentice will teach you all the basic concepts you need to master this language. Follow along the easily and thoroughly explained concepts and you will be building Dart applications in a breeze." + publisher: Kodeco + cover: dart-apprentice-fundamentals.png + link: "https://www.kodeco.com/books/dart-apprentice-fundamentals" + desc: "Dart Apprentice: Fundamentals is the first of a two-book series that will teach you all the basic concepts you need to master this powerful and versatile language." +- title: 'Dart Apprentice: Beyond the Basics' + authors: + - Jonathan Sande + publisher: Kodeco + cover: dart-apprentice-beyond-the-basics.png + link: "https://www.kodeco.com/books/dart-apprentice-beyond-the-basics" + desc: "Dart Apprentice: Beyond the Basics is the second of a two-book series that will teach you all the important concepts you need to master this powerful and versatile language." - title: "Data Structures & Algorithms in Dart" authors: - Jonathan Sande diff --git a/src/_data/linter_rules.json b/src/_data/linter_rules.json index 30d41171d..17656c04f 100644 --- a/src/_data/linter_rules.json +++ b/src/_data/linter_rules.json @@ -7,7 +7,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**DO** avoid relative imports for files in `lib/`.\n\nWhen mixing relative and absolute imports it's possible to create confusion\nwhere the same member gets imported in two different ways. One way to avoid\nthat is to ensure you consistently use absolute imports for files withing the\n`lib/` directory.\n\nThis is the opposite of 'prefer_relative_imports'.\n\nYou can also use 'avoid_relative_lib_imports' to disallow relative imports of\nfiles within `lib/` directory outside of it (for example `test/`).\n\n**GOOD:**\n\n```dart\nimport 'package:foo/bar.dart';\n\nimport 'package:foo/baz.dart';\n\nimport 'package:foo/src/baz.dart';\n...\n```\n\n**BAD:**\n\n```dart\nimport 'baz.dart';\n\nimport 'src/bag.dart'\n\nimport '../lib/baz.dart';\n\n...\n```\n\n", + "details": "**DO** avoid relative imports for files in `lib/`.\n\nWhen mixing relative and absolute imports it's possible to create confusion\nwhere the same member gets imported in two different ways. One way to avoid\nthat is to ensure you consistently use absolute imports for files within the\n`lib/` directory.\n\nThis is the opposite of 'prefer_relative_imports'.\n\nYou can also use 'avoid_relative_lib_imports' to disallow relative imports of\nfiles within `lib/` directory outside of it (for example `test/`).\n\n**BAD:**\n```dart\nimport 'baz.dart';\n\nimport 'src/bag.dart'\n\nimport '../lib/baz.dart';\n\n...\n```\n\n**GOOD:**\n```dart\nimport 'package:foo/bar.dart';\n\nimport 'package:foo/baz.dart';\n\nimport 'package:foo/src/baz.dart';\n...\n```\n\n", "sinceDartSdk": "2.10.0", "sinceLinter": "0.1.118" }, @@ -65,7 +65,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DO** avoid relative imports for files in `lib/`.\n\nWhen mixing relative and absolute imports it's possible to create confusion\nwhere the same member gets imported in two different ways. An easy way to avoid\nthat is to ensure you have no relative imports that include `lib/` in their\npaths.\n\nYou can also use 'always_use_package_imports' to disallow relative imports\nbetween files within `lib/`.\n\n**GOOD:**\n\n```dart\nimport 'package:foo/bar.dart';\n\nimport 'baz.dart';\n\n...\n```\n\n**BAD:**\n\n```dart\nimport 'package:foo/bar.dart';\n\nimport '../lib/baz.dart';\n\n...\n```\n\n", + "details": "**DO** avoid relative imports for files in `lib/`.\n\nWhen mixing relative and absolute imports it's possible to create confusion\nwhere the same member gets imported in two different ways. An easy way to avoid\nthat is to ensure you have no relative imports that include `lib/` in their\npaths.\n\nYou can also use 'always_use_package_imports' to disallow relative imports\nbetween files within `lib/`.\n\n**BAD:**\n```dart\nimport 'package:foo/bar.dart';\n\nimport '../lib/baz.dart';\n\n...\n```\n\n**GOOD:**\n```dart\nimport 'package:foo/bar.dart';\n\nimport 'baz.dart';\n\n...\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.44" }, @@ -166,8 +166,8 @@ "maturity": "stable", "incompatible": [], "sets": [], - "fixStatus": "unregistered", - "details": "**DON'T** invoke certain collection method with an argument with an unrelated\ntype.\n\nDoing this will invoke `==` on the collection's elements and most likely will\nreturn `false`.\n\nAn argument passed to a collection method should relate to the collection type\nas follows:\n\n* an argument to `Iterable.contains` should be related to `E`\n* an argument to `List.remove` should be related to `E`\n* an argument to `Map.containsKey` should be related to `K`\n* an argument to `Map.containsValue` should be related to `V`\n* an argument to `Map.remove` should be related to `K`\n* an argument to `Map.[]` should be related to `K`\n* an argument to `Queue.remove` should be related to `E`\n* an argument to `Set.containsAll` should be related to `Iterable`\n* an argument to `Set.difference` should be related to `Set`\n* an argument to `Set.intersection` should be related to `Set`\n* an argument to `Set.lookup` should be related to `E`\n* an argument to `Set.remove` should be related to `E`\n* an argument to `Set.removeAll` should be related to `Iterable`\n* an argument to `Set.retainAll` should be related to `Iterable`\n\n**BAD:**\n```dart\nvoid someFunction() {\n var list = [];\n if (list.contains('1')) print('someFunction'); // LINT\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction() {\n var set = {};\n set.removeAll({'1'}); // LINT\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction() {\n var list = [];\n if (list.contains(1)) print('someFunction'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction() {\n var set = {};\n set.removeAll({1}); // OK\n}\n```\n\n", + "fixStatus": "needsEvaluation", + "details": "**DON'T** invoke certain collection method with an argument with an unrelated\ntype.\n\nDoing this will invoke `==` on the collection's elements and most likely will\nreturn `false`.\n\nAn argument passed to a collection method should relate to the collection type\nas follows:\n\n* an argument to `Iterable.contains` should be related to `E`\n* an argument to `List.remove` should be related to `E`\n* an argument to `Map.containsKey` should be related to `K`\n* an argument to `Map.containsValue` should be related to `V`\n* an argument to `Map.remove` should be related to `K`\n* an argument to `Map.[]` should be related to `K`\n* an argument to `Queue.remove` should be related to `E`\n* an argument to `Set.lookup` should be related to `E`\n* an argument to `Set.remove` should be related to `E`\n\n**BAD:**\n```dart\nvoid someFunction() {\n var list = [];\n if (list.contains('1')) print('someFunction'); // LINT\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction() {\n var set = {};\n set.remove('1'); // LINT\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction() {\n var list = [];\n if (list.contains(1)) print('someFunction'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction() {\n var set = {};\n set.remove(1); // OK\n}\n```\n\n", "sinceDartSdk": "Unreleased", "sinceLinter": "1.29.0" }, @@ -179,7 +179,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**DO** reference only in scope identifiers in doc comments.\n\nIf you surround things like variable, method, or type names in square brackets,\nthen [`dart doc`](https://dart.dev/tools/dart-doc) will look\nup the name and link to its docs. For this all to work, ensure that all\nidentifiers in docs wrapped in brackets are in scope.\n\nFor example,\n\n**GOOD:**\n```dart\n/// Return the larger of [a] or [b].\nint max_int(int a, int b) { ... }\n```\n\nOn the other hand, assuming `outOfScopeId` is out of scope:\n\n**BAD:**\n```dart\n/// Return true if [value] is larger than [outOfScopeId].\nbool isOutOfRange(int value) { ... }\n```\n\nNote that the square bracket comment format is designed to allow \ncomments to refer to declarations using a fairly natural format \nbut does not allow *arbitrary expressions*. In particular, code \nreferences within square brackets can consist of either\n\n- a single identifier where the identifier is any identifier in scope for the comment (see the spec for what is in scope in doc comments),\n- two identifiers separated by a period where the first identifier is the name of a class that is in scope and the second is the name of a member declared in the class,\n- a single identifier followed by a pair of parentheses where the identifier is the name of a class that is in scope (used to refer to the unnamed constructor for the class), or\n- two identifiers separated by a period and followed by a pair of parentheses where the first identifier is the name of a class that is in scope and the second is the name of a named constructor (not strictly necessary, but allowed for consistency).\n\n", + "details": "**DO** reference only in scope identifiers in doc comments.\n\nIf you surround things like variable, method, or type names in square brackets,\nthen [`dart doc`](https://dart.dev/tools/dart-doc) will look\nup the name and link to its docs. For this all to work, ensure that all\nidentifiers in docs wrapped in brackets are in scope.\n\nFor example, assuming `outOfScopeId` is out of scope:\n\n**BAD:**\n```dart\n/// Return true if [value] is larger than [outOfScopeId].\nbool isOutOfRange(int value) { ... }\n```\n\n**GOOD:**\n```dart\n/// Return the larger of [a] or [b].\nint max_int(int a, int b) { ... }\n```\n\nNote that the square bracket comment format is designed to allow\ncomments to refer to declarations using a fairly natural format\nbut does not allow *arbitrary expressions*. In particular, code\nreferences within square brackets can consist of either\n\n- a single identifier where the identifier is any identifier in scope for the comment (see the spec for what is in scope in doc comments),\n- two identifiers separated by a period where the first identifier is the name of a class that is in scope and the second is the name of a member declared in the class,\n- a single identifier followed by a pair of parentheses where the identifier is the name of a class that is in scope (used to refer to the unnamed constructor for the class), or\n- two identifiers separated by a period and followed by a pair of parentheses where the first identifier is the name of a class that is in scope and the second is the name of a named constructor (not strictly necessary, but allowed for consistency).\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.17" }, @@ -194,7 +194,7 @@ "flutter" ], "fixStatus": "needsEvaluation", - "details": "**AVOID** control flow leaving finally blocks.\n\nUsing control flow in finally blocks will inevitably cause unexpected behavior\nthat is hard to debug.\n\n**GOOD:**\n```dart\nclass Ok {\n double compliantMethod() {\n var i = 5;\n try {\n i = 1 / 0;\n } catch (e) {\n print(e); // OK\n }\n return i;\n }\n}\n```\n\n**BAD:**\n```dart\nclass BadReturn {\n double nonCompliantMethod() {\n try {\n return 1 / 0;\n } catch (e) {\n print(e);\n } finally {\n return 1.0; // LINT\n }\n }\n}\n```\n\n**BAD:**\n```dart\nclass BadContinue {\n double nonCompliantMethod() {\n for (var o in [1, 2]) {\n try {\n print(o / 0);\n } catch (e) {\n print(e);\n } finally {\n continue; // LINT\n }\n }\n return 1.0;\n }\n}\n```\n\n**BAD:**\n```dart\nclass BadBreak {\n double nonCompliantMethod() {\n for (var o in [1, 2]) {\n try {\n print(o / 0);\n } catch (e) {\n print(e);\n } finally {\n break; // LINT\n }\n }\n return 1.0;\n }\n}\n```\n\n", + "details": "**AVOID** control flow leaving finally blocks.\n\nUsing control flow in finally blocks will inevitably cause unexpected behavior\nthat is hard to debug.\n\n**BAD:**\n```dart\nclass BadReturn {\n double nonCompliantMethod() {\n try {\n return 1 / 0;\n } catch (e) {\n print(e);\n } finally {\n return 1.0; // LINT\n }\n }\n}\n```\n\n**BAD:**\n```dart\nclass BadContinue {\n double nonCompliantMethod() {\n for (var o in [1, 2]) {\n try {\n print(o / 0);\n } catch (e) {\n print(e);\n } finally {\n continue; // LINT\n }\n }\n return 1.0;\n }\n}\n```\n\n**BAD:**\n```dart\nclass BadBreak {\n double nonCompliantMethod() {\n for (var o in [1, 2]) {\n try {\n print(o / 0);\n } catch (e) {\n print(e);\n } finally {\n break; // LINT\n }\n }\n return 1.0;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Ok {\n double compliantMethod() {\n var i = 5;\n try {\n i = 1 / 0;\n } catch (e) {\n print(e); // OK\n }\n return i;\n }\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.16" }, @@ -317,7 +317,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**DON'T** use adjacent strings in list.\n\nThis can be sign of forgotten comma.\n\n**GOOD:**\n```dart\nList list = [\n 'a' +\n 'b',\n 'c',\n];\n```\n\n**BAD:**\n```dart\nList list = [\n 'a'\n 'b',\n 'c',\n];\n```\n\n", + "details": "**DON'T** use adjacent strings in list.\n\nThis can be sign of forgotten comma.\n\n**BAD:**\n```dart\nList list = [\n 'a'\n 'b',\n 'c',\n];\n```\n\n**GOOD:**\n```dart\nList list = [\n 'a' +\n 'b',\n 'c',\n];\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -333,7 +333,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DON'T** use more than one case with same value.\n\nThis is usually a typo or changed value of constant.\n\n**GOOD:**\n```dart\nconst int A = 1;\nswitch (v) {\n case A:\n case 2:\n}\n```\n\n**BAD:**\n```dart\nconst int A = 1;\nswitch (v) {\n case 1:\n case 2:\n case A:\n case 2:\n}\n```\n\n", + "details": "**DON'T** use more than one case with same value.\n\nThis is usually a typo or changed value of constant.\n\n**BAD:**\n```dart\nconst int A = 1;\nswitch (v) {\n case 1:\n case 2:\n case A:\n case 2:\n}\n```\n\n**GOOD:**\n```dart\nconst int A = 1;\nswitch (v) {\n case A:\n case 2:\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -359,7 +359,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**PREFER** relative imports for files in `lib/`.\n\nWhen mixing relative and absolute imports it's possible to create confusion\nwhere the same member gets imported in two different ways. One way to avoid\nthat is to ensure you consistently use relative imports for files withing the\n`lib/` directory.\n\n**GOOD:**\n\n```dart\nimport 'bar.dart';\n```\n\n**BAD:**\n\n```dart\nimport 'package:my_package/bar.dart';\n```\n\n", + "details": "**PREFER** relative imports for files in `lib/`.\n\nWhen mixing relative and absolute imports it's possible to create confusion\nwhere the same member gets imported in two different ways. One way to avoid\nthat is to ensure you consistently use relative imports for files within the\n`lib/` directory.\n\n**BAD:**\n```dart\nimport 'package:my_package/bar.dart';\n```\n\n**GOOD:**\n```dart\nimport 'bar.dart';\n```\n\n", "sinceDartSdk": "2.6.0", "sinceLinter": "0.1.99" }, @@ -386,7 +386,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**DO** test type arguments in operator ==(Object other).\n\nNot testing types might result in null pointer exceptions which will be\nunexpected for consumers of your class.\n\n**GOOD:**\n```dart\nclass Field {\n}\n\nclass Good {\n final Field someField;\n\n Good(this.someField);\n\n @override\n bool operator ==(Object other) {\n if (identical(this, other)) {\n return true;\n }\n return other is Good &&\n this.someField == other.someField;\n }\n\n @override\n int get hashCode {\n return someField.hashCode;\n }\n}\n```\n\n**BAD:**\n```dart\nclass Field {\n}\n\nclass Bad {\n final Field someField;\n\n Bad(this.someField);\n\n @override\n bool operator ==(Object other) {\n Bad otherBad = other as Bad; // LINT\n bool areEqual = otherBad != null && otherBad.someField == someField;\n return areEqual;\n }\n\n @override\n int get hashCode {\n return someField.hashCode;\n }\n}\n```\n\n", + "details": "**DO** test type arguments in operator ==(Object other).\n\nNot testing types might result in null pointer exceptions which will be\nunexpected for consumers of your class.\n\n**BAD:**\n```dart\nclass Field {\n}\n\nclass Bad {\n final Field someField;\n\n Bad(this.someField);\n\n @override\n bool operator ==(Object other) {\n Bad otherBad = other as Bad; // LINT\n bool areEqual = otherBad != null && otherBad.someField == someField;\n return areEqual;\n }\n\n @override\n int get hashCode {\n return someField.hashCode;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Field {\n}\n\nclass Good {\n final Field someField;\n\n Good(this.someField);\n\n @override\n bool operator ==(Object other) {\n if (identical(this, other)) {\n return true;\n }\n return other is Good &&\n this.someField == other.someField;\n }\n\n @override\n int get hashCode {\n return someField.hashCode;\n }\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.16" }, @@ -398,7 +398,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**AVOID** throwing exceptions in finally blocks.\n\nThrowing exceptions in finally blocks will inevitably cause unexpected behavior\nthat is hard to debug.\n\n**GOOD:**\n```dart\nclass Ok {\n double compliantMethod() {\n var i = 5;\n try {\n i = 1 / 0;\n } catch (e) {\n print(e); // OK\n }\n return i;\n }\n}\n```\n\n**BAD:**\n```dart\nclass BadThrow {\n double nonCompliantMethod() {\n try {\n print('hello world! ${1 / 0}');\n } catch (e) {\n print(e);\n } finally {\n throw 'Find the hidden error :P'; // LINT\n }\n }\n}\n```\n\n", + "details": "**AVOID** throwing exceptions in finally blocks.\n\nThrowing exceptions in finally blocks will inevitably cause unexpected behavior\nthat is hard to debug.\n\n**BAD:**\n```dart\nclass BadThrow {\n double nonCompliantMethod() {\n try {\n print('hello world! ${1 / 0}');\n } catch (e) {\n print(e);\n } finally {\n throw 'Find the hidden error :P'; // LINT\n }\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Ok {\n double compliantMethod() {\n var i = 5;\n try {\n i = 1 / 0;\n } catch (e) {\n print(e); // OK\n }\n return i;\n }\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.16" }, @@ -452,7 +452,7 @@ "flutter" ], "fixStatus": "needsEvaluation", - "details": "**DON'T** use BuildContext across asynchronous gaps.\n\nStoring `BuildContext` for later usage can easily lead to difficult to diagnose\ncrashes. Asynchronous gaps are implicitly storing `BuildContext` and are some of\nthe easiest to overlook when writing code.\n\nWhen a `BuildContext` is used, its `mounted` property must be checked after an\nasynchronous gap.\n\n**GOOD:**\n```dart\nvoid onButtonTapped(BuildContext context) {\n Navigator.of(context).pop();\n}\n```\n\n**BAD:**\n```dart\nvoid onButtonTapped(BuildContext context) async {\n await Future.delayed(const Duration(seconds: 1));\n Navigator.of(context).pop();\n}\n```\n\n**GOOD:**\n```dart\nvoid onButtonTapped() async {\n await Future.delayed(const Duration(seconds: 1));\n\n if (!context.mounted) return;\n Navigator.of(context).pop();\n}\n```\n", + "details": "**DON'T** use BuildContext across asynchronous gaps.\n\nStoring `BuildContext` for later usage can easily lead to difficult to diagnose\ncrashes. Asynchronous gaps are implicitly storing `BuildContext` and are some of\nthe easiest to overlook when writing code.\n\nWhen a `BuildContext` is used, its `mounted` property must be checked after an\nasynchronous gap.\n\n**BAD:**\n```dart\nvoid onButtonTapped(BuildContext context) async {\n await Future.delayed(const Duration(seconds: 1));\n Navigator.of(context).pop();\n}\n```\n\n**GOOD:**\n```dart\nvoid onButtonTapped(BuildContext context) {\n Navigator.of(context).pop();\n}\n```\n\n**GOOD:**\n```dart\nvoid onButtonTapped() async {\n await Future.delayed(const Duration(seconds: 1));\n\n if (!context.mounted) return;\n Navigator.of(context).pop();\n}\n```\n", "sinceDartSdk": "2.13.0", "sinceLinter": "1.1.0" }, @@ -525,7 +525,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**DO** Use secure urls in `pubspec.yaml`.\n\nUse `https` instead of `http` or `git:`.\n\n**GOOD:**\n```yaml\nrepository: https://github.com/dart-lang/example\n```\n\n**BAD:**\n```yaml\nrepository: http://github.com/dart-lang/example\n```\n\n```yaml\ngit:\n url: git://github.com/dart-lang/example/example.git \n```\n", + "details": "**DO** Use secure urls in `pubspec.yaml`.\n\nUse `https` instead of `http` or `git:`.\n\n**BAD:**\n```yaml\nrepository: http://github.com/dart-lang/example\n```\n\n```yaml\ngit:\n url: git://github.com/dart-lang/example/example.git\n```\n\n**GOOD:**\n```yaml\nrepository: https://github.com/dart-lang/example\n```\n\n", "sinceDartSdk": "2.16.0", "sinceLinter": "1.15.0" }, @@ -561,7 +561,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "From the [flutter style guide](https://flutter.dev/style-guide/):\n\n**DO** separate the control structure expression from its statement.\n\nDon't put the statement part of an `if`, `for`, `while`, `do` on the same line\nas the expression, even if it is short. Doing so makes it unclear that there\nis relevant code there. This is especially important for early returns.\n\n**GOOD:**\n```dart\nif (notReady)\n return;\n\nif (notReady)\n return;\nelse\n print('ok')\n\nwhile (condition)\n i += 1;\n```\n\n**BAD:**\n```dart\nif (notReady) return;\n\nif (notReady)\n return;\nelse print('ok')\n\nwhile (condition) i += 1;\n```\n\n", + "details": "From the [style guide for the flutter repo](https://flutter.dev/style-guide/):\n\n**DO** separate the control structure expression from its statement.\n\nDon't put the statement part of an `if`, `for`, `while`, `do` on the same line\nas the expression, even if it is short. Doing so makes it unclear that there\nis relevant code there. This is especially important for early returns.\n\n**BAD:**\n```dart\nif (notReady) return;\n\nif (notReady)\n return;\nelse print('ok')\n\nwhile (condition) i += 1;\n```\n\n**GOOD:**\n```dart\nif (notReady)\n return;\n\nif (notReady)\n return;\nelse\n print('ok')\n\nwhile (condition)\n i += 1;\n```\n\nNote that this rule can conflict with the\n[Dart formatter](https://dart.dev/tools/dart-format), and should not be enabled\nwhen the Dart formatter is used.\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.31" }, @@ -573,7 +573,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsFix", - "details": "**DO** specify `required` on named parameter before other named parameters.\n\n**GOOD:**\n```dart\nm({required a, b, c}) ;\n```\n\n**BAD:**\n```dart\nm({b, c, required a}) ;\n```\n\n**GOOD:**\n```dart\nm({@required a, b, c}) ;\n```\n\n**BAD:**\n```dart\nm({b, c, @required a}) ;\n```\n\n", + "details": "**DO** specify `required` on named parameter before other named parameters.\n\n**BAD:**\n```dart\nm({b, c, required a}) ;\n```\n\n**GOOD:**\n```dart\nm({required a, b, c}) ;\n```\n\n**BAD:**\n```dart\nm({b, c, @required a}) ;\n```\n\n**GOOD:**\n```dart\nm({@required a, b, c}) ;\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.33" }, @@ -588,7 +588,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DO** specify `@required` on named parameters without a default value on which \nan `assert(param != null)` is done.\n\n**GOOD:**\n```dart\nm1({@required a}) {\n assert(a != null);\n}\n\nm2({a: 1}) {\n assert(a != null);\n}\n```\n\n**BAD:**\n```dart\nm1({a}) {\n assert(a != null);\n}\n```\n\nNOTE: Only asserts at the start of the bodies will be taken into account.\n\n", + "details": "**DO** specify `@required` on named parameters without a default value on which \nan `assert(param != null)` is done.\n\n**BAD:**\n```dart\nm1({a}) {\n assert(a != null);\n}\n```\n\n**GOOD:**\n```dart\nm1({@required a}) {\n assert(a != null);\n}\n\nm2({a: 1}) {\n assert(a != null);\n}\n```\n\nNOTE: Only asserts at the start of the bodies will be taken into account.\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.31" }, @@ -603,7 +603,7 @@ ], "sets": [], "fixStatus": "hasFix", - "details": "From the [flutter style guide](https://flutter.dev/style-guide/):\n\n**DO** specify type annotations.\n\nAvoid `var` when specifying that a type is unknown and short-hands that elide\ntype annotations. Use `dynamic` if you are being explicit that the type is\nunknown. Use `Object` if you are being explicit that you want an object that\nimplements `==` and `hashCode`.\n\n**GOOD:**\n```dart\nint foo = 10;\nfinal Bar bar = Bar();\nString baz = 'hello';\nconst int quux = 20;\n```\n\n**BAD:**\n```dart\nvar foo = 10;\nfinal bar = Bar();\nconst quux = 20;\n```\n\nNOTE: Using the the `@optionalTypeArgs` annotation in the `meta` package, API\nauthors can special-case type variables whose type needs to by dynamic but whose\ndeclaration should be treated as optional. For example, suppose you have a\n`Key` object whose type parameter you'd like to treat as optional. Using the\n`@optionalTypeArgs` would look like this:\n\n```dart\nimport 'package:meta/meta.dart';\n\n@optionalTypeArgs\nclass Key {\n ...\n}\n\nmain() {\n Key s = Key(); // OK!\n}\n```\n\n", + "details": "From the [style guide for the flutter repo](https://flutter.dev/style-guide/):\n\n**DO** specify type annotations.\n\nAvoid `var` when specifying that a type is unknown and short-hands that elide\ntype annotations. Use `dynamic` if you are being explicit that the type is\nunknown. Use `Object` if you are being explicit that you want an object that\nimplements `==` and `hashCode`.\n\n**BAD:**\n```dart\nvar foo = 10;\nfinal bar = Bar();\nconst quux = 20;\n```\n\n**GOOD:**\n```dart\nint foo = 10;\nfinal Bar bar = Bar();\nString baz = 'hello';\nconst int quux = 20;\n```\n\nNOTE: Using the the `@optionalTypeArgs` annotation in the `meta` package, API\nauthors can special-case type variables whose type needs to by dynamic but whose\ndeclaration should be treated as optional. For example, suppose you have a\n`Key` object whose type parameter you'd like to treat as optional. Using the\n`@optionalTypeArgs` would look like this:\n\n```dart\nimport 'package:meta/meta.dart';\n\n@optionalTypeArgs\nclass Key {\n ...\n}\n\nmain() {\n Key s = Key(); // OK!\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.4" }, @@ -618,7 +618,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DO** annotate overridden methods and fields.\n\nThis practice improves code readability and helps protect against\nunintentionally overriding superclass members.\n\n**GOOD:**\n```dart\nabstract class Dog {\n String get breed;\n void bark() {}\n}\n\nclass Husky extends Dog {\n @override\n final String breed = 'Husky';\n @override\n void bark() {}\n}\n```\n\n**BAD:**\n```dart\nclass Cat {\n int get lives => 9;\n}\n\nclass Lucky extends Cat {\n final int lives = 14;\n}\n```\n\n", + "details": "**DO** annotate overridden methods and fields.\n\nThis practice improves code readability and helps protect against\nunintentionally overriding superclass members.\n\n**BAD:**\n```dart\nclass Cat {\n int get lives => 9;\n}\n\nclass Lucky extends Cat {\n final int lives = 14;\n}\n```\n\n**GOOD:**\n```dart\nabstract class Dog {\n String get breed;\n void bark() {}\n}\n\nclass Husky extends Dog {\n @override\n final String breed = 'Husky';\n @override\n void bark() {}\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.11" }, @@ -642,7 +642,7 @@ "incompatible": [], "sets": [], "fixStatus": "noFix", - "details": "**AVOID** using `as`.\n\nIf you know the type is correct, use an assertion or assign to a more\nnarrowly-typed variable (this avoids the type check in release mode; `as` is not\ncompiled out in release mode). If you don't know whether the type is\ncorrect, check using `is` (this avoids the exception that `as` raises).\n\n**BAD:**\n```dart\n(pm as Person).firstName = 'Seth';\n```\n\n**GOOD:**\n```dart\nif (pm is Person)\n pm.firstName = 'Seth';\n```\n\nbut certainly not\n\n**BAD:**\n```dart\ntry {\n (pm as Person).firstName = 'Seth';\n} on CastError { }\n```\n\nNote that an exception is made in the case of `dynamic` since the cast has no\nperformance impact.\n\n**OK:**\n```dart\nHasScrollDirection scrollable = renderObject as dynamic;\n```\n\n\n**DEPRECATED:** This advice is no longer recommended.\n \nThe rule will be removed in a future Linter release.\n", + "details": "**AVOID** using `as`.\n\nIf you know the type is correct, use an assertion or assign to a more\nnarrowly-typed variable (this avoids the type check in release mode; `as` is not\ncompiled out in release mode). If you don't know whether the type is\ncorrect, check using `is` (this avoids the exception that `as` raises).\n\n**BAD:**\n```dart\n(pm as Person).firstName = 'Seth';\n```\n\n**GOOD:**\n```dart\nif (pm is Person)\n pm.firstName = 'Seth';\n```\n\nbut certainly not\n\n**BAD:**\n```dart\ntry {\n (pm as Person).firstName = 'Seth';\n} on CastError { }\n```\n\nNote that an exception is made in the case of `dynamic` since the cast has no\nperformance impact.\n\n**OK:**\n```dart\nHasScrollDirection scrollable = renderObject as dynamic;\n```\n\n\n**DEPRECATED:** This advice is no longer recommended.\n\nThe rule will be removed in a future Linter release.\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.5" }, @@ -690,7 +690,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**AVOID** defining a class that contains only static members.\n\nCreating classes with the sole purpose of providing utility or otherwise static\nmethods is discouraged. Dart allows functions to exist outside of classes for\nthis very reason.\n\n**BAD:**\n```dart\nclass DateUtils {\n static DateTime mostRecent(List dates) {\n return dates.reduce((a, b) => a.isAfter(b) ? a : b);\n }\n}\n\nclass _Favorites {\n static const mammal = 'weasel';\n}\n```\n\n**GOOD:**\n```dart\nDateTime mostRecent(List dates) {\n return dates.reduce((a, b) => a.isAfter(b) ? a : b);\n}\n\nconst _favoriteMammal = 'weasel';\n```\n\n", + "details": "From [Effective Dart](https://dart.dev/guides/language/effective-dart/design#avoid-defining-a-class-that-contains-only-static-members):\n\n**AVOID** defining a class that contains only static members.\n\nCreating classes with the sole purpose of providing utility or otherwise static\nmethods is discouraged. Dart allows functions to exist outside of classes for\nthis very reason.\n\n**BAD:**\n```dart\nclass DateUtils {\n static DateTime mostRecent(List dates) {\n return dates.reduce((a, b) => a.isAfter(b) ? a : b);\n }\n}\n\nclass _Favorites {\n static const mammal = 'weasel';\n}\n```\n\n**GOOD:**\n```dart\nDateTime mostRecent(List dates) {\n return dates.reduce((a, b) => a.isAfter(b) ? a : b);\n}\n\nconst _favoriteMammal = 'weasel';\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.31" }, @@ -714,7 +714,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**AVOID** overloading operator == and hashCode on classes not marked `@immutable`.\n\nIf a class is not immutable, overloading operator == and hashCode can lead to\nunpredictable and undesirable behavior when used in collections. See\nhttps://dart.dev/guides/language/effective-dart/design#avoid-defining-custom-equality-for-mutable-classes\nfor more information.\n\n**GOOD:**\n```dart\n@immutable\nclass A {\n final String key;\n const A(this.key);\n @override\n operator ==(other) => other is A && other.key == key;\n @override\n int get hashCode => key.hashCode;\n}\n```\n\n**BAD:**\n```dart\nclass B {\n String key;\n const B(this.key);\n @override\n operator ==(other) => other is B && other.key == key;\n @override\n int get hashCode => key.hashCode;\n}\n```\n\nNOTE: The lint checks the use of the @immutable annotation, and will trigger\neven if the class is otherwise not mutable. Thus:\n\n**BAD:**\n```dart\nclass C {\n final String key;\n const C(this.key);\n @override\n operator ==(other) => other is C && other.key == key;\n @override\n int get hashCode => key.hashCode;\n}\n```\n\n", + "details": "**AVOID** overloading operator == and hashCode on classes not marked `@immutable`.\n\nIf a class is not immutable, overloading operator == and hashCode can lead to\nunpredictable and undesirable behavior when used in collections. See\nhttps://dart.dev/guides/language/effective-dart/design#avoid-defining-custom-equality-for-mutable-classes\nfor more information.\n\n**BAD:**\n```dart\nclass B {\n String key;\n const B(this.key);\n @override\n operator ==(other) => other is B && other.key == key;\n @override\n int get hashCode => key.hashCode;\n}\n```\n\n**GOOD:**\n```dart\n@immutable\nclass A {\n final String key;\n const A(this.key);\n @override\n operator ==(other) => other is A && other.key == key;\n @override\n int get hashCode => key.hashCode;\n}\n```\n\nNOTE: The lint checks the use of the `@immutable` annotation, and will trigger\neven if the class is otherwise not mutable. Thus:\n\n**BAD:**\n```dart\nclass C {\n final String key;\n const C(this.key);\n @override\n operator ==(other) => other is C && other.key == key;\n @override\n int get hashCode => key.hashCode;\n}\n```\n\n", "sinceDartSdk": "2.6.0", "sinceLinter": "0.1.97" }, @@ -752,7 +752,7 @@ ], "sets": [], "fixStatus": "needsEvaluation", - "details": "**AVOID** declaring parameters as final.\n\nDeclaring parameters as final can lead to unnecessarily verbose code, especially\nwhen using the \"parameter_assignments\" rule.\n\n**GOOD:**\n```dart\nvoid badParameter(String label) { // OK\n print(label);\n}\n```\n\n**BAD:**\n```dart\nvoid goodParameter(final String label) { // LINT\n print(label);\n}\n```\n\n**GOOD:**\n```dart\nvoid badExpression(int value) => print(value); // OK\n```\n\n**BAD:**\n```dart\nvoid goodExpression(final int value) => print(value); // LINT\n```\n\n**GOOD:**\n```dart\n[1, 4, 6, 8].forEach((value) => print(value + 2)); // OK\n```\n\n**BAD:**\n```dart\n[1, 4, 6, 8].forEach((final value) => print(value + 2)); // LINT\n```\n\n", + "details": "**AVOID** declaring parameters as final.\n\nDeclaring parameters as final can lead to unnecessarily verbose code, especially\nwhen using the \"parameter_assignments\" rule.\n\n**BAD:**\n```dart\nvoid goodParameter(final String label) { // LINT\n print(label);\n}\n```\n\n**GOOD:**\n```dart\nvoid badParameter(String label) { // OK\n print(label);\n}\n```\n\n**BAD:**\n```dart\nvoid goodExpression(final int value) => print(value); // LINT\n```\n\n**GOOD:**\n```dart\nvoid badExpression(int value) => print(value); // OK\n```\n\n**BAD:**\n```dart\n[1, 4, 6, 8].forEach((final value) => print(value + 2)); // LINT\n```\n\n**GOOD:**\n```dart\n[1, 4, 6, 8].forEach((value) => print(value + 2)); // OK\n```\n\n", "sinceDartSdk": "2.16.0", "sinceLinter": "1.15.0" }, @@ -767,7 +767,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**AVOID** using `forEach` with a function literal.\n\nThe `for` loop enables a developer to be clear and explicit as to their intent.\nA return in the body of the `for` loop returns from the body of the function, \nwhere as a return in the body of the `forEach` closure only returns a value \nfor that iteration of the `forEach`. The body of a `for` loop can contain \n`await`s, while the closure body of a `forEach` cannot.\n\n**BAD:**\n```dart\npeople.forEach((person) {\n ...\n});\n```\n\n**GOOD:**\n```dart\nfor (var person in people) {\n ...\n}\n```\n", + "details": "**AVOID** using `forEach` with a function literal.\n\nThe `for` loop enables a developer to be clear and explicit as to their intent.\nA return in the body of the `for` loop returns from the body of the function,\nwhere as a return in the body of the `forEach` closure only returns a value\nfor that iteration of the `forEach`. The body of a `for` loop can contain\n`await`s, while the closure body of a `forEach` cannot.\n\n**BAD:**\n```dart\npeople.forEach((person) {\n ...\n});\n```\n\n**GOOD:**\n```dart\nfor (var person in people) {\n ...\n}\n```\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -779,7 +779,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**DON'T** implement classes that override `==`.\n\nThe `==` operator is contractually required to be an equivalence relation;\nthat is, symmetrically for all objects `o1` and `o2`, `o1 == o2` and `o2 == o1`\nmust either both be true, or both be false.\n\n> _NOTE_: Dart does not have true _value types_, so instead we consider a class\n> that implements `==` as a _proxy_ for identifying value types.\n\nWhen using `implements`, you do not inherit the method body of `==`, making it\nnearly impossible to follow the contract of `==`. Classes that override `==`\ntypically are usable directly in tests _without_ creating mocks or fakes as\nwell. For example, for a given class `Size`:\n\n```dart\nclass Size {\n final int inBytes;\n const Size(this.inBytes);\n\n @override\n bool operator ==(Object other) => other is Size && other.inBytes == inBytes;\n\n @override\n int get hashCode => inBytes.hashCode;\n}\n```\n\n**BAD**:\n```dart\nclass CustomSize implements Size {\n final int inBytes;\n const CustomSize(this.inBytes);\n\n int get inKilobytes => inBytes ~/ 1000;\n}\n```\n\n**BAD**:\n```dart\nimport 'package:test/test.dart';\nimport 'size.dart';\n\nclass FakeSize implements Size {\n int inBytes = 0;\n}\n\nvoid main() {\n test('should not throw on a size >1Kb', () {\n expect(() => someFunction(FakeSize()..inBytes = 1001), returnsNormally);\n });\n}\n```\n\n**GOOD**:\n```dart\nclass ExtendedSize extends Size {\n ExtendedSize(int inBytes) : super(inBytes);\n\n int get inKilobytes => inBytes ~/ 1000;\n}\n```\n\n**GOOD**:\n```dart\nimport 'package:test/test.dart';\nimport 'size.dart';\n\nvoid main() {\n test('should not throw on a size >1Kb', () {\n expect(() => someFunction(Size(1001)), returnsNormally);\n });\n}\n```\n\n", + "details": "**DON'T** implement classes that override `==`.\n\nThe `==` operator is contractually required to be an equivalence relation;\nthat is, symmetrically for all objects `o1` and `o2`, `o1 == o2` and `o2 == o1`\nmust either both be true, or both be false.\n\n> _NOTE_: Dart does not have true _value types_, so instead we consider a class\n> that implements `==` as a _proxy_ for identifying value types.\n\nWhen using `implements`, you do not inherit the method body of `==`, making it\nnearly impossible to follow the contract of `==`. Classes that override `==`\ntypically are usable directly in tests _without_ creating mocks or fakes as\nwell. For example, for a given class `Size`:\n\n```dart\nclass Size {\n final int inBytes;\n const Size(this.inBytes);\n\n @override\n bool operator ==(Object other) => other is Size && other.inBytes == inBytes;\n\n @override\n int get hashCode => inBytes.hashCode;\n}\n```\n\n**BAD:**\n```dart\nclass CustomSize implements Size {\n final int inBytes;\n const CustomSize(this.inBytes);\n\n int get inKilobytes => inBytes ~/ 1000;\n}\n```\n\n**BAD:**\n```dart\nimport 'package:test/test.dart';\nimport 'size.dart';\n\nclass FakeSize implements Size {\n int inBytes = 0;\n}\n\nvoid main() {\n test('should not throw on a size >1Kb', () {\n expect(() => someFunction(FakeSize()..inBytes = 1001), returnsNormally);\n });\n}\n```\n\n**GOOD:**\n```dart\nclass ExtendedSize extends Size {\n ExtendedSize(int inBytes) : super(inBytes);\n\n int get inKilobytes => inBytes ~/ 1000;\n}\n```\n\n**GOOD:**:\n```dart\nimport 'package:test/test.dart';\nimport 'size.dart';\n\nvoid main() {\n test('should not throw on a size >1Kb', () {\n expect(() => someFunction(Size(1001)), returnsNormally);\n });\n}\n```\n\n", "sinceDartSdk": "2.1.0", "sinceLinter": "0.1.62" }, @@ -794,7 +794,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "From [effective dart](https://dart.dev/guides/language/effective-dart/usage#dont-explicitly-initialize-variables-to-null):\n\n**DON'T** explicitly initialize variables to null.\n\nIn Dart, a variable or field that is not explicitly initialized automatically\ngets initialized to null. This is reliably specified by the language. There's\nno concept of \"uninitialized memory\" in Dart. Adding `= null` is redundant and\nunneeded.\n\n**GOOD:**\n```dart\nint _nextId;\n\nclass LazyId {\n int _id;\n\n int get id {\n if (_nextId == null) _nextId = 0;\n if (_id == null) _id = _nextId++;\n\n return _id;\n }\n}\n```\n\n**BAD:**\n```dart\nint _nextId = null;\n\nclass LazyId {\n int _id = null;\n\n int get id {\n if (_nextId == null) _nextId = 0;\n if (_id == null) _id = _nextId++;\n\n return _id;\n }\n}\n```\n\n", + "details": "From [Effective Dart](https://dart.dev/guides/language/effective-dart/usage#dont-explicitly-initialize-variables-to-null):\n\n**DON'T** explicitly initialize variables to null.\n\nIn Dart, a variable or field that is not explicitly initialized automatically\ngets initialized to null. This is reliably specified by the language. There's\nno concept of \"uninitialized memory\" in Dart. Adding `= null` is redundant and\nunneeded.\n\n**BAD:**\n```dart\nint _nextId = null;\n\nclass LazyId {\n int _id = null;\n\n int get id {\n if (_nextId == null) _nextId = 0;\n if (_id == null) _id = _nextId++;\n\n return _id;\n }\n}\n```\n\n**GOOD:**\n```dart\nint _nextId;\n\nclass LazyId {\n int _id;\n\n int get id {\n if (_nextId == null) _nextId = 0;\n if (_id == null) _id = _nextId++;\n\n return _id;\n }\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.11" }, @@ -869,7 +869,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**DON'T** declare arguments with values that match the defaults for the\ncorresponding parameter.\n\n**BAD:**\n```dart\nvoid f({bool valWithDefault = true, bool? val}) {\n ...\n}\n\nvoid main() {\n f(valWithDefault: true);\n}\n```\n\n**GOOD:**\n```dart\nvoid f({bool valWithDefault = true, bool? val}) {\n ...\n}\n\nvoid main() {\n f(valWithDefault: false);\n f();\n}\n```\n", + "details": "**DON'T** pass an argument that matches the corresponding parameter's default\nvalue.\n\n**BAD:**\n```dart\nvoid f({bool valWithDefault = true, bool? val}) {\n ...\n}\n\nvoid main() {\n f(valWithDefault: true);\n}\n```\n\n**GOOD:**\n```dart\nvoid f({bool valWithDefault = true, bool? val}) {\n ...\n}\n\nvoid main() {\n f(valWithDefault: false);\n f();\n}\n```\n", "sinceDartSdk": "2.8.1", "sinceLinter": "0.1.107" }, @@ -899,7 +899,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**AVOID** return types on setters.\n\nAs setters do not return a value, declaring the return type of one is redundant.\n\n**GOOD:**\n```dart\nset speed(int ms);\n```\n\n**BAD:**\n```dart\nvoid set speed(int ms);\n```\n\n", + "details": "**AVOID** return types on setters.\n\nAs setters do not return a value, declaring the return type of one is redundant.\n\n**BAD:**\n```dart\nvoid set speed(int ms);\n```\n\n**GOOD:**\n```dart\nset speed(int ms);\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.11" }, @@ -1033,7 +1033,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**DO** mark async functions as returning Future.\n\nWhen declaring an async method or function which does not return a value,\ndeclare that it returns `Future` and not just `void`.\n\n**BAD:**\n```dart\nvoid f() async {}\nvoid f2() async => null;\n```\n\n**GOOD:**\n```dart\nFuture f() async {}\nFuture f2() async => null;\n```\n\n**EXCEPTION**\n\nAn exception is made for top-level `main` functions, where the `Future`\nannotation *can* (and generally should) be dropped in favor of `void`.\n\n**GOOD:**\n```dart\nFuture f() async {}\n\nvoid main() async {\n await f();\n}\n```\n", + "details": "**DO** mark async functions as returning Future.\n\nWhen declaring an async method or function which does not return a value,\ndeclare that it returns `Future` and not just `void`.\n\n**BAD:**\n```dart\nvoid f() async {}\nvoid f2() async => null;\n```\n\n**GOOD:**\n```dart\nFuture f() async {}\nFuture f2() async => null;\n```\n\n**EXCEPTION:**\n\nAn exception is made for top-level `main` functions, where the `Future`\nannotation *can* (and generally should) be dropped in favor of `void`.\n\n**GOOD:**\n```dart\nFuture f() async {}\n\nvoid main() async {\n await f();\n}\n```\n", "sinceDartSdk": "2.1.0", "sinceLinter": "0.1.60" }, @@ -1144,7 +1144,7 @@ "flutter" ], "fixStatus": "needsEvaluation", - "details": "**PREFER** using lowerCamelCase for constant names.\n\nIn new code, use `lowerCamelCase` for constant variables, including enum values.\n\nIn existing code that uses `ALL_CAPS_WITH_UNDERSCORES` for constants, you may\ncontinue to use all caps to stay consistent.\n\n**GOOD:**\n```dart\nconst pi = 3.14;\nconst defaultTimeout = 1000;\nfinal urlScheme = RegExp('^([a-z]+):');\n\nclass Dice {\n static final numberGenerator = Random();\n}\n```\n\n**BAD:**\n```dart\nconst PI = 3.14;\nconst kDefaultTimeout = 1000;\nfinal URL_SCHEME = RegExp('^([a-z]+):');\n\nclass Dice {\n static final NUMBER_GENERATOR = Random();\n}\n\n```\n\n", + "details": "**PREFER** using lowerCamelCase for constant names.\n\nIn new code, use `lowerCamelCase` for constant variables, including enum values.\n\nIn existing code that uses `ALL_CAPS_WITH_UNDERSCORES` for constants, you may\ncontinue to use all caps to stay consistent.\n\n**BAD:**\n```dart\nconst PI = 3.14;\nconst kDefaultTimeout = 1000;\nfinal URL_SCHEME = RegExp('^([a-z]+):');\n\nclass Dice {\n static final NUMBER_GENERATOR = Random();\n}\n```\n\n**GOOD:**\n```dart\nconst pi = 3.14;\nconst defaultTimeout = 1000;\nfinal urlScheme = RegExp('^([a-z]+):');\n\nclass Dice {\n static final numberGenerator = Random();\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.1" }, @@ -1160,7 +1160,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DO** use curly braces for all flow control structures.\n\nDoing so avoids the [dangling else](https://en.wikipedia.org/wiki/Dangling_else)\nproblem.\n\n**GOOD:**\n```dart\nif (isWeekDay) {\n print('Bike to work!');\n} else {\n print('Go dancing or read a book!');\n}\n```\n\nThere is one exception to this: an `if` statement with no `else` clause where\nthe entire `if` statement and the then body all fit in one line. In that case,\nyou may leave off the braces if you prefer:\n\n**GOOD:**\n```dart\nif (arg == null) return defaultValue;\n```\n\nIf the body wraps to the next line, though, use braces:\n\n**GOOD:**\n```dart\nif (overflowChars != other.overflowChars) {\n return overflowChars < other.overflowChars;\n}\n```\n\n**BAD:**\n```dart\nif (overflowChars != other.overflowChars)\n return overflowChars < other.overflowChars;\n```\n", + "details": "**DO** use curly braces for all flow control structures.\n\nDoing so avoids the [dangling else](https://en.wikipedia.org/wiki/Dangling_else)\nproblem.\n\n**BAD:**\n```dart\nif (overflowChars != other.overflowChars)\n return overflowChars < other.overflowChars;\n```\n\n**GOOD:**\n```dart\nif (isWeekDay) {\n print('Bike to work!');\n} else {\n print('Go dancing or read a book!');\n}\n```\n\nThere is one exception to this: an `if` statement with no `else` clause where\nthe entire `if` statement and the then body all fit in one line. In that case,\nyou may leave off the braces if you prefer:\n\n**GOOD:**\n```dart\nif (arg == null) return defaultValue;\n```\n\nIf the body wraps to the next line, though, use braces:\n\n**GOOD:**\n```dart\nif (overflowChars != other.overflowChars) {\n return overflowChars < other.overflowChars;\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.57" }, @@ -1171,7 +1171,7 @@ "maturity": "stable", "incompatible": [], "sets": [], - "fixStatus": "unregistered", + "fixStatus": "needsEvaluation", "details": "Attach library doc comments (with `///`) to library directives, rather than\nleaving them dangling near the top of a library.\n\n**BAD:**\n```dart\n/// This is a great library.\nimport 'package:math';\n```\n\n```dart\n/// This is a great library.\n\nclass C {}\n```\n\n**GOOD:**\n```dart\n/// This is a great library.\nlibrary;\n\nimport 'package:math';\n\nclass C {}\n```\n\n**NOTE:** An unnamed library, like `library;` above, is only supported in Dart\n2.19 and later. Code which might run in earlier versions of Dart will need to\nprovide a name in the `library` directive.\n", "sinceDartSdk": "Unreleased", "sinceLinter": "1.29.0" @@ -1196,7 +1196,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**DO** follow the conventions in the \n[Effective Dart Guide](https://dart.dev/guides/language/effective-dart/style#ordering)\n\n**DO** place `dart:` imports before other imports.\n\n**BAD:**\n```dart\nimport 'package:bar/bar.dart';\nimport 'package:foo/foo.dart';\n\nimport 'dart:async'; // LINT\nimport 'dart:html'; // LINT\n```\n\n**BAD:**\n```dart\nimport 'dart:html'; // OK\nimport 'package:bar/bar.dart';\n\nimport 'dart:async'; // LINT\nimport 'package:foo/foo.dart';\n```\n\n**GOOD:**\n```dart\nimport 'dart:async'; // OK\nimport 'dart:html'; // OK\n\nimport 'package:bar/bar.dart';\nimport 'package:foo/foo.dart';\n```\n\n**DO** place `package:` imports before relative imports.\n\n**BAD:**\n```dart\nimport 'a.dart';\nimport 'b.dart';\n\nimport 'package:bar/bar.dart'; // LINT\nimport 'package:foo/foo.dart'; // LINT\n```\n\n**BAD:**\n```dart\nimport 'package:bar/bar.dart'; // OK\nimport 'a.dart';\n\nimport 'package:foo/foo.dart'; // LINT\nimport 'b.dart';\n```\n\n**GOOD:**\n```dart\nimport 'package:bar/bar.dart'; // OK\nimport 'package:foo/foo.dart'; // OK\n\nimport 'a.dart';\nimport 'b.dart';\n```\n\n**DO** specify exports in a separate section after all imports.\n\n**BAD:**\n```dart\nimport 'src/error.dart';\nexport 'src/error.dart'; // LINT\nimport 'src/string_source.dart';\n```\n\n**GOOD:**\n```dart\nimport 'src/error.dart';\nimport 'src/string_source.dart';\n\nexport 'src/error.dart'; // OK\n```\n\n**DO** sort sections alphabetically.\n\n**BAD:**\n```dart\nimport 'package:foo/bar.dart'; // OK\nimport 'package:bar/bar.dart'; // LINT\n\nimport 'a/b.dart'; // OK\nimport 'a.dart'; // LINT\n```\n\n**GOOD:**\n```dart\nimport 'package:bar/bar.dart'; // OK\nimport 'package:foo/bar.dart'; // OK\n\nimport 'a.dart'; // OK\nimport 'a/b.dart'; // OK\n```\n", + "details": "**DO** follow the directive ordering conventions in\n[Effective Dart](https://dart.dev/guides/language/effective-dart/style#ordering):\n\n**DO** place `dart:` imports before other imports.\n\n**BAD:**\n```dart\nimport 'package:bar/bar.dart';\nimport 'package:foo/foo.dart';\n\nimport 'dart:async'; // LINT\nimport 'dart:html'; // LINT\n```\n\n**BAD:**\n```dart\nimport 'dart:html'; // OK\nimport 'package:bar/bar.dart';\n\nimport 'dart:async'; // LINT\nimport 'package:foo/foo.dart';\n```\n\n**GOOD:**\n```dart\nimport 'dart:async'; // OK\nimport 'dart:html'; // OK\n\nimport 'package:bar/bar.dart';\nimport 'package:foo/foo.dart';\n```\n\n**DO** place `package:` imports before relative imports.\n\n**BAD:**\n```dart\nimport 'a.dart';\nimport 'b.dart';\n\nimport 'package:bar/bar.dart'; // LINT\nimport 'package:foo/foo.dart'; // LINT\n```\n\n**BAD:**\n```dart\nimport 'package:bar/bar.dart'; // OK\nimport 'a.dart';\n\nimport 'package:foo/foo.dart'; // LINT\nimport 'b.dart';\n```\n\n**GOOD:**\n```dart\nimport 'package:bar/bar.dart'; // OK\nimport 'package:foo/foo.dart'; // OK\n\nimport 'a.dart';\nimport 'b.dart';\n```\n\n**DO** specify exports in a separate section after all imports.\n\n**BAD:**\n```dart\nimport 'src/error.dart';\nexport 'src/error.dart'; // LINT\nimport 'src/string_source.dart';\n```\n\n**GOOD:**\n```dart\nimport 'src/error.dart';\nimport 'src/string_source.dart';\n\nexport 'src/error.dart'; // OK\n```\n\n**DO** sort sections alphabetically.\n\n**BAD:**\n```dart\nimport 'package:foo/bar.dart'; // OK\nimport 'package:bar/bar.dart'; // LINT\n\nimport 'a/b.dart'; // OK\nimport 'a.dart'; // LINT\n```\n\n**GOOD:**\n```dart\nimport 'package:bar/bar.dart'; // OK\nimport 'package:foo/bar.dart'; // OK\n\nimport 'a.dart'; // OK\nimport 'a/b.dart'; // OK\n```\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -1239,10 +1239,22 @@ "flutter" ], "fixStatus": "hasFix", - "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**DO** use `;` instead of `{}` for empty constructor bodies.\n\nIn Dart, a constructor with an empty body can be terminated with just a\nsemicolon. This is required for const constructors. For consistency and\nbrevity, other constructors should also do this.\n\n**GOOD:**\n```dart\nclass Point {\n int x, y;\n Point(this.x, this.y);\n}\n```\n\n**BAD:**\n```dart\nclass Point {\n int x, y;\n Point(this.x, this.y) {}\n}\n```\n\n", + "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**DO** use `;` instead of `{}` for empty constructor bodies.\n\nIn Dart, a constructor with an empty body can be terminated with just a\nsemicolon. This is required for const constructors. For consistency and\nbrevity, other constructors should also do this.\n\n**BAD:**\n```dart\nclass Point {\n int x, y;\n Point(this.x, this.y) {}\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n int x, y;\n Point(this.x, this.y);\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.1" }, + { + "name": "enable_null_safety", + "description": "Do use sound null safety.", + "group": "style", + "maturity": "stable", + "incompatible": [], + "sets": [], + "fixStatus": "noFix", + "details": "**DO** use sound null safety, by not specifying a dart version lower than `2.12`.\n\n**BAD:**\n```dart\n// @dart=2.8\na() {\n}\n```\n\n**GOOD:**\n```dart\nb() {\n}\n```\n", + "sinceDartSdk": "Unreleased", + "sinceLinter": "1.30.0" + }, { "name": "eol_at_end_of_file", "description": "Put a single newline at end of file.", @@ -1282,7 +1294,7 @@ "flutter" ], "fixStatus": "needsEvaluation", - "details": "**DO** name source files using `lowercase_with_underscores`.\n\nSome file systems are not case-sensitive, so many projects require filenames to\nbe all lowercase. Using a separating character allows names to still be readable\nin that form. Using underscores as the separator ensures that the name is still\na valid Dart identifier, which may be helpful if the language later supports\nsymbolic imports.\n\n**GOOD:**\n\n* `slider_menu.dart`\n* `file_system.dart`\n\n**BAD:**\n\n* `SliderMenu.dart`\n* `filesystem.dart`\n* `file-system.dart`\n\nFiles without a strict `.dart` extension are ignored. For example:\n\n**OK:**\n\n* `file-system.g.dart`\n* `SliderMenu.css.dart`\n\nThe lint `library_names` can be used to enforce the same kind of naming on the\nlibrary.\n\n", + "details": "**DO** name source files using `lowercase_with_underscores`.\n\nSome file systems are not case-sensitive, so many projects require filenames to\nbe all lowercase. Using a separating character allows names to still be readable\nin that form. Using underscores as the separator ensures that the name is still\na valid Dart identifier, which may be helpful if the language later supports\nsymbolic imports.\n\n**BAD:**\n\n* `SliderMenu.dart`\n* `filesystem.dart`\n* `file-system.dart`\n\n**GOOD:**\n\n* `slider_menu.dart`\n* `file_system.dart`\n\nFiles without a strict `.dart` extension are ignored. For example:\n\n**OK:**\n\n* `file-system.g.dart`\n* `SliderMenu.css.dart`\n\nThe lint `library_names` can be used to enforce the same kind of naming on the\nlibrary.\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.54" }, @@ -1309,7 +1321,7 @@ "flutter" ], "fixStatus": "needsEvaluation", - "details": "From the the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files):\n\n**DON'T** import implementation files from another package.\n\nThe libraries inside `lib` are publicly visible: other packages are free to\nimport them. But much of a package's code is internal implementation libraries\nthat should only be imported and used by the package itself. Those go inside a\nsubdirectory of `lib` called `src`. You can create subdirectories in there if\nit helps you organize things.\n\nYou are free to import libraries that live in `lib/src` from within other Dart\ncode in the same package (like other libraries in `lib`, scripts in `bin`,\nand tests) but you should never import from another package's `lib/src`\ndirectory. Those files are not part of the package's public API, and they\nmight change in ways that could break your code.\n\n**BAD:**\n```dart\n// In 'road_runner'\nimport 'package:acme/lib/src/internals.dart;\n```\n\n", + "details": "From the the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files):\n\n**DON'T** import implementation files from another package.\n\nThe libraries inside `lib` are publicly visible: other packages are free to\nimport them. But much of a package's code is internal implementation libraries\nthat should only be imported and used by the package itself. Those go inside a\nsubdirectory of `lib` called `src`. You can create subdirectories in there if\nit helps you organize things.\n\nYou are free to import libraries that live in `lib/src` from within other Dart\ncode in the same package (like other libraries in `lib`, scripts in `bin`,\nand tests) but you should never import from another package's `lib/src`\ndirectory. Those files are not part of the package's public API, and they\nmight change in ways that could break your code.\n\n**BAD:**\n```dart\n// In 'road_runner'\nimport 'package:acme/src/internals.dart';\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.4" }, @@ -1320,7 +1332,7 @@ "maturity": "experimental", "incompatible": [], "sets": [], - "fixStatus": "unregistered", + "fixStatus": "hasFix", "details": "**DO**\nExplicitly tear off `.call` methods from objects when assigning to a Function\ntype. There is less magic with an explicit tear off. Future language versions\nmay remove the implicit call tear off.\n\n**BAD:**\n```dart\nclass Callable {\n void call() {}\n}\nvoid callIt(void Function() f) {\n f();\n}\n\ncallIt(Callable());\n```\n\n**GOOD:**\n```dart\nclass Callable {\n void call() {}\n}\nvoid callIt(void Function() f) {\n f();\n}\n\ncallIt(Callable().call);\n```\n\n", "sinceDartSdk": "Unreleased", "sinceLinter": "1.29.0" @@ -1349,6 +1361,18 @@ "sinceDartSdk": "2.8.1", "sinceLinter": "0.1.113" }, + { + "name": "library_annotations", + "description": "Attach library annotations to library directives.", + "group": "style", + "maturity": "stable", + "incompatible": [], + "sets": [], + "fixStatus": "needsFix", + "details": "Attach library annotations to library directives, rather than\nsome other library-level element.\n\n**BAD:**\n```dart\nimport 'package:test/test.dart';\n\n@TestOn('browser')\nvoid main() {}\n```\n\n**GOOD:**\n```dart\n@TestOn('browser')\nlibrary;\nimport 'package:test/test.dart';\n\nvoid main() {}\n```\n\n**NOTE:** An unnamed library, like `library;` above, is only supported in Dart\n2.19 and later. Code which might run in earlier versions of Dart will need to\nprovide a name in the `library` directive.\n", + "sinceDartSdk": "Unreleased", + "sinceLinter": "1.30.0" + }, { "name": "library_names", "description": "Name libraries using `lowercase_with_underscores`.", @@ -1360,7 +1384,7 @@ "flutter" ], "fixStatus": "needsEvaluation", - "details": "**DO** name libraries using `lowercase_with_underscores`.\n\nSome file systems are not case-sensitive, so many projects require filenames to\nbe all lowercase. Using a separating character allows names to still be readable\nin that form. Using underscores as the separator ensures that the name is still\na valid Dart identifier, which may be helpful if the language later supports\nsymbolic imports.\n\n**GOOD:**\n```dart\nlibrary peg_parser;\n```\n\n**BAD:**\n```dart\nlibrary peg-parser;\n```\n\nThe lint `file_names` can be used to enforce the same kind of naming on the\nfile.\n\n", + "details": "**DO** name libraries using `lowercase_with_underscores`.\n\nSome file systems are not case-sensitive, so many projects require filenames to\nbe all lowercase. Using a separating character allows names to still be readable\nin that form. Using underscores as the separator ensures that the name is still\na valid Dart identifier, which may be helpful if the language later supports\nsymbolic imports.\n\n**BAD:**\n```dart\nlibrary peg-parser;\n```\n\n**GOOD:**\n```dart\nlibrary peg_parser;\n```\n\nThe lint `file_names` can be used to enforce the same kind of naming on the\nfile.\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.1" }, @@ -1375,7 +1399,7 @@ "flutter" ], "fixStatus": "needsEvaluation", - "details": "**DO** use `lowercase_with_underscores` when specifying a library prefix.\n\n**GOOD:**\n```dart\nimport 'dart:math' as math;\nimport 'dart:json' as json;\nimport 'package:js/js.dart' as js;\nimport 'package:javascript_utils/javascript_utils.dart' as js_utils;\n```\n\n**BAD:**\n```dart\nimport 'dart:math' as Math;\nimport 'dart:json' as JSON;\nimport 'package:js/js.dart' as JS;\nimport 'package:javascript_utils/javascript_utils.dart' as jsUtils;\n```\n\n", + "details": "**DO** use `lowercase_with_underscores` when specifying a library prefix.\n\n**BAD:**\n```dart\nimport 'dart:math' as Math;\nimport 'dart:json' as JSON;\nimport 'package:js/js.dart' as JS;\nimport 'package:javascript_utils/javascript_utils.dart' as jsUtils;\n```\n\n**GOOD:**\n```dart\nimport 'dart:math' as math;\nimport 'dart:json' as json;\nimport 'package:js/js.dart' as js;\nimport 'package:javascript_utils/javascript_utils.dart' as js_utils;\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.1" }, @@ -1390,7 +1414,7 @@ "flutter" ], "fixStatus": "needsEvaluation", - "details": "**AVOID** using library private types in public APIs.\n\nFor the purposes of this lint, a public API is considered to be any top-level or\nmember declaration unless the declaration is library private or contained in a\ndeclaration that's library private. The following uses of types are checked:\n\n- the return type of a function or method,\n- the type of any parameter of a function or method,\n- the bound of a type parameter to any function, method, class, mixin,\n extension's extended type, or type alias,\n- the type of any top level variable or field,\n- any type used in the declaration of a type alias (for example\n `typedef F = _Private Function();`), or\n- any type used in the `on` clause of an extension or a mixin\n\n**GOOD:**\n```dart\nf(String s) { ... }\n```\n\n**BAD:**\n```dart\nf(_Private p) { ... }\nclass _Private {}\n```\n\n", + "details": "**AVOID** using library private types in public APIs.\n\nFor the purposes of this lint, a public API is considered to be any top-level or\nmember declaration unless the declaration is library private or contained in a\ndeclaration that's library private. The following uses of types are checked:\n\n- the return type of a function or method,\n- the type of any parameter of a function or method,\n- the bound of a type parameter to any function, method, class, mixin,\n extension's extended type, or type alias,\n- the type of any top level variable or field,\n- any type used in the declaration of a type alias (for example\n `typedef F = _Private Function();`), or\n- any type used in the `on` clause of an extension or a mixin\n\n**BAD:**\n```dart\nf(_Private p) { ... }\nclass _Private {}\n```\n\n**GOOD:**\n```dart\nf(String s) { ... }\n```\n\n", "sinceDartSdk": "2.14.0", "sinceLinter": "1.3.0" }, @@ -1426,7 +1450,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "Switches on enums and enum-like classes should not use a `default` clause.\n\nEnum-like classes are defined as concrete (non-abstract) classes that have:\n * only private non-factory constructors\n * two or more static const fields whose type is the enclosing class and\n * no subclasses of the class in the defining library\n\n**DO** define default behavior outside switch statements.\n\n**GOOD:**\n```dart\n switch (testEnum) {\n case TestEnum.A:\n return '123';\n case TestEnum.B:\n return 'abc';\n }\n // Default here.\n return null;\n```\n\n**BAD:**\n```dart\n switch (testEnum) {\n case TestEnum.A:\n return '123';\n case TestEnum.B:\n return 'abc';\n default:\n return null;\n }\n```\n", + "details": "Switches on enums and enum-like classes should not use a `default` clause.\n\nEnum-like classes are defined as concrete (non-abstract) classes that have:\n * only private non-factory constructors\n * two or more static const fields whose type is the enclosing class and\n * no subclasses of the class in the defining library\n\n**DO** define default behavior outside switch statements.\n\n**BAD:**\n```dart\n switch (testEnum) {\n case TestEnum.A:\n return '123';\n case TestEnum.B:\n return 'abc';\n default:\n return null;\n }\n```\n\n**GOOD:**\n```dart\n switch (testEnum) {\n case TestEnum.A:\n return '123';\n case TestEnum.B:\n return 'abc';\n }\n // Default here.\n return null;\n```\n\n", "sinceDartSdk": "2.9.0", "sinceLinter": "0.1.116" }, @@ -1441,7 +1465,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DON'T** use a leading underscore for library prefixes.\nThere is no concept of \"private\" for library prefixes. When one of those has a\nname that starts with an underscore, it sends a confusing signal to the reader. \nTo avoid that, don't use leading underscores in those names.\n\n**BAD**\n```dart\nimport 'dart:core' as _core;\n```\n\n**GOOD:**\n```dart\nimport 'dart:core' as core;\n```\n", + "details": "**DON'T** use a leading underscore for library prefixes.\nThere is no concept of \"private\" for library prefixes. When one of those has a\nname that starts with an underscore, it sends a confusing signal to the reader. \nTo avoid that, don't use leading underscores in those names.\n\n**BAD:**\n```dart\nimport 'dart:core' as _core;\n```\n\n**GOOD:**\n```dart\nimport 'dart:core' as core;\n```\n", "sinceDartSdk": "2.16.0", "sinceLinter": "1.15.0" }, @@ -1456,7 +1480,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DON'T** use a leading underscore for identifiers that aren't private. Dart\nuses a leading underscore in an identifier to mark members and top-level\ndeclarations as private. This trains users to associate a leading underscore\nwith one of those kinds of declarations. They see `_` and think \"private\".\nThere is no concept of \"private\" for local variables or parameters. When one of \nthose has a name that starts with an underscore, it sends a confusing signal to\nthe reader. To avoid that, don't use leading underscores in those names.\n\n**Exception**: An unused parameter can be named `_`, `__`, `___`, etc. This is\ncommon practice in callbacks where you are passed a value but you don't need\nto use it. Giving it a name that consists solely of underscores is the idiomatic\nway to indicate that the value isn't used.\n\n**BAD**\n```dart\nvoid print(String _name) {\n var _size = _name.length;\n ...\n}\n```\n**GOOD:**\n\n```dart\nvoid print(String name) {\n var size = name.length;\n ...\n}\n```\n\n**OK:**\n\n```dart\n[1,2,3].map((_) => print('Hello'));\n```\n", + "details": "**DON'T** use a leading underscore for identifiers that aren't private. Dart\nuses a leading underscore in an identifier to mark members and top-level\ndeclarations as private. This trains users to associate a leading underscore\nwith one of those kinds of declarations. They see `_` and think \"private\".\nThere is no concept of \"private\" for local variables or parameters. When one of \nthose has a name that starts with an underscore, it sends a confusing signal to\nthe reader. To avoid that, don't use leading underscores in those names.\n\n**EXCEPTION:**: An unused parameter can be named `_`, `__`, `___`, etc. This is\ncommon practice in callbacks where you are passed a value but you don't need\nto use it. Giving it a name that consists solely of underscores is the idiomatic\nway to indicate that the value isn't used.\n\n**BAD:**\n```dart\nvoid print(String _name) {\n var _size = _name.length;\n ...\n}\n```\n**GOOD:**\n\n```dart\nvoid print(String name) {\n var size = name.length;\n ...\n}\n```\n\n**OK:**\n\n```dart\n[1,2,3].map((_) => print('Hello'));\n```\n", "sinceDartSdk": "2.16.0", "sinceLinter": "1.15.0" }, @@ -1553,7 +1577,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**AVOID** defining a one-member abstract class when a simple function will do.\n\nUnlike Java, Dart has first-class functions, closures, and a nice light syntax\nfor using them. If all you need is something like a callback, just use a\nfunction. If you're defining a class and it only has a single abstract member\nwith a meaningless name like `call` or `invoke`, there is a good chance\nyou just want a function.\n\n**GOOD:**\n```dart\ntypedef Predicate = bool Function(item);\n```\n\n**BAD:**\n```dart\nabstract class Predicate {\n bool test(item);\n}\n```\n\n", + "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**AVOID** defining a one-member abstract class when a simple function will do.\n\nUnlike Java, Dart has first-class functions, closures, and a nice light syntax\nfor using them. If all you need is something like a callback, just use a\nfunction. If you're defining a class and it only has a single abstract member\nwith a meaningless name like `call` or `invoke`, there is a good chance\nyou just want a function.\n\n**BAD:**\n```dart\nabstract class Predicate {\n bool test(item);\n}\n```\n\n**GOOD:**\n```dart\ntypedef Predicate = bool Function(item);\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.1" }, @@ -1592,7 +1616,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**DO** provide doc comments for all public APIs.\n\nAs described in the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files),\npublic APIs consist in everything in your package's `lib` folder, minus\nimplementation files in `lib/src`, adding elements explicitly exported with an\n`export` directive.\n\nFor example, given `lib/foo.dart`:\n```dart\nexport 'src/bar.dart' show Bar;\nexport 'src/baz.dart';\n\nclass Foo { }\n\nclass _Foo { }\n```\nits API includes:\n\n* `Foo` (but not `_Foo`)\n* `Bar` (exported) and\n* all *public* elements in `src/baz.dart`\n\nAll public API members should be documented with `///` doc-style comments.\n\n**GOOD:**\n```dart\n/// A Foo.\nabstract class Foo {\n /// Start foo-ing.\n void start() => _start();\n\n _start();\n}\n```\n\n**BAD:**\n```dart\nclass Bar {\n void bar();\n}\n```\n\nAdvice for writing good doc comments can be found in the\n[Doc Writing Guidelines](https://dart.dev/guides/language/effective-dart/documentation).\n\n", + "details": "**DO** provide doc comments for all public APIs.\n\nAs described in the [pub package layout doc](https://dart.dev/tools/pub/package-layout#implementation-files),\npublic APIs consist in everything in your package's `lib` folder, minus\nimplementation files in `lib/src`, adding elements explicitly exported with an\n`export` directive.\n\nFor example, given `lib/foo.dart`:\n```dart\nexport 'src/bar.dart' show Bar;\nexport 'src/baz.dart';\n\nclass Foo { }\n\nclass _Foo { }\n```\nits API includes:\n\n* `Foo` (but not `_Foo`)\n* `Bar` (exported) and\n* all *public* elements in `src/baz.dart`\n\nAll public API members should be documented with `///` doc-style comments.\n\n**BAD:**\n```dart\nclass Bar {\n void bar();\n}\n```\n\n**GOOD:**\n```dart\n/// A Foo.\nabstract class Foo {\n /// Start foo-ing.\n void start() => _start();\n\n _start();\n}\n```\n\nAdvice for writing good doc comments can be found in the\n[Doc Writing Guidelines](https://dart.dev/guides/language/effective-dart/documentation).\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.1" }, @@ -1647,7 +1671,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**DO** put asserts in initializer lists.\n\n**GOOD:**\n```dart\nclass A {\n A(int a) : assert(a != 0);\n}\n```\n\n**BAD:**\n```dart\nclass A {\n A(int a) {\n assert(a != 0);\n }\n}\n```\n", + "details": "**DO** put asserts in initializer lists.\n\n**BAD:**\n```dart\nclass A {\n A(int a) {\n assert(a != 0);\n }\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n A(int a) : assert(a != 0);\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.33" }, @@ -1686,7 +1710,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DO** use collection literals when possible.\n\n**BAD:**\n```dart\nvar points = List();\nvar addresses = Map();\nvar uniqueNames = Set();\nvar ids = LinkedHashSet();\nvar coordinates = LinkedHashMap();\n```\n\n**GOOD:**\n```dart\nvar points = [];\nvar addresses = {};\nvar uniqueNames = {};\nvar ids = {};\nvar coordinates = {};\n```\n\n**EXCEPTIONS:**\n\nThere are cases with `LinkedHashSet` or `LinkedHashMap` where a literal constructor\nwill trigger a type error so those will be excluded from the lint.\n\n```dart\nvoid main() {\n LinkedHashSet linkedHashSet = LinkedHashSet.from([1, 2, 3]); // OK\n LinkedHashMap linkedHashMap = LinkedHashMap(); // OK\n \n printSet(LinkedHashSet()); // LINT\n printHashSet(LinkedHashSet()); // OK\n\n printMap(LinkedHashMap()); // LINT\n printHashMap(LinkedHashMap()); // OK\n}\n\nvoid printSet(Set ids) => print('$ids!');\nvoid printHashSet(LinkedHashSet ids) => printSet(ids);\nvoid printMap(Map map) => print('$map!');\nvoid printHashMap(LinkedHashMap map) => printMap(map);\n```\n", + "details": "**DO** use collection literals when possible.\n\n**BAD:**\n```dart\nvar points = List();\nvar addresses = Map();\nvar uniqueNames = Set();\nvar ids = LinkedHashSet();\nvar coordinates = LinkedHashMap();\n```\n\n**GOOD:**\n```dart\nvar points = [];\nvar addresses = {};\nvar uniqueNames = {};\nvar ids = {};\nvar coordinates = {};\n```\n\n**EXCEPTIONS:**\n\nThere are cases with `LinkedHashSet` or `LinkedHashMap` where a literal constructor\nwill trigger a type error so those will be excluded from the lint.\n\n```dart\nvoid main() {\n LinkedHashSet linkedHashSet = LinkedHashSet.from([1, 2, 3]); // OK\n LinkedHashMap linkedHashMap = LinkedHashMap(); // OK\n \n printSet(LinkedHashSet()); // LINT\n printHashSet(LinkedHashSet()); // OK\n\n printMap(LinkedHashMap()); // LINT\n printHashMap(LinkedHashMap()); // OK\n}\n\nvoid printSet(Set ids) => print('$ids!');\nvoid printHashSet(LinkedHashSet ids) => printSet(ids);\nvoid printMap(Map map) => print('$map!');\nvoid printHashMap(LinkedHashMap map) => printMap(map);\n```\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -1715,7 +1739,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**PREFER** using `const` for instantiating constant constructors.\n\nIf a constructor can be invoked as const to produce a canonicalized instance,\nit's preferable to do so.\n\n**GOOD:**\n```dart\nclass A {\n const A();\n}\n\nvoid accessA() {\n A a = const A();\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n final int x;\n\n const A(this.x);\n}\n\nA foo(int x) => new A(x);\n```\n\n**BAD:**\n```dart\nclass A {\n const A();\n}\n\nvoid accessA() {\n A a = new A();\n}\n```\n\n", + "details": "**PREFER** using `const` for instantiating constant constructors.\n\nIf a constructor can be invoked as const to produce a canonicalized instance,\nit's preferable to do so.\n\n**BAD:**\n```dart\nclass A {\n const A();\n}\n\nvoid accessA() {\n A a = new A();\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n const A();\n}\n\nvoid accessA() {\n A a = const A();\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n final int x;\n\n const A(this.x);\n}\n\nA foo(int x) => new A(x);\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -1729,7 +1753,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**PREFER** declaring const constructors on `@immutable` classes.\n\nIf a class is immutable, it is usually a good idea to make its constructor a\nconst constructor.\n\n**GOOD:**\n```dart\n@immutable\nclass A {\n final a;\n const A(this.a);\n}\n```\n\n**BAD:**\n```dart\n@immutable\nclass A {\n final a;\n A(this.a);\n}\n```\n\n", + "details": "**PREFER** declaring const constructors on `@immutable` classes.\n\nIf a class is immutable, it is usually a good idea to make its constructor a\nconst constructor.\n\n**BAD:**\n```dart\n@immutable\nclass A {\n final a;\n A(this.a);\n}\n```\n\n**GOOD:**\n```dart\n@immutable\nclass A {\n final a;\n const A(this.a);\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.33" }, @@ -1743,7 +1767,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**PREFER** using `const` for const declarations.\n\nConst declarations are more hot-reload friendly and allow to use const\nconstructors if an instantiation references this declaration.\n\n**GOOD:**\n```dart\nconst o = [];\n\nclass A {\n static const o = [];\n}\n```\n\n**BAD:**\n```dart\nfinal o = const [];\n\nclass A {\n static final o = const [];\n}\n```\n\n", + "details": "**PREFER** using `const` for const declarations.\n\nConst declarations are more hot-reload friendly and allow to use const\nconstructors if an instantiation references this declaration.\n\n**BAD:**\n```dart\nfinal o = const [];\n\nclass A {\n static final o = const [];\n}\n```\n\n**GOOD:**\n```dart\nconst o = [];\n\nclass A {\n static const o = [];\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.43" }, @@ -1784,7 +1808,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DON'T** use `indexOf` to see if a collection contains an element.\n\nCalling `indexOf` to see if a collection contains something is difficult to read\nand may have poor performance.\n\nInstead, prefer `contains`.\n\n**GOOD:**\n```dart\nif (!lunchBox.contains('sandwich')) return 'so hungry...';\n```\n\n**BAD:**\n```dart\nif (lunchBox.indexOf('sandwich') == -1) return 'so hungry...';\n```\n\n", + "details": "**DON'T** use `indexOf` to see if a collection contains an element.\n\nCalling `indexOf` to see if a collection contains something is difficult to read\nand may have poor performance.\n\nInstead, prefer `contains`.\n\n**BAD:**\n```dart\nif (lunchBox.indexOf('sandwich') == -1) return 'so hungry...';\n```\n\n**GOOD:**\n```dart\nif (!lunchBox.contains('sandwich')) return 'so hungry...';\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -1981,7 +2005,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DO** use initializing formals when possible.\n\nUsing initializing formals when possible makes your code more terse.\n\n**BAD:**\n```dart\nclass Point {\n num x, y;\n Point(num x, num y) {\n this.x = x;\n this.y = y;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n num x, y;\n Point(this.x, this.y);\n}\n```\n\n**BAD:**\n```dart\nclass Point {\n num x, y;\n Point({num x, num y}) {\n this.x = x;\n this.y = y;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n num x, y;\n Point({this.x, this.y});\n}\n```\n\n**NOTE**\nThis rule will not generate a lint for named parameters unless the parameter\nname and the field name are the same. The reason for this is that resolving\nsuch a lint would require either renaming the field or renaming the parameter,\nand both of those actions would potentially be a breaking change. For example,\nthe following will not generate a lint:\n\n```dart\nclass Point {\n bool isEnabled;\n Point({bool enabled}) {\n this.isEnabled = enabled; // OK\n }\n}\n```\n\n**NOTE**\nAlso note that it is possible to enforce a type that is stricter than the\ninitialized field with an initializing formal parameter. In the following\nexample the unnamed `Bid` constructor requires a non-null `int` despite\n`amount` being declared nullable (`int?`).\n\n```dart\nclass Bid {\n final int? amount;\n Bid(int this.amount);\n Bid.pass() : amount = null;\n}\n```\n", + "details": "**DO** use initializing formals when possible.\n\nUsing initializing formals when possible makes your code more terse.\n\n**BAD:**\n```dart\nclass Point {\n num x, y;\n Point(num x, num y) {\n this.x = x;\n this.y = y;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n num x, y;\n Point(this.x, this.y);\n}\n```\n\n**BAD:**\n```dart\nclass Point {\n num x, y;\n Point({num x, num y}) {\n this.x = x;\n this.y = y;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n num x, y;\n Point({this.x, this.y});\n}\n```\n\n**NOTE:**\nThis rule will not generate a lint for named parameters unless the parameter\nname and the field name are the same. The reason for this is that resolving\nsuch a lint would require either renaming the field or renaming the parameter,\nand both of those actions would potentially be a breaking change. For example,\nthe following will not generate a lint:\n\n```dart\nclass Point {\n bool isEnabled;\n Point({bool enabled}) {\n this.isEnabled = enabled; // OK\n }\n}\n```\n\n**NOTE:**\nAlso note that it is possible to enforce a type that is stricter than the\ninitialized field with an initializing formal parameter. In the following\nexample the unnamed `Bid` constructor requires a non-null `int` despite\n`amount` being declared nullable (`int?`).\n\n```dart\nclass Bid {\n final int? amount;\n Bid(int this.amount);\n Bid.pass() : amount = null;\n}\n```\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -2039,7 +2063,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DON'T** use `length` to see if a collection is empty.\n\nThe `Iterable` contract does not require that a collection know its length or be\nable to provide it in constant time. Calling `length` just to see if the\ncollection contains anything can be painfully slow.\n\nInstead, there are faster and more readable getters: `isEmpty` and\n`isNotEmpty`. Use the one that doesn't require you to negate the result.\n\n**GOOD:**\n```dart\nif (lunchBox.isEmpty) return 'so hungry...';\nif (words.isNotEmpty) return words.join(' ');\n```\n\n**BAD:**\n```dart\nif (lunchBox.length == 0) return 'so hungry...';\nif (words.length != 0) return words.join(' ');\n```\n\n", + "details": "**DON'T** use `length` to see if a collection is empty.\n\nThe `Iterable` contract does not require that a collection know its length or be\nable to provide it in constant time. Calling `length` just to see if the\ncollection contains anything can be painfully slow.\n\nInstead, there are faster and more readable getters: `isEmpty` and\n`isNotEmpty`. Use the one that doesn't require you to negate the result.\n\n**BAD:**\n```dart\nif (lunchBox.length == 0) return 'so hungry...';\nif (words.length != 0) return words.join(' ');\n```\n\n**GOOD:**\n```dart\nif (lunchBox.isEmpty) return 'so hungry...';\nif (words.isNotEmpty) return words.join(' ');\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -2055,7 +2079,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**PREFER** `x.isNotEmpty` to `!x.isEmpty` for `Iterable` and `Map` instances.\n\nWhen testing whether an iterable or map is empty, prefer `isNotEmpty` over\n`!isEmpty` to improve code readability.\n\n**GOOD:**\n```dart\nif (todo.isNotEmpty) {\n sendResults(request, todo.isEmpty);\n}\n```\n\n**BAD:**\n```dart\nif (!sources.isEmpty) {\n process(sources);\n}\n```\n\n", + "details": "**PREFER** `x.isNotEmpty` to `!x.isEmpty` for `Iterable` and `Map` instances.\n\nWhen testing whether an iterable or map is empty, prefer `isNotEmpty` over\n`!isEmpty` to improve code readability.\n\n**BAD:**\n```dart\nif (!sources.isEmpty) {\n process(sources);\n}\n```\n\n**GOOD:**\n```dart\nif (todo.isNotEmpty) {\n sendResults(request, todo.isEmpty);\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.5" }, @@ -2198,7 +2222,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "**DO** document all public members.\n\nAll non-overriding public members should be documented with `///` doc-style\ncomments.\n\n**GOOD:**\n```dart\n/// A good thing.\nabstract class Good {\n /// Start doing your thing.\n void start() => _start();\n\n _start();\n}\n```\n\n**BAD:**\n```dart\nclass Bad {\n void meh() { }\n}\n```\n\nIn case a public member overrides a member it is up to the declaring member\nto provide documentation. For example, in the following, `Sub` needn't\ndocument `init` (though it certainly may, if there's need).\n\n**GOOD:**\n```dart\n/// Base of all things.\nabstract class Base {\n /// Initialize the base.\n void init();\n}\n\n/// A sub base.\nclass Sub extends Base {\n @override\n void init() { ... }\n}\n```\n\nNote that consistent with `dart doc`, an exception to the rule is made when\ndocumented getters have corresponding undocumented setters. In this case the\nsetters inherit the docs from the getters.\n\n", + "details": "**DO** document all public members.\n\nAll non-overriding public members should be documented with `///` doc-style\ncomments.\n\n**BAD:**\n```dart\nclass Bad {\n void meh() { }\n}\n```\n\n**GOOD:**\n```dart\n/// A good thing.\nabstract class Good {\n /// Start doing your thing.\n void start() => _start();\n\n _start();\n}\n```\n\nIn case a public member overrides a member it is up to the declaring member\nto provide documentation. For example, in the following, `Sub` needn't\ndocument `init` (though it certainly may, if there's need).\n\n**GOOD:**\n```dart\n/// Base of all things.\nabstract class Base {\n /// Initialize the base.\n void init();\n}\n\n/// A sub base.\nclass Sub extends Base {\n @override\n void init() { ... }\n}\n```\n\nNote that consistent with `dart doc`, an exception to the rule is made when\ndocumented getters have corresponding undocumented setters. In this case the\nsetters inherit the docs from the getters.\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.11" }, @@ -2225,7 +2249,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**DO** use trailing commas for all function calls and declarations unless the\nfunction call or definition, from the start of the function name up to the\nclosing parenthesis, fits in a single line.\n\n**GOOD:**\n```dart\nvoid run() {\n method(\n 'does not fit on one line',\n 'test test test test test test test test test test test',\n );\n}\n```\n\n**BAD:**\n```dart\nvoid run() {\n method('does not fit on one line',\n 'test test test test test test test test test test test');\n}\n```\n\n**Exception:** If the final parameter/argument is positional (vs named) and is\neither a function literal implemented using curly braces, a literal map, a\nliteral set or a literal array. This exception only applies if the final\nparameter does not fit entirely on one line.\n\n**Note:** This lint rule assumes `dart format` has been run over the code and\nmay produce false positives until that has happened.\n\n", + "details": "**DO** use trailing commas for all function calls and declarations unless the\nfunction call or definition, from the start of the function name up to the\nclosing parenthesis, fits in a single line.\n\n**BAD:**\n```dart\nvoid run() {\n method('does not fit on one line',\n 'test test test test test test test test test test test');\n}\n```\n\n**GOOD:**\n```dart\nvoid run() {\n method(\n 'does not fit on one line',\n 'test test test test test test test test test test test',\n );\n}\n```\n\n**EXCEPTION:** If the final parameter/argument is positional (vs named) and is\neither a function literal implemented using curly braces, a literal map, a\nliteral set or a literal array. This exception only applies if the final\nparameter does not fit entirely on one line.\n\n**NOTE:** This lint rule assumes `dart format` has been run over the code and\nmay produce false positives until that has happened.\n\n", "sinceDartSdk": "2.14.0", "sinceLinter": "1.3.0" }, @@ -2292,7 +2316,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**DO** sort constructor declarations before other members.\n\n**GOOD:**\n```dart\nabstract class Animation {\n const Animation(this.value);\n double value;\n void addListener(VoidCallback listener);\n}\n```\n\n**BAD:**\n```dart\nabstract class Visitor {\n double value;\n visitSomething(Something s);\n Visitor();\n}\n```\n\n", + "details": "**DO** sort constructor declarations before other members.\n\n**BAD:**\n```dart\nabstract class Visitor {\n double value;\n visitSomething(Something s);\n Visitor();\n}\n```\n\n**GOOD:**\n```dart\nabstract class Animation {\n const Animation(this.value);\n double value;\n void addListener(VoidCallback listener);\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.11" }, @@ -2304,7 +2328,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**DO** sort unnamed constructor declarations first, before named ones.\n\n**GOOD:**\n```dart\nabstract class CancelableFuture implements Future {\n factory CancelableFuture(computation()) => ...\n factory CancelableFuture.delayed(Duration duration, [computation()]) => ...\n ...\n}\n```\n\n**BAD:**\n```dart\nclass _PriorityItem {\n factory _PriorityItem.forName(bool isStatic, String name, _MemberKind kind) => ...\n _PriorityItem(this.isStatic, this.kind, this.isPrivate);\n ...\n}\n```\n\n", + "details": "**DO** sort unnamed constructor declarations first, before named ones.\n\n**BAD:**\n```dart\nclass _PriorityItem {\n factory _PriorityItem.forName(bool isStatic, String name, _MemberKind kind) => ...\n _PriorityItem(this.isStatic, this.kind, this.isPrivate);\n ...\n}\n```\n\n**GOOD:**\n```dart\nabstract class CancelableFuture implements Future {\n factory CancelableFuture(computation()) => ...\n factory CancelableFuture.delayed(Duration duration, [computation()]) => ...\n ...\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.11" }, @@ -2316,7 +2340,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**DO** place the `super` call last in a constructor initialization list.\n\nField initializers are evaluated in the order that they appear in the\nconstructor initialization list. If you place a `super()` call in the middle of\nan initializer list, the superclass's initializers will be evaluated right then\nbefore evaluating the rest of the subclass's initializers.\n\nWhat it doesn't mean is that the superclass's constructor body will be executed\nthen. That always happens after all initializers are run regardless of where\n`super` appears. It's vanishingly rare that the order of initializers matters,\nso the placement of `super` in the list almost never matters either.\n\nGetting in the habit of placing it last improves consistency, visually\nreinforces when the superclass's constructor body is run, and may help\nperformance.\n\n**GOOD:**\n```dart\nView(Style style, List children)\n : _children = children,\n super(style) {\n```\n\n**BAD:**\n```dart\nView(Style style, List children)\n : super(style),\n _children = children {\n```\n\n**DEPRECATED:** In Dart 2, it is a compile-time error if a superinitializer\nappears in an initializer list at any other position than at the end so this\nrule is made redundant by the Dart analyzer's basic checks and is no longer\nnecessary.\n \nThe rule will be removed in a future Linter release.\n", + "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**DO** place the `super` call last in a constructor initialization list.\n\nField initializers are evaluated in the order that they appear in the\nconstructor initialization list. If you place a `super()` call in the middle of\nan initializer list, the superclass's initializers will be evaluated right then\nbefore evaluating the rest of the subclass's initializers.\n\nWhat it doesn't mean is that the superclass's constructor body will be executed\nthen. That always happens after all initializers are run regardless of where\n`super` appears. It's vanishingly rare that the order of initializers matters,\nso the placement of `super` in the list almost never matters either.\n\nGetting in the habit of placing it last improves consistency, visually\nreinforces when the superclass's constructor body is run, and may help\nperformance.\n\n**BAD:**\n```dart\nView(Style style, List children)\n : super(style),\n _children = children {\n```\n\n**GOOD:**\n```dart\nView(Style style, List children)\n : _children = children,\n super(style) {\n```\n\n**DEPRECATED:** In Dart 2, it is a compile-time error if a superinitializer\nappears in an initializer list at any other position than at the end so this\nrule is made redundant by the Dart analyzer's basic checks and is no longer\nnecessary.\n \nThe rule will be removed in a future Linter release.\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.1" }, @@ -2340,7 +2364,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "From [effective dart](https://dart.dev/guides/language/effective-dart/design#prefer-type-annotating-public-fields-and-top-level-variables-if-the-type-isnt-obvious):\n\n**PREFER** type annotating public APIs.\n\nType annotations are important documentation for how a library should be used.\nAnnotating the parameter and return types of public methods and functions helps\nusers understand what the API expects and what it provides.\n\nNote that if a public API accepts a range of values that Dart's type system\ncannot express, then it is acceptable to leave that untyped. In that case, the\nimplicit `dynamic` is the correct type for the API.\n\nFor code internal to a library (either private, or things like nested functions)\nannotate where you feel it helps, but don't feel that you *must* provide them.\n\n**BAD:**\n```dart\ninstall(id, destination) {\n // ...\n}\n```\n\nHere, it's unclear what `id` is. A string? And what is `destination`? A string\nor a `File` object? Is this method synchronous or asynchronous?\n\n**GOOD:**\n```dart\nFuture install(PackageId id, String destination) {\n // ...\n}\n```\n\nWith types, all of this is clarified.\n\n", + "details": "From [Effective Dart](https://dart.dev/guides/language/effective-dart/design#do-type-annotate-fields-and-top-level-variables-if-the-type-isnt-obvious):\n\n**PREFER** type annotating public APIs.\n\nType annotations are important documentation for how a library should be used.\nAnnotating the parameter and return types of public methods and functions helps\nusers understand what the API expects and what it provides.\n\nNote that if a public API accepts a range of values that Dart's type system\ncannot express, then it is acceptable to leave that untyped. In that case, the\nimplicit `dynamic` is the correct type for the API.\n\nFor code internal to a library (either private, or things like nested functions)\nannotate where you feel it helps, but don't feel that you *must* provide them.\n\n**BAD:**\n```dart\ninstall(id, destination) {\n // ...\n}\n```\n\nHere, it's unclear what `id` is. A string? And what is `destination`? A string\nor a `File` object? Is this method synchronous or asynchronous?\n\n**GOOD:**\n```dart\nFuture install(PackageId id, String destination) {\n // ...\n}\n```\n\nWith types, all of this is clarified.\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.5" }, @@ -2355,7 +2379,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**DON'T** type annotate initializing formals.\n\nIf a constructor parameter is using `this.x` to initialize a field, then the\ntype of the parameter is understood to be the same type as the field. If a \na constructor parameter is using `super.x` to forward to a super constructor,\nthen the type of the parameter is understood to be the same as the super\nconstructor parameter.\n\nType annotating an initializing formal with a different type than that of the\nfield is OK.\n\n**GOOD:**\n```dart\nclass Point {\n int x, y;\n Point(this.x, this.y);\n}\n```\n\n**BAD:**\n```dart\nclass Point {\n int x, y;\n Point(int this.x, int this.y);\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n int a;\n A(this.a);\n}\n\nclass B extends A {\n B(super.a);\n}\n```\n\n**BAD:**\n```dart\nclass A {\n int a;\n A(this.a);\n}\n\nclass B extends A {\n B(int super.a);\n}\n```\n", + "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**DON'T** type annotate initializing formals.\n\nIf a constructor parameter is using `this.x` to initialize a field, then the\ntype of the parameter is understood to be the same type as the field. If a \na constructor parameter is using `super.x` to forward to a super constructor,\nthen the type of the parameter is understood to be the same as the super\nconstructor parameter.\n\nType annotating an initializing formal with a different type than that of the\nfield is OK.\n\n**BAD:**\n```dart\nclass Point {\n int x, y;\n Point(int this.x, int this.y);\n}\n```\n\n**GOOD:**\n```dart\nclass Point {\n int x, y;\n Point(this.x, this.y);\n}\n```\n\n**BAD:**\n```dart\nclass A {\n int a;\n A(this.a);\n}\n\nclass B extends A {\n B(int super.a);\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n int a;\n A(this.a);\n}\n\nclass B extends A {\n B(super.a);\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.1" }, @@ -2367,7 +2391,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**DO** await functions that return a `Future` inside of an async function body.\n\nIt's easy to forget await in async methods as naming conventions usually don't\ntell us if a method is sync or async (except for some in `dart:io`).\n\nWhen you really _do_ want to start a fire-and-forget `Future`, the recommended\nway is to use `unawaited` from `dart:async`. The `// ignore` and\n`// ignore_for_file` comments also work.\n\n**GOOD:**\n```dart\nFuture doSomething() => ...;\n\nvoid main() async {\n await doSomething();\n\n unawaited(doSomething()); // Explicitly-ignored fire-and-forget.\n}\n```\n\n**BAD:**\n```dart\nvoid main() async {\n doSomething(); // Likely a bug.\n}\n```\n\n", + "details": "**DO** await functions that return a `Future` inside of an async function body.\n\nIt's easy to forget await in async methods as naming conventions usually don't\ntell us if a method is sync or async (except for some in `dart:io`).\n\nWhen you really _do_ want to start a fire-and-forget `Future`, the recommended\nway is to use `unawaited` from `dart:async`. The `// ignore` and\n`// ignore_for_file` comments also work.\n\n**BAD:**\n```dart\nvoid main() async {\n doSomething(); // Likely a bug.\n}\n```\n\n**GOOD:**\n```dart\nFuture doSomething() => ...;\n\nvoid main() async {\n await doSomething();\n\n unawaited(doSomething()); // Explicitly-ignored fire-and-forget.\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.19" }, @@ -2394,7 +2418,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**AVOID** using braces in interpolation when not needed.\n\nIf you're just interpolating a simple identifier, and it's not immediately\nfollowed by more alphanumeric text, the `{}` can and should be omitted.\n\n**GOOD:**\n```dart\nprint(\"Hi, $name!\");\n```\n\n**BAD:**\n```dart\nprint(\"Hi, ${name}!\");\n```\n\n", + "details": "**AVOID** using braces in interpolation when not needed.\n\nIf you're just interpolating a simple identifier, and it's not immediately\nfollowed by more alphanumeric text, the `{}` can and should be omitted.\n\n**BAD:**\n```dart\nprint(\"Hi, ${name}!\");\n```\n\n**GOOD:**\n```dart\nprint(\"Hi, $name!\");\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -2439,7 +2463,7 @@ ], "sets": [], "fixStatus": "hasFix", - "details": "**DON'T** use `final` for local variables.\n\n`var` is shorter, and `final` does not change the meaning of the code.\n\n**BAD:**\n```dart\nvoid badMethod() {\n final label = 'Final or var?';\n for (final char in ['v', 'a', 'r']) {\n print(char);\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid goodMethod() {\n var label = 'Final or var?';\n for (var char in ['v', 'a', 'r']) {\n print(char);\n }\n}\n```\n", + "details": "Use `var`, not `final`, when declaring local variables.\n\nPer [Effective Dart](https://dart.dev/guides/language/effective-dart/usage#do-follow-a-consistent-rule-for-var-and-final-on-local-variables),\nthere are two styles in wide use. This rule enforces the `var` style.\nFor the alternative style that prefers `final`, enable `prefer_final_locals`\nand `prefer_final_in_for_each` instead.\n\nFor fields, `final` is always recommended; see the rule `prefer_final_fields`.\n\n**BAD:**\n```dart\nvoid badMethod() {\n final label = 'Final or var?';\n for (final char in ['v', 'a', 'r']) {\n print(char);\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid goodMethod() {\n var label = 'Final or var?';\n for (var char in ['v', 'a', 'r']) {\n print(char);\n }\n}\n```\n", "sinceDartSdk": "2.7.0", "sinceLinter": "0.1.104" }, @@ -2454,7 +2478,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**AVOID** wrapping fields in getters and setters just to be \"safe\".\n\nIn Java and C#, it's common to hide all fields behind getters and setters (or\nproperties in C#), even if the implementation just forwards to the field. That\nway, if you ever need to do more work in those members, you can do it without needing\nto touch the callsites. This is because calling a getter method is different\nthan accessing a field in Java, and accessing a property isn't binary-compatible\nwith accessing a raw field in C#.\n\nDart doesn't have this limitation. Fields and getters/setters are completely\nindistinguishable. You can expose a field in a class and later wrap it in a\ngetter and setter without having to touch any code that uses that field.\n\n**GOOD:**\n\n```dart\nclass Box {\n var contents;\n}\n```\n\n**BAD:**\n\n```dart\nclass Box {\n var _contents;\n get contents => _contents;\n set contents(value) {\n _contents = value;\n }\n}\n```\n\n", + "details": "From the [style guide](https://dart.dev/guides/language/effective-dart/style/):\n\n**AVOID** wrapping fields in getters and setters just to be \"safe\".\n\nIn Java and C#, it's common to hide all fields behind getters and setters (or\nproperties in C#), even if the implementation just forwards to the field. That\nway, if you ever need to do more work in those members, you can do it without needing\nto touch the callsites. This is because calling a getter method is different\nthan accessing a field in Java, and accessing a property isn't binary-compatible\nwith accessing a raw field in C#.\n\nDart doesn't have this limitation. Fields and getters/setters are completely\nindistinguishable. You can expose a field in a class and later wrap it in a\ngetter and setter without having to touch any code that uses that field.\n\n**BAD:**\n```dart\nclass Box {\n var _contents;\n get contents => _contents;\n set contents(value) {\n _contents = value;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Box {\n var contents;\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.1" }, @@ -2492,8 +2516,8 @@ "maturity": "stable", "incompatible": [], "sets": [], - "fixStatus": "unregistered", - "details": "**DO** use library directives if you want to document a library and/or annotate \na library.\n\n**GOOD:**\n```dart\n/// This library does important things\nlibrary;\n```\n\n```dart\n@TestOn('js')\nlibrary;\n```\n\n**BAD:**\n```dart\nlibrary;\n```\n\nNOTE: Due to limitations with this lint, libraries with parts will not be\nflagged for unnecessary library directives.\n", + "fixStatus": "needsEvaluation", + "details": "**DO** use library directives if you want to document a library and/or annotate \na library.\n\n**BAD:**\n```dart\nlibrary;\n```\n\n**GOOD:**\n```dart\n/// This library does important things\nlibrary;\n```\n\n```dart\n@TestOn('js')\nlibrary;\n```\n\nNOTE: Due to limitations with this lint, libraries with parts will not be\nflagged for unnecessary library directives.\n", "sinceDartSdk": "Unreleased", "sinceLinter": "1.29.0" }, @@ -2523,7 +2547,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**AVOID** `null` in null-aware assignment.\n\nUsing `null` on the right-hand side of a null-aware assignment effectively makes\nthe assignment redundant.\n\n**GOOD:**\n```dart\nvar x;\nx ??= 1;\n```\n\n**BAD:**\n```dart\nvar x;\nx ??= null;\n```\n\n", + "details": "**AVOID** `null` in null-aware assignment.\n\nUsing `null` on the right-hand side of a null-aware assignment effectively makes\nthe assignment redundant.\n\n**BAD:**\n```dart\nvar x;\nx ??= null;\n```\n\n**GOOD:**\n```dart\nvar x;\nx ??= 1;\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -2562,7 +2586,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**AVOID** using `null` as an operand in `if null` operators.\n\nUsing `null` in an `if null` operator is redundant, regardless of which side\n`null` is used on.\n\n**GOOD:**\n```dart\nvar x = a ?? 1;\n```\n\n**BAD:**\n```dart\nvar x = a ?? null;\nvar y = null ?? 1;\n```\n\n", + "details": "**AVOID** using `null` as an operand in `if null` operators.\n\nUsing `null` in an `if null` operator is redundant, regardless of which side\n`null` is used on.\n\n**BAD:**\n```dart\nvar x = a ?? null;\nvar y = null ?? 1;\n```\n\n**GOOD:**\n```dart\nvar x = a ?? 1;\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.30" }, @@ -2605,7 +2629,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "**AVOID** using parentheses when not needed.\n\n**GOOD:**\n```dart\na = b;\n```\n\n**BAD:**\n```dart\na = (b);\n```\n\nParentheses are considered unnecessary if they do not change the meaning of the\ncode and they do not improve the readability of the code. The goal is not to\nforce all developers to maintain the expression precedence table in their heads,\nwhich is why the second condition is included. Examples of this condition\ninclude:\n\n* cascade expressions - it is sometimes not clear what the target of a cascade\n expression is, especially with assignments, or nested cascades. For example,\n the expression `a.b = (c..d)`.\n* expressions with whitespace between tokens - it can look very strange to see\n an expression like `!await foo` which is valid and equivalent to\n `!(await foo)`.\n* logical expressions - parentheses can improve the readability of the implicit\n grouping defined by precedence. For example, the expression\n `(a && b) || c && d`.\n", + "details": "**AVOID** using parentheses when not needed.\n\n**BAD:**\n```dart\na = (b);\n```\n\n**GOOD:**\n```dart\na = b;\n```\n\nParentheses are considered unnecessary if they do not change the meaning of the\ncode and they do not improve the readability of the code. The goal is not to\nforce all developers to maintain the expression precedence table in their heads,\nwhich is why the second condition is included. Examples of this condition\ninclude:\n\n* cascade expressions - it is sometimes not clear what the target of a cascade\n expression is, especially with assignments, or nested cascades. For example,\n the expression `a.b = (c..d)`.\n* expressions with whitespace between tokens - it can look very strange to see\n an expression like `!await foo` which is valid and equivalent to\n `!(await foo)`.\n* logical expressions - parentheses can improve the readability of the implicit\n grouping defined by precedence. For example, the expression\n `(a && b) || c && d`.\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.44" }, @@ -2763,7 +2787,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "From [effective dart](https://dart.dev/guides/language/effective-dart/usage#prefer-using--to-convert-null-to-a-boolean-value):\n\nUse if-null operators to convert nulls to bools.\n\n**BAD:**\n```dart\nif (nullableBool == true) {\n}\nif (nullableBool != false) {\n}\n```\n\n**GOOD:**\n```dart\nif (nullableBool ?? false) {\n}\nif (nullableBool ?? true) {\n}\n```\n\n", + "details": "From [Effective Dart](https://dart.dev/guides/language/effective-dart/usage#prefer-using--to-convert-null-to-a-boolean-value):\n\nUse if-null operators to convert nulls to bools.\n\n**BAD:**\n```dart\nif (nullableBool == true) {\n}\nif (nullableBool != false) {\n}\n```\n\n**GOOD:**\n```dart\nif (nullableBool ?? false) {\n}\nif (nullableBool ?? true) {\n}\n```\n\n", "sinceDartSdk": "2.13.0", "sinceLinter": "1.0.0" }, @@ -2862,7 +2886,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsFix", - "details": "From [effective dart](https://dart.dev/guides/language/effective-dart/usage#do-use-strings-in-part-of-directives):\n\n**DO** use strings in `part of` directives.\n\n**BAD:**\n\n```dart\npart of my_library;\n```\n\n**GOOD:**\n\n```dart\npart of '../../my_library.dart';\n```\n\n", + "details": "From [Effective Dart](https://dart.dev/guides/language/effective-dart/usage#do-use-strings-in-part-of-directives):\n\n**DO** use strings in `part of` directives.\n\n**BAD:**\n\n```dart\npart of my_library;\n```\n\n**GOOD:**\n\n```dart\npart of '../../my_library.dart';\n```\n\n", "sinceDartSdk": "Unreleased", "sinceLinter": "1.27.0" }, @@ -2898,7 +2922,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsEvaluation", - "details": "From the [design guide](https://dart.dev/guides/language/effective-dart/design):\n\n**PREFER** naming a method to___() if it copies the object's state to a new object.\n\n**PREFER** naming a method as___() if it returns a different representation backed by the original object.\n\n**BAD:**\n```dart\nclass Bar {\n Foo myMethod() {\n return Foo.from(this);\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Bar {\n Foo toFoo() {\n return Foo.from(this);\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Bar {\n Foo asFoo() {\n return Foo.from(this);\n }\n}\n```\n\n", + "details": "From the [Effective Dart](https://dart.dev/guides/language/effective-dart/design):\n\n**PREFER** naming a method `to___()` if it copies the object's state to a new\nobject.\n\n**PREFER** naming a method `as___()` if it returns a different representation\nbacked by the original object.\n\n**BAD:**\n```dart\nclass Bar {\n Foo myMethod() {\n return Foo.from(this);\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Bar {\n Foo toFoo() {\n return Foo.from(this);\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Bar {\n Foo asFoo() {\n return Foo.from(this);\n }\n}\n```\n\n", "sinceDartSdk": "2.0.0", "sinceLinter": "0.1.31" }, diff --git a/src/_data/side-nav.yml b/src/_data/side-nav.yml index 52393ffc0..e55e690ab 100644 --- a/src/_data/side-nav.yml +++ b/src/_data/side-nav.yml @@ -96,9 +96,7 @@ permalink: /guides/libraries/library-tour - title: 介绍文章 children: - - title: dart:io 库介绍 - permalink: /articles/libraries/dart-io - - title: 使用 stream + - title: 创建 stream permalink: /articles/libraries/creating-streams - title: Packages diff --git a/src/_guides/language/coming-from/js-to-dart.md b/src/_guides/language/coming-from/js-to-dart.md index 24ac40813..e3f07806a 100644 --- a/src/_guides/language/coming-from/js-to-dart.md +++ b/src/_guides/language/coming-from/js-to-dart.md @@ -3,101 +3,96 @@ title: Learning Dart as a JavaScript developer description: Leverage your JavaScript knowledge when learning Dart. --- -This guide aims to leverage your JavaScript (JS) -programming knowledge when learning Dart. -It showcases key similarities and differences -in both languages, and introduces Dart concepts -that are not present in vanilla JavaScript. -As a JavaScript developer, -Dart should feel quite familiar, -as both languages share many concepts. +This guide aims to leverage your JavaScript programming knowledge +when learning Dart. +It showcases key similarities and differences in both languages, +and introduces Dart concepts that unsupported in JavaScript. +As a JavaScript developer, Dart should feel quite familiar, +as both languages share many concepts. Like JavaScript, Dart runs on an event loop, so both languages execute code in a similar way. For example, asynchronous concepts like futures -(promises in JS) and the `async/await` syntax are very similar. +(promises in JavaScript) and the `async/await` syntax are very similar. Dart is strongly typed, unlike JavaScript. -If you are also familiar with TypeScript or tooling -that adds static typing (like Flow), then learning Dart -probably won't be much of an extra step for you. -However, if you've mostly worked with vanilla JavaScript, -it might take a bit more effort to adjust. -The good news is that since Dart is strongly typed, -many errors that might exist in JavaScript code are -caught even before compiling your Dart code. - -As of Dart 2.12, null safety is enabled by default, -which JavaScript doesn't support. As a JavaScript developer, +If you have used with TypeScript or Flow, +this should simplify learning Dart. +If you've mostly worked with pure JavaScript, +it might be more of an adjustment. +With strong typing, Dart catches many errors before compiling +that might exist in JavaScript code. + +Dart enables null safety by default. +JavaScript doesn't support null safety. +As a JavaScript developer, it might take a while to learn how to write null safe code, but the trade-off is better protection against null reference exceptions that are detected even before compiling Dart code. (Thereby avoiding those dreaded `TypeError`s that occur when doing operations -on a JS variable that turns out to be null.) +on a JavaScript variable that turns out to be null.) ## Conventions and linting -JavaScript and Dart both have linting tools -to enforce standard conventions. However, -while JavaScript has `ESLint` as a standalone tool -(among other available tooling), -and many different standards and configurations, -Dart has official layout conventions and includes -a linter to make compliance effortless. +JavaScript and Dart both have linting tools to enforce standard conventions. +While JavaScript offers many tools, standards, and configurations, +Dart has one official set of layout and style conventions plus a linter +to simplify compliance. +The Dart analyzer lints code along with providing more analytical functions. To customize the lint rules for your project, follow the [Customizing static analysis][] instructions. -{{site.alert.secondary}} - **Pro tip:** Dart provides [`dart fix`][], - which finds and fixes errors found by the analyzer. -{{site.alert.end}} +Dart provides [`dart fix`][] to find and fix errors. -Dart also provides a code formatter, -which is similar to JS tools like [Prettier][]. -Automatically format any Dart project by running -[`dart format`](/tools/dart-format) on the command line. -For Flutter, `flutter format` acts as an alias for this command. -(Note that the IDE plugins for Dart and Flutter -also provide this functionality.) +Dart also provides a code formatter similar to JavaScript tools like [Prettier][]. +To format code in any Dart project, run [`dart format`](/tools/dart-format) on +your command line. In Flutter, use `flutter format`. +The IDE plugins for Dart and Flutter also provide this ability. -{{site.alert.secondary}} - **Pro tip:** Dart supports optional trailing - commas for any comma-separated values, - such as function parameters or list items. - This causes the formatter to place each item - onto its own line, which helps with readability, - especially when you have a lot of nested code - (as can happen in Flutter layout code). -{{site.alert.end}} +Dart supports trailing commas for comma-separated lists of collections, +parameters, or arguments. When you add the trailing comma, +the formatter places each list item on its own line. +When you believe your list may have more items at a later date, +add the trailing comma. Avoid adding the trailing comma for the formatting +benefit alone. -For more information on using commas to make your code -read more like HTML, check out -[Using trailing commas][] on flutter.dev. +JavaScript supports trailing commas in list and map literals only. -For more information about Dart conventions and linting, -check out [Effective Dart][] and [Linter rules][]. +{{site.alert.secondary}} + To learn more about: + * Using commas to make your code read more like HTML, read + [Using trailing commas][] on flutter.dev. + * Linting Dart, read [Linter rules][]. + * Writing good Dart code, read [Effective Dart][]. +{{site.alert.end}} [Customizing static analysis]: /guides/language/analysis-options [`dart fix`]: /tools/dart-fix -[Effective Dart]: /guides/language/effective-dart +[Effective Dart]: /guides/language/effective-dart [Linter rules]: /tools/linter-rules [Prettier]: https://prettier.io/ [Using trailing commas]: {{site.flutter-docs}}/development/tools/formatting#using-trailing-commas - ## Built-in types -While both JavaScript and Dart have types, -only Dart is a strongly typed language. -This means that all Dart types have to be -inferrable by the analyzer, explicitly defined, -or assigned as `dynamic`, which disables static type -checking for that identifier. +Both JavaScript and Dart categorize their data into _types_. +Every variable has an associated type. +The type determines the kind of value the variable can store and +what operations can be performed on these values. +Dart differs from JavaScript in that it assigns a static type to every +variable and to every expression. +In Dart, the static type predicts the runtime type of the values of a +variable, or of the value of an expression. +Dart assigns a static type to every expression and variable. +In Dart, the static type predicts the runtime type of the value of an +expression. This means that Dart apps have sound static typing. + +JavaScript provides primitive types `num`, `string`, and `boolean` +and the `null` value as well as _arrays_ and a `Map` type. -Dart supports nullable and non-nullable versions -of the the following built-in types: +Dart supports built-in types include: * Numbers (`num`, `int`, `double`) * Strings (`String`) @@ -108,52 +103,46 @@ of the the following built-in types: * Symbols (`Symbol`) * The value `null` (`Null`) -For more information, check out -[Built-in types][] in the [Dart Language Tour][]. +To learn more, see [Built-in types][] in the [Dart Language Tour][]. -In Dart, all types are reference types, -meaning that all variables refer to an object -(an instance of a class). However, the types -`int`, `double`, `String`, and `bool` -are implemented to be immutable (unchanging) -and are canonicalized, -which means they behave as if they are value types. +All non-`Null` types in Dart are subtypes of Object. +All values are also objects. +Dart doesn't use “primitive types” like JavaScript. +By contrast, Dart normalizes or _canonicalizes_ number, boolean +and `null` values. +This means only one `int` value with the numerical value `1` exists. {{site.alert.note}} - JavaScript has two equality operators, - `==` and `===`. The `==` operator performs - the equality test after doing any necessary - type conversions. The `===` operator doesn't - perform type conversions. Dart doesn't have - an equivalent to `===`. + JavaScript has two equality operators, `==` and `===`. + The `==` operator performs the equality test after doing any necessary + type conversions on or to primitive values. + The `===` operator doesn't perform type conversions. + Dart uses the `identical` function to check if two values are the + same object, and the `==` operator to check whether the objects + consider themselves as equal. {{site.alert.end}} -For more information on these JavaScript operators, -check out [this question on Stack Overflow][]. - [Built-in types]: /guides/language/language-tour#built-in-types [Dart Language Tour]: /guides/language -[this question on Stack Overflow]: https://stackoverflow.com/questions/359494/which-equals-operator-vs-should-be-used-in-javascript-comparisons/359509#359509 -For example, the equals operator `==` and the `identical()` -method are guaranteed to return true for the -same values of these types, as shown in the following code: +For example: +The equals operator `==` and the `identical()` method return `true` +for the same values of number types. Review the example shown in the +following code: {:.include-lang} ```dart -var a = 1; -var b = 1; +var a = 2; +var b = 1 + 1; print(a == b); // Prints true -print(identical(a, b)); // Prints true +print(identical(a, b)); // Prints true; only one "2" object exists ``` -The next section covers basic types. -Other types are covered later in this page, -including collection types (lists, maps) -and types that aid asynchrony (futures, streams). +### Primitive Types -### Numbers +This section covers how Dart represents primitive types from JavaScript. +#### Numbers Dart has three data types for holding numbers: @@ -161,90 +150,98 @@ Dart has three data types for holding numbers: : The equivalent to the generic number type in JavaScript. `int` -: Any numeric value without a decimal point. +: A numeric value without a fractional part. `double` -: Any numeric value, including those with a decimal point. +: Any 64-bit (double-precision) floating point number. -All these types are also classes within the Dart API. +The Dart API includes all these types as classes. Both the `int` and `double` types share `num` as their parent class: num subclasses Object and int and double each subclass num -As number values are technically class instances, -they have the convenience of exposing their own -utility functions. Because of this, a `double` can, -for example, be rounded up as follows: +As Dart considers numbers as objects, numbers can expose their +own utility functions as object methods. +You don't need to use an additional object to apply a function to a number. -{:.include-lang} -```dart -var rounded = 2.5.round(); -``` +For example, to round a `double` to an integer: {:.include-lang} ```js let rounded = Math.round(2.5); ``` -### Strings +{:.include-lang} +```dart +var rounded = 2.5.round(); +``` + +#### Strings -Strings in Dart work similarly to strings in JavaScript. -String literals are defined using single quotation marks (`'`), -but can also be defined using double quotation marks -to enable use of single quotation marks within the string -without escaping. However, single quotes are preferred. +Strings in Dart work like strings in JavaScript. +To write a string literal, enclose it in single (`'`) or double (`"`) +quotation marks. +The majority of Dart developers use single quotes, +but the language enforces no standard. +Use double quotation marks if you don't want to escape +single quotes within the string. {:.include-lang} ```dart var a = 'This is a string.'; ``` -#### Escaping special characters +##### Escaping special characters -Escaping special characters in Dart is similar -to JavaScript (and most other languages). -To include special characters escape them -using the backslash character. +To include a character with another meaning in a string, +like a `$` used for string interpolation, you must escape that character. +Escaping special characters in Dart works like JavaScript +and most other languages. +To escape special characters, +precede that character with the backslash character (`\`). -The following code shows some examples. +The following code shows some examples. {:.include-lang} ```dart final singleQuotes = 'I\'m learning Dart'; // I'm learning Dart final doubleQuotes = "Escaping the \" character"; // Escaping the " character +final dollarEscape = 'The price is \$3.14.'; // The price is $3.14. +final backslashEscape = 'The Dart string escape character is \\.'; final unicode = '\u{1F60E}'; // 😎, Unicode scalar U+1F60E ``` -Note that 4-digit hexadecimal values can also be used directly -(for example, `\u2665`), however, curly braces also work. -For more information on working with unicode characters, -check out [Runes and grapheme clusters][]. +{{site.alert.note}} + You can use four-digit hexadecimal characters with or without curly braces. + To learn more about working with unicode characters, + see [Runes and grapheme clusters][]. +{{site.alert.end}} [Runes and grapheme clusters]: /guides/language/language-tour#characters -#### String interpolation +##### String interpolation + +JavaScript supports template literals. +These use backtick (`` ` ``) character delimiters for the following reasons: -JavaScript supports template literals, -which are literals delimited with backtick (`` ` ``) characters, -allowing for multiline strings, -for string interpolation with embedded expressions, -and for special constructs called tagged templates. -Dart supports string concatenation and interpolation -with embedded expressions as part of standard string literals, -meaning that you aren't required to enclose the string in -backticks to enable that functionality. -For more information, -check out [Strings][] in the [Dart Language Tour][]. +* To allow for multiline strings +* To interpolate strings with embedded expressions +* To create special constructs called tagged templates + +In Dart, you don't need to enclose a string in backticks to concatenate +strings or use interpolations within string literals. + +To learn more, see [Strings][] in the [Dart Language Tour][]. [Strings]: /guides/language/language-tour#strings As in JavaScript template literals, -insert expressions into the string literal -using the `${}` syntax. -Dart expands on this by allowing the curly braces -to be omitted when the expression is a single identifier: +you can use the `${}` syntax to insert expressions into +a string literal. +Dart uses this syntax and allows you to omit the curly braces +when the expression uses a single identifier. {:.include-lang} ```dart @@ -257,12 +254,12 @@ var str = 'I eat ${food}'; // I eat bread In JavaScript, you can define multiline strings using template literals. -Dart has two ways to define multiline strings: +Dart has two ways to define multiline strings.
  1. Using implicit string concatenation: - Any neighboring string literals are automatically - concatenated, even when they are spread over multiple lines: + Dart concantenates any neighboring string literals, + even when spread over multiple lines: {:.include-lang} ```dart @@ -274,15 +271,18 @@ final s1 = 'String '
  2. Using a multi line string literal: When using three quotation marks (either single or double) -on either side of the string, -the literal is allowed to span multiple lines: +on either side of the string, the literal can span multiple lines. + {:.include-lang} ```dart -final s2 = '''You can create -multiline strings like this one.'''; +final s2 = ''' +You can create +multiline strings like this one. +'''; -final s3 = """This is also a +final s3 = """ +This is also a multiline string."""; ```
  3. @@ -290,10 +290,9 @@ multiline string."""; #### Equality -As in JavaScript, use the equal-to operator (`==`) -to determine if two strings are equal. -Two strings are equal if they contain the same -sequence of code units. +Dart considers two strings equal when they contain the same sequence +of code units. To determine if two strings have the same sequences, +use the equal-to operator (`==`). {:.include-lang} ```dart @@ -305,165 +304,170 @@ assert(s1 == 'line breaks.'); ``` -### Booleans +#### Booleans -Both Dart and JavaScript booleans represent -a binary value. Each language has two objects -that hold this type: the boolean literals `true` and `false`, -which are compile-time constants in both languages. +Boolean values in both Dart and Javascript express a binary condition. +These two values represent whether a value or expression is +`true` or `false`. +You can return the values using the literals `true` and `false`, +or produced them using expressions like `x < 5` or `y == null`. {:.include-lang} -```dart -var a = true; +```js +let isBananaPeeled = false; ``` + {:.include-lang} -```js -let a = true; +```dart +var isBananaPeeled = false; ``` ## Variables -Variables in Dart are similar to variables in JavaScript, -with the following caveats: +Variables in Dart work like variables in JavaScript, +with two exceptions: -* As Dart is a statically typed language, - when declaring variables the type has to be - inferrable, or you must explicitly define the - type when initializing the variable. +1. Each variable has a type. +1. Dart scopes all variables at the block level, + like `let` and `const` variables in JavaScript. -* All variables in Dart are block scoped, - as you would expect with `let` or `const` in JavaScript. +A Dart variable gets its type in one of two ways: -Declaring and initializing variables in Dart works -almost identically to JavaScript: +1. Declared: A type written in the declaration +1. Inferred: An expression used to initialize the variable + By convention, use `var` or `final` when the analyzer can infer the type. {:.include-lang} -```dart -// Declare a variable -var name; -// Initialize the variable -name = 'bob'; +```js // Declare and initialize a variable at once -var name = 'bob'; +let name = "bob"; ``` {:.include-lang} -```js -// Declare a variable -let name; -// Initialize the variable -name = "bob"; -// Declare and initialize a variable at once -let name = "bob"; +```dart +// Declare a variable with a specific type +// when you don't provide an initial value +String name; +// Declare and initialize a variable +// at the same time and Dart infers +// the type +var name = 'bob'; ``` -Note that you can replace var in Dart with -an explicit type. However, by convention, -var is recommended when the analyzer can -implicitly infer the type. +Variables can only accept values of their type. {:.include-lang} ```dart -String name = 'bob'; // This is the same as 'var', - // since Dart infers the type to be String. +var name = 'bob'; +name = 5; // Forbidden, as `name` has type `String`. ``` -When a variable without an explicit type -is initialized after its declaration, -its type is inferred as the catch-all `dynamic` type. -Likewise, when a type cannot be automatically inferred, -it defaults back to the `dynamic` type. +If you don't provide an initial value or explicit type, +Dart infers the variable's type to be the catch-all type `dynamic`. + +Like JavaScript variables, you can assign any value to Dart variables +that use the `dynamic` type. -Unlike JavaScript, a Dart variable's type can't be changed -after initialization: +{:.include-lang} +```js +// Declare a variable +let name; +// Initialize the variable +name = "bob"; +``` {:.include-lang} ```dart -// Variable initialized later, `name` has type `dynamic`. -var name; +// Declare a variable without a type or assigned value +// and Dart infers the 'dynamic' type +var name; +// Initialize the variable and the type remains `dynamic` name = 'bob'; - name = 5; // Allowed, as `name` has type `dynamic`. - -// Variable initialized immediately, `name` has type `String`. -var name = 'bob'; - -name = 5; // Forbidden, as `name` has type `String`. ``` ### Final and const -The final modifier in Dart acts like the const -modifier in JavaScript: +Both JavaScript and Dart use variable modifiers. Both use `const`, but +differ in how `const` works. Where JavaScript would use `const`, +Dart uses `final`. -
      -
    1. The variable must be initialized - immediately upon declaration. +When you add `final` to a Dart variable or `const` to a JavaScript variable, +you must initialize the variable before other code can read its value. +Once initialized, you can't change these variables' references. -{{site.alert.note}} - One exception to this is with class fields, - which might be initialized in the class constructor. - Learn more in the [Classes](#classes) section. -{{site.alert.end}} -
    2. +When Dart uses `const`, it refers to special values that it creates +when compiling. +Dart uses limited expressions to create these immutable values. +These expressions _cannot_ have side effects. +Under these conditions, the compiler can then predict the precise value +of a constant variable or expression, not just its static type. -
    3. Once the variable has been initialized, - its reference can't be changed later. -
    4. -
    +{:.include-lang} +```dart +final String name; +// Cannot read name here, not initialized. +if (useNickname) { + name = "Bob"; +} else { + name = "Robert"; +} +print(name); // Properly initialized here. +``` -The `const` modifier in Dart acts the same as its -`final` modifier, except that its value must -be known at compile time. Since JavaScript is an -interpreted language requiring no compilation step, -it doesn’t have an equivalent. +{{site.alert.note}} +When you create an object, the class constructor must initialize the +`final` instance variables. +This ensures that these variables have a value before anyone can read them. -Although you can't modify a `const` object in JS, -you can modify its fields. In comparison, -you can't change a Dart `const` object or its fields: -they're _immutable_ (they can't be changed). +Learn more in the [Classes](#classes) section. +{{site.alert.end}} -In Dart, **constant variables must contain constant values**. -However, non-constant variables can still contain -constant values, and values themselves can also be marked `const`. +In Dart, _constant variables must contain constant values_. +Non-constant variables can contain constant values that +you can also mark as `const`. {:.include-lang} ```dart -var foo = const []; // foo is not constant, but the value it points to is. +var foo = const []; + // foo is not constant, but the value it points to is. // You can reassign foo to a different list value, - // but its current list value cannot be altered. + // but its current list value cannot be altered. const baz = []; // Equivalent to `const []` ``` Likewise, classes can have their own `const` constructors -that produce immutable instances. For more information, -check out the [Classes](#classes) section. +that produce immutable instances. + +You can't modify a `const` variable in JavaScript or Dart. +JavaScript does allow you to modify a `const` object's fields, but +Dart does not. + +To learn more, see the [Classes](#classes) section. -## Null safety +## Null safety -Unlike vanilla JavaScript, -Dart supports null safety, making any type non-nullable -by default (as of Dart 2.12). One key benefit of this is -that null reference exceptions are caught when writing code, -so they are unlikely to occur at runtime. +Unlike JavaScript, Dart supports null safety. +In Dart, all types default to non-nullable. +This benefits Dart developers because Dart catches null reference +exceptions when writing code, rather than at runtime. ### Nullable vs non-nullable types -For example, all the variables in the following code -are non-nullable: +None of the variables in the following code example can be `null`. {:.include-lang} ```dart // In null-safe Dart, none of these can ever be null. var i = 42; // Inferred to be an int. String name = getFileName(); -final b = Foo(); +final b = Foo(); // Foo() invokes a constructor ``` To indicate that a variable might have the value `null`, -just add `?` to its type declaration: +add `?` to its type declaration: {:.include-lang} ```dart @@ -486,24 +490,21 @@ String returnsNonNullable() { } ``` -### Null-aware operators +### Null-aware operators Dart supports several operators to deal with nullability. -As in JavaScript, the null assignment operator (`??=`), -null coalescing operator (`??`), -and optional chaining operator (`?.`), -are all available in Dart and operate the same as in JavaScript. +As in JavaScript, Dart supports the null assignment operator (`??=`), +null-coalescing operator (`??`), and optional chaining operator (`?.`). +These operators work the same as JavaScript. #### ! Operator -In cases where it's safe to assume that a -nullable variable or expression is in fact non-null, -it's possible to tell the compiler to repress any -compile time errors. This is done using the (`!`) operator, -by placing it as a suffix to the expression. -(Don't confuse this with Dart's not (`!`) operator, -which uses the same symbol but is always prefixed -to the expression.) +In cases where a nullable variable or expression might be non-null, +you can tell the compiler to repress any compile time errors +using the (`!`) operator. Place this operator after the expression. + +Don't confuse this with Dart's not (`!`) operator, +which uses the same symbol but place before the expression. {:.include-lang} ```dart @@ -541,9 +542,9 @@ whether at the top level, as a class field, or in the local scope. {:.include-lang} -```dart +```js // On the top level -multiply(a, b) { +function multiply(a, b) { return a * b; } @@ -555,19 +556,19 @@ class Multiplier { } // In a local scope -main() { - multiply(a, b) { +function main() { + function multiply(a, b) { return a * b; } - print(multiply(3, 4)); + console.log(multiply(3, 4)); } ``` {:.include-lang} -```js +```dart // On the top level -function multiply(a, b) { +int multiply(a, b) { return a * b; } @@ -579,20 +580,20 @@ class Multiplier { } // In a local scope -function main() { - function multiply(a, b) { +main() { + multiply(a, b) { return a * b; } - console.log(multiply(3, 4)); + print(multiply(3, 4)); } ``` ### Arrow syntax Both Dart and JavaScript support arrow syntax (`=>`), -but they are different. -In Dart, arrow syntax is only used when the function +but differ in how they support it. +In Dart, you can only use the arrow syntax when the function contains a single expression or return statement. For example, the following `isNoble` functions are equivalent: @@ -611,15 +612,13 @@ bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null; ### Parameters -In JavaScript, -all parameters are _optional_ positioned parameters. -In Dart, this is not the case. -By default, all standard parameters are _required_ -positional parameters and must be provided when calling a function. +In JavaScript, all parameters _can_ be positional parameters. +By default, Dart _requires_ you to pass all parameters as arguments +to functions. {:.include-lang} ```dart -multiply(int a, int b) { +int multiply(int a, int b) { return a * b; } @@ -634,17 +633,16 @@ This can change in two situations: 1. The positional parameters are marked as optional. 1. The parameters are named and not marked as required. -Define optional positional parameters by enclosing them -in square brackets following the required positional -parameters, if they exist. You can't define required -parameters after an optional parameter. +To define optional positional parameters, enclose them +in square brackets following any required positional parameters. +You can't follow optional parameters with required parameters. Due to null safety, optional positional parameters must have a default value or be marked as nullable. -Learn more in the preceding section about [null safety](#null-safety). +To learn more, see the preceding section about [null safety](#null-safety). The following code has one valid and two invalid examples -of functions that define optional positional parameters: +of functions that define optional positional parameters. {:.include-lang} ```dart @@ -656,13 +654,14 @@ multiply(int a, [int b = 5, int? c]) { multiply(int a, [int b = 5], int c) { ... } -// Invalid: Neither positional parameter has a default value or has been flagged as nullable. +// Invalid: Neither positional parameter has a default +// value or has been flagged as nullable. multiply(int a, [int b, int c]) { ... } ``` -Here are some examples of calling a function that has optional parameters: +The following example shows how to call a function with optional parameters: {:.include-lang} ```dart @@ -692,20 +691,19 @@ pass values by prefixing the passed value with the name of the parameter, separated by a colon. For example, `f(namedParameter: 5)`. -Again, with null safety, -named parameters that are not flagged as required -either need to have a default value or be flagged as nullable. +Again, with null safety, named parameters that are not flagged as +required either need to have a default value or be flagged as nullable. The following code defines a function with named parameters: {:.include-lang} ```dart -// Valid: +// Valid: // - `a` has been flagged as required -// - `b` has a default value of 5 +// - `b` has a default value of 5 // - `c` is marked as nullable // - Named parameters follow the positional one -multiply(bool x, { required int a, int b = 5, int? c}) { +multiply(bool x, {required int a, int b = 5, int? c}) { ... } ``` @@ -714,7 +712,7 @@ The following examples call a function with named parameters: {:.include-lang} ```dart -// All are valid function calls. +// All are valid function calls. // Beyond providing the required positional parameter: multiply(false, a: 3); // Only provide required named parameters multiply(false, a: 3, b: 9); // Override default value of `b` @@ -723,9 +721,8 @@ multiply(false, c: 9, a: 3, b: 2); // Provide all named parameters out of order ### First-class functions -As in JavaScript, -functions are first-class citizens in Dart, -which means that they're treated as any other object. +JavaScript and Dart treat functions as first-class citizens. +This means that Dart treats functions as any other object. For example, the following code shows how to pass a function as a parameter to another function: @@ -757,81 +754,102 @@ JavaScript has two ways to declare an anonymous function: 1. Use a standard function expression 2. Use arrow syntax -For example: +Likewise, Dart also has two ways to declare anonymous functions. +Both work in a similar manner to the JavaScript arrow expression. +Dart's anonymous functions do not support the extra functionality +that comes with regular function expressions. +For example, JavaScript's support for a function expression acting +like a constructor, or creating a custom binding to this. + +To learn more, see the [Classes](#classes) section. {:.include-lang} ```js -// A regular function expression, assigned to a variable -let funcExpr = function(a, b) { return a * b; } -// The same anonymous function as an arrow function expression, with curly braces. -let arrowFuncExpr = (a, b) => { return a * b; } -// An arrow function with only one return statement as its contents does not require a block. +// A regular function expression +// assigned to a variable +let funcExpr = function(a, b) { + return a * b; +} +// The same anonymous function +// expressed as an arrow +// function with curly braces. +let arrowFuncExpr = (a, b) => { + return a * b; +} +// An arrow function with only +// one return statement as +// its contents does not +// require a block. let arrowFuncExpr2 = (a, b) => a * b; ``` -Likewise, Dart also has two ways to declare -anonymous functions, though both are functionally -similar to the arrow expression in JavaScript. -The extra functionality that comes with regular -function expressions (for example, -JavaScript's support for a function expression acting -like a constructor, or creating a custom binding to this), -aren't supported in Dart's anonymous functions. -(For more information, -check out the [Classes](#classes) section). - {:.include-lang} ```dart -// Assigning an anonymous function to a variable. -var blockFunc = (int a, int b) { - var c = a * b; - return c; -} +// Assign an anonymous function +// to a variable. +var blockFunc = + optionalCallback ?? (int a, int b) { + return a * b; +}; -// In the case of a single returned expression, -// you can shorten the syntax: +// For an expression with only a return statement, +// you can use the arrow syntax: var singleFunc = (int a, int b) => a * b; ``` -As with JavaScript, anonymous functions -can also be passed to other functions. -This is commonly used (in both languages) -when using the `map` function +As with JavaScript, you can pass anonymous functions to other functions. +Developers often pass anonymous functions when using the `map` function for arrays and lists: {:.include-lang} ```js -[1, 2, 3].map(e => e + 3); // [4, 5, 6] -[1, 2, 3].map(e => { +// returns [4, 5, 6] +[1, 2, 3].map(e => e + 3); + +// returns [5, 7, 9] +[1, 2, 3].map(e => { e *= 2; return e + 3; -}); // [5, 7, 9] +}); ``` {:.include-lang} ```dart -[1, 2, 3].map((e) => e + 3).toList(); // [4, 5, 6] -[1, 2, 3].map((e) { +// returns [4, 5, 6] +[1, 2, 3].map((e) => e + 3).toList(); + +// returns [5, 7, 9] +var list2 = [1, 2, 3].map((e) { e *= 2; return e + 3; -}).toList(); // [5, 7, 9] +}).toList(); ``` {{site.alert.note}} - The `map` function in these examples returns + The `map` function in the previous examples returns an `Iterable, rather than a `List`. - Therefore, the `toList` function converts the - returned `Iterable` back to a `List`. + The `toList` function converts the returned + `Iterable` back to a `List`. + + A list literal could achieve the same goal. + + {:.include-lang} + ```dart + // These two statements are equivalent: + print([for (var e in [1, 2, 3]) e + 3]); + print([1, 2, 3].map((e) => e + 3).toList()); + ``` {{site.alert.end}} ### Generator functions -Dart supports [_generator functions_] -that return an iterable collection of items -that are lazily built to improve the UI’s performance. -Convert a function to a generator function by adding -the `sync*` keyword after the function parameters, -and modify it to return an `Iterable`. +Both languages support [_generator functions_]. +These functions return an iterable collection of items +computed to avoid unncessary work. + +To write a generator function in Dart, +add the `sync*` keyword after the function parameters, +and return an `Iterable`. Add items to the final iterable using the `yield` keyword, or add whole sets of items using `yield*`. @@ -840,30 +858,67 @@ Add items to the final iterable using the The following example shows how to write a basic generator function: + +{:.include-lang} +```js +function* naturalsTo(n) { + let k = 0; + while (k < n) { + yield k++; + } +} + +// Returns [0, 1, 2, 3, 4] +for (let value of naturalsTo(5)) { + console.log(value); +} + +``` + + {:.include-lang} ```dart Iterable naturalsTo(int n) sync* { int k = 0; - while (k < n) { + while (k < n) { yield k++; } } -print(naturalsTo(5)); // Returns an iterable with [0, 1, 2, 3, 4]. +// Returns an iterable with [0, 1, 2, 3, 4] +print(naturalsTo(5).toList()); +``` +{:.include-lang} +```js +function* doubleNaturalsTo(n) { + let k = 0; + while (k < n) { + yield* [k, k]; + k++; + } +} + +// Returns [0, 0, 1, 1, 2, 2] +for (let value of doubleNaturalsTo(3)) { + console.log(value); +} +``` + +{:.include-lang} +```dart Iterable doubleNaturalsTo(int n) sync* { int k = 0; - while (k < n) { - yield* [k, k]; + while (k < n) { + yield* [k, k]; k++; } } -print(doubleNaturalsTo(3)); // Returns an iterable with [0, 0, 1, 1, 2, 2]. +// Returns an iterable with [0, 0, 1, 1, 2, 2] +print(doubleNaturalsTo(3)); ``` -This is a synchronous generator function, -and is not available in JavaScript. You can also define asynchronous generator functions, which return streams instead of iterables. Learn more in the upcoming [Asynchrony](#asynchrony) section. @@ -873,33 +928,24 @@ Learn more in the upcoming [Asynchrony](#asynchrony) section. This section describes differences in statements between JavaScript and Dart. -### Control flow (if/else, for, while, switch) +### Control flow (if/else, for, while, switch) -Nearly all control statements work similarly -to their JavaScript counterparts, -although some have additional uses when it comes -to collections -(discussed in more detail in the [Collections](#collections) section). +Most control statements work like their JavaScript counterparts. +Some have additional uses for [Collections](#collections). #### Iteration While both JavaScript and Dart have `for-in` loops, -their behavior is different. +their behaviors differ. -JavaScript's `for-in` loop iterates over an object's properties, -so to iterate over an iterable object's elements, -you must instead `for-of` or `Array.forEach()`. -Dart's `for-in` loop does this natively. +JavaScript's `for-in` loop iterates over an object's properties. +To iterate over a JavaScript iterable object's elements, +you must use `for-of` or `Array.forEach()`. +Dart's `for-in` loop works like JavaScripts `for-of`. The following example shows iterating over a collection and printing out each element: -{:.include-lang} -```dart -for (final element in list) { - print(element) -} -``` {:.include-lang} ```js @@ -908,13 +954,20 @@ for (const element of list) { } ``` +{:.include-lang} +```dart +for (final element in list) { + print(element) +} +``` + #### Switch {{site.alert.note}} One key difference with the `switch` statement in JavaScript and Dart: when a case has no `break`, `continue`, or `return` statement, - JS allows execution to fall through and continue + JavaScript allows execution to fall through and continue with the next statement. However, Dart only allows this when a case's body is empty. {{site.alert.end}} @@ -938,30 +991,27 @@ switch (testEnum) { ### Operators Both Dart and JavaScript contain predefined operators. -Adding new operators is not supported in either language, -but Dart allows you to overload existing operators +Neither language supports adding new operators. +Dart supports overloading some existing operators with the `operator` keyword. For example: {:.include-lang} ```dart -class Box { - Box({ - required this.length, - required this.width, - required this.height, - }); - - final double length; - final double width; - final double height; - - Box operator +(Box x) { - return Box( - length: length + x.length, - width: width + x.width, - height: height + x.height, - ); - } +class Vector { + final double x; + final double y; + final double z; + Vector(this.x, this.y, this.z); + Vector operator +(Vector other) => Vector( + x + other.x, + y + other.y, + z + other.z, + ); + Vector operator *(double scalar) => Vector( + x * scalar, + y * scalar, + z * scalar, + ); } ``` @@ -970,22 +1020,21 @@ class Box { The equality and relational operators of both languages are almost identical, as shown in the following table: -| Meaning | Dart operator | JS equivalent | -|---------------------------------------------------|-----------------|---------------| -| Add | `+` | `+` | -| Subtract | `-` | `-` | -| Unary minus, also known as negation | `-expr` | `-expr` | -| Multiply | `*` | `*` | -| Divide | `/` | `/` | -| Divide returning an integer result | `~/` | | -| Get the remainder of an integer division (modulo) | `%` | `%` | -| `var = var + 1` (expression value is `var + 1`) | `++var` | `++var` | -| `var = var + 1` (expression value is `var`) | `var++` | `var++` | -| `var = var - 1` (expression value is `var - 1`) | `--var` | `--var` | -| `var = var - 1` (expression value is `var`) | `var--` | `var--` | +| Meaning | JavaScript operator | Dart operator | +|---------------------------------------------------|---------------------|---------------| +| Add | `+` | `+` | +| Subtract | `-` | `-` | +| Unary minus, also known as negation | `-expr` | `-expr` | +| Multiply | `*` | `*` | +| Divide | `/` | `/` | +| Divide returning an integer result | | `~/` | +| Get the remainder of an integer division (modulo) | `%` | `%` | +| `x = x + 1` (expression value is `x + 1`) | `++x` | `++x` | +| `x = x + 1` (expression value is `x`) | `x++` | `x++` | +| `x = x - 1` (expression value is `x - 1`) | `--x` | `--x` | +| `x = x - 1` (expression value is `x`) | `x--` | `x--` | {:.table .table-striped} - For example: {:.include-lang} @@ -1015,7 +1064,7 @@ assert(a != b); // -1 != 0 ``` You've probably noticed that Dart also contains -a `~/ `operator (called a _truncating division operator_), +a `~/` operator (called a _truncating division operator_), that divides a double and outputs a floored integer: {:.include-lang} @@ -1030,21 +1079,19 @@ assert(25 == 51.6 ~/ 2); The equality and relational operators of both languages work in the same way: -| Meaning | Dart operator | JS equivalent | -|-------------------------------|---------------|---------------| -| Strict equal | `==` | `===` | -| Abstract equal | | `==` | -| Strict not equal | `!=` | `!==` | -| Abstract not equal | | `!=` | -| Greater than | `>` | `>` | -| Less than | `<` | `<` | -| Greater than or equal to | `>=` | `>=` | -| Less than or equal to | `<=` | `<=` | +| Meaning | JavaScript operator | Dart operator | +|---------------------------|---------------------|---------------| +| Strict equal | `===` | `==` | +| Abstract equal | `==` | | +| Strict not equal | `!==` | `!=` | +| Abstract not equal | `!=` | | +| Greater than | `>` | `>` | +| Less than | `<` | `<` | +| Greater than or equal to | `>=` | `>=` | +| Less than or equal to | `<=` | `<=` | {:.table .table-striped} -Unlike JavaScript, -Dart doesn’t have the concept of abstract equality, -so the `==` and `!=` JavaScript operators have no equivalent. +The `==` and `!=` JavaScript operators have no equivalent. For example: @@ -1061,25 +1108,22 @@ assert(2 <= 3); #### Type test operators The implementation of test operators is a bit -different between the two languages: +different between the two languages: -| Meaning | Dart operator | JS equivalent | -|----------------------------------------------------|---------------|--------------------| -| Typecast (described below) | `var as T` | | -| True if the object has the specified type | `var is T` | `typeof var === T` | -| True if the object doesn’t have the specified type | `var is! T` | `typeof var !== T` | +| Meaning | JavaScript operator | Dart operator | +|-------------------------------------|---------------------|---------------| +| Typecast | | `x as T` | +| True if object has specified type | `x instanceof T` | `x is T` | +| True if object lacks specified type | `!(x instanceof T)` | `x is! T` | {:.table .table-striped} The result of `obj is T` is true if `obj` implements the interface specified by `T`. For example, `obj is Object?` is always true. -Since JavaScript makes use of type coercion, -it doesn't have an equivalent. - -Use the typecast operator to cast an object -to a particular type if—and only if—you -are sure that the object is of that type. +Use the typecast operator (`as`) to ensure that a value +has a particular type. The compiler can use that, +if you _know_ that the object will have that type. For example: @@ -1088,12 +1132,12 @@ For example: (person as Employee).employeeNumber = 4204583; ``` -If you aren't sure that the object is of type `T`, -then use `is T` to check the type before using the object. +If you don't _know_ that the object is of type `T`, +then use `is T` to check the type _before_ using the object. In Dart, the types of local variables update within the scope of the if statement. -This is not the case for instance variables. +This is not the case for instance variables. {:.include-lang} ```dart @@ -1108,22 +1152,22 @@ You can invert or combine boolean expressions using logical operators. The logical operators of both languages are identical. -|--------------------------------------------------------------------------+---------------+---------------| -| Meaning | Dart operator | JS equivalent | -|--------------------------------------------------------------------------|---------------|---------------| -| Inverts the following expression (changes false to true, and vice versa) | `!var` | `!var` | -| Logical OR | `||` | `||` | -| Logical AND | `&&` | `&&` | +|----------------------------------------------------------------+---------------------|---------------+ +| Meaning | JavaScript operator | Dart operator | +|----------------------------------------------------------------|---------------------|---------------| +| Inverts next expression (changes false to true and vice versa) | `!x` | `!x` | +| Logical OR | `||` | `||` | +| Logical AND | `&&` | `&&` | {:.table .table-striped} -Dart does not have the concept of "truthy" or "falsy" -values—only actual booleans. Because of this, -Logical OR and Logical AND expressions always resolve -to a boolean, not one of the two values like these -operators do in JavaScript. +JavaScript allows any value to be used where you need a Boolean value. +It then converts those values to either `true` or `false`. +JavaScript considers empty strings and the number `0` to be "falsy" values. +Dart allows `bool` values in conditions and as operands of logical operators. For example: +{:.include-lang} ```dart if (!done && (col == 0 || col == 3)) { // ...Do something... @@ -1137,19 +1181,19 @@ by using bitwise and shift operators with integers. The operators of both languages are almost identical, as shown in the following table: -|-------------------------------------------------------+---------------+---------------| -| Meaning | Dart operator | JS equivalent | -|-------------------------------------------------------|---------------|---------------| -| Bitwise AND | `&` | `&` | -| Bitwise OR | `|` | `|` | -| Bitwise XOR | `^` | `^` | -| Unary bitwise complement (0s become 1s; 1s become 0s) | `~expr` | `~expr` | -| Shift left | `<<` | `<<` | -| Shift right | `>>` | `>>` | -| Unsigned shift right | `>>>` | `>>>` | +|-------------------------------------------------------+---------------------+---------------| +| Meaning | JavaScript operator | Dart operator | +|-------------------------------------------------------|---------------------|---------------| +| Bitwise AND | `&` | `&` | +| Bitwise OR | `|` | `|` | +| Bitwise XOR | `^` | `^` | +| Unary bitwise complement (0s become 1s; 1s become 0s) | `~expr` | `~expr` | +| Shift left | `<<` | `<<` | +| Shift right | `>>` | `>>` | +| Unsigned shift right | `>>>` | `>>>` | {:.table .table-striped} -For example: +For example: {:.include-lang} ```dart @@ -1167,69 +1211,90 @@ assert((value >>> 4) == 0x02); // Unsigned shift right assert((-value >>> 4) > 0); // Unsigned shift right ``` -#### Ternary operator +#### Conditional operator -Both Dart and JavaScript contain a (`?:`) -ternary operator for evaluating expressions -that might otherwise require [if-else][] statements: +Both Dart and JavaScript contain a conditional operator (`?:`) +for evaluating expressions. +Some developers refer to this as a ternary operator +because it takes three operands. +As Dart has another operator (`[]=`) that takes three operands, +call this operator (`?:`) the conditional operator. +This operator works for expressions like [if-else][] does for statements. {:.include-lang} -```dart -final visibility = isPublic ? 'public' : 'private'; +```js +let visibility = isPublic ? "public" : "private"; ``` {:.include-lang} -```js -let visibility = isPublic ? "public" : "private"; +```dart +final visibility = isPublic ? 'public' : 'private'; ``` [if-else]: /guides/language/language-tour#if-and-else ### Assignment operators -As mentioned previously, -you can assign values using the (`=`) operator: +Use the (`=`) operator to assign values. +{:.include-lang} ```dart // Assign value to a a = value; ``` -This operator also has a null-aware variant. -For more information, -check out the [null-assignment](#null-aware-operators) operator section. +This operator also has a null-aware variant (`??=`). + +To learn more, +see the [null-assignment](#null-aware-operators) operator section. + +JavaScript and Dart include operators that calculate and assign +new values to the variable in the expression. +These assignment operators use the right-side value and +the variable initial value as operands. -Here are other assignment operators that directly -assign the result of an operation on a variable -back to that same variable: +The following table lists these assignment operators: -| `=` | `*=` | `%=` | `>>>=` | `^=` | -| `+=` | `/=` | `<<=` | `&=` | `|=` | -| `-=` | `~/=` | `>>=` | | | -{:.table} +| Operator | Description | ++----------+---------------------------------+ +| `=` | Assignment | +| `+=` | Addition assignment | +| `-=` | Subtraction assignment | +| `*=` | Multiplication assignment | +| `/=` | Division assignment | +| `~/=` | Truncating division assignment | +| `%=` | Remainder (modulo) assignment | +| `>>>=` | Unsigned right shift assignment | +| `^=` | Bitwise XOR assignment | +| `<<=` | Left shift assignment | +| `>>=` | Right shift assignment | +| `&=` | Bitwise AND assignment | +| `|=` | Bitwise OR assignment | +{:.table} + +JavaScript does not support the `~/=` assignment operator. {:.include-lang} ```dart var a = 5; -a *= 2; // Multiply `a` by 2 and assign the value back to a. +a *= 2; // Multiply `a` by 2 and assign the result back to a. print(a); // `a` is now 10. ``` -### Cascades (`..` operator) +### Cascades (`..` operator) + +Dart allows you to chain multiple method calls, property assignments, +or both on a single object. Dart refers to this as _cascading_ and +uses the cascade syntax (`..`) to perform this action. -Unlike JavaScript, -Dart supports cascading with the cascades operator. -This allows you to chain multiple method calls -or property assignments on a single object. +JavaScript lacks this syntax. -The following example shows setting the value -of multiple properties, then calling multiple methods -on a newly constructed object, all within a single chain -using the cascade operator: +The following example shows chaining multiple methods +on a newly constructed object using the cascade syntax: {:.include-lang} ```dart -var animal = Animal() +var animal = Animal() // Sets multiple properties and methods ..name = "Bob" ..age = 5 ..feed() @@ -1239,17 +1304,26 @@ print(animal.name); // "Bob" print(animal.age); // 5 ``` +To make the first cascade syntax null-aware, write it as `?..`. + +{:.include-lang} +```dart +var result = maybePerson + ?..employment = employer + ..salary = salary; +``` + +Dart ignores the entire cascade if the `maybePerson` value is `null`. + ## Collections -This section covers some collection types -in Dart and how they compare to their equivalents -in JavaScript. +This section covers some collection types in Dart and compare them +to similar types in JavaScript. ### Lists -List literals are defined the same way in Dart as -arrays are defined in JavaScript, -using square brackets and separated by commas: +Dart writes list literals in the same ways as JavaScript arrays. +Dart encloses lists in square brackets and separate values with commas. {:.include-lang} ```dart @@ -1263,10 +1337,10 @@ final list2 = ['one', 'two', 'three']; final list3 = ['one', 'two', 'three']; ``` -The following code samples give an overview of the -basic actions that you can perform on a Dart `List`. -The first example shows how to retrieve a value -from a `List` using the index operator: +The following code samples give an overview of the basic actions that +you can perform on a Dart `List`. +The following example shows how to retrieve a value from a `List` +using the index operator. {:.include-lang} ```dart @@ -1317,9 +1391,9 @@ fruits.removeLast(); fruits.removeAt(1); // Removes the elements with positions greater than // or equal to start (1) and less than end (3) from the list. -fruits.removeRange(1, 3); +fruits.removeRange(1, 3); // Removes all elements from the list that match the given predicate. -fruits.removeWhere((fruit) => fruit.contains('p')); +fruits.removeWhere((fruit) => fruit.contains('p')); ``` Use `length` to obtain the number of values in the `List`: @@ -1348,24 +1422,28 @@ assert(fruits.isNotEmpty); #### Filled -One handy feature of Dart's `List` class is the -`filled` constructor; use `filled` to quickly -create a list of size `n` with the specified default value. +Dart's `List` class includes a way to create a List with +each item having the same value. +This `filled` constructor creates a fixed-length list of size `n` with +one default value. The following example create a list of 3 items: {:.include-lang} ```dart -// Creates: [ 'a', 'a', 'a' ] -final list1 = List.filled(3, 'a'); +final list1 = List.filled(3, 'a'); // Creates: [ 'a', 'a', 'a' ] ``` +* You cannot add or remove elements from this list by default. + To permit this list to add or remove elements, add `, growable: true` + to the end of the parameter list. +* You can access and update elements of this list using their index value. + #### Generate -The `List` class also provides a `generate` -constructor to quickly create a list of -size `n` with a default value builder -that creates elements. -The value builder takes the index as a parameter. +The Dart `List` class includes a way to create a List of incrementing values. +This `generate` constructor creates a fixed-length list of size `n` +with a template to build element values. +This template takes the index as a parameter. {:.include-lang} ```dart @@ -1375,25 +1453,22 @@ final list1 = List.generate(3, (index) => 'a$index'); ### Sets -Unlike JavaScript, -Dart supports defining `Set`s with literals. -Sets are defined in the same way as lists, -but using curly braces instead of square brackets. -Sets are unordered collections that only contain -unique items. The uniqueness of these items are -enforced using hash codes, meaning that objects -need hash values to be stored in a `Set`. +Unlike JavaScript, Dart supports defining `Set`s with literals. +Dart defines sets in the same way as lists, +but using curly braces rather than square brackets. +Sets are unordered collections that only contain unique items. +Dart enforces the uniqueness of these items using hash codes, +meaning that objects need hash values to be stored in a `Set`. {{site.alert.note}} - In Dart, the hash value defaults to the - instance of an object but you can override - it to use a set of properties. For more information, - check out the [`hashCode`][] property page. + In Dart, the hash value defaults to the instance of an object + but you can override it to use a set of properties. + To learn more, see the [`hashCode`][] property page. {{site.alert.end}} [`hashCode`]: {{site.dart-api}}/dart-core/Object/hashCode.html -The following code snippet shows how to initialize a `Set`: +The following code snippet shows how to initialize a `Set`: {:.include-lang} ```dart @@ -1416,7 +1491,7 @@ final names = {}; The following examples provide an overview of the basic actions that you can perform on a Dart `Set`. -Add a value to the `Set` using the `add` method. +Add a value to the `Set` using the `add` method. Use the `addAll` method to add multiple values: {:.include-lang} @@ -1466,46 +1541,44 @@ assert(fruits.isNotEmpty); ### Maps -The `Map` type in Dart is similar to the `Map` type -in JavaScript. Both types associate keys with values. -A key can be any object type, so long as all keys have -the same type; the same is true for values. -Each key occurs once at most, but you can use the -same value multiple times. +The `Map` type in Dart resembles the `Map` type in JavaScript. +Both types associate keys with values. +A key can be any object type if all keys have the same type. +This rule applies to values as well. +Each key occurs once at most, but you can use the same value multiple times. -In Dart, the dictionary is based on a hash table, -which means that keys need to be hashable. In Dart, -every object contains a unique hash. +Dart bases the dictionary on a hash table. +This means that keys need to be hashable. +Every Dart object contains a hash. {{site.alert.note}} - In Dart, the hash value defaults to an instance - of an object but you can override it to resemble - a data class. For more information, - check out the [`hashCode`][] property page. +In Dart, the hash value of an object defaults to a value derived from +the object's identity, and being compatible with an equality where the +object can only equal itself. To introduce an equality based on the +_contents_ of the object, override `hashCode` and `operator==`. {{site.alert.end}} -Here are a couple of simple `Map` examples, -created using literals: +Consider these simple `Map` examples, created using literals: {:.include-lang} ```dart final gifts = { - 'first': 'partridge', - 'second': 'turtle doves', - 'fifth': 'golden rings' + 'first': 'partridge', + 'second': 'turtle doves', + 'fifth': 'golden rings' }; final nobleGases = { - 2: 'helium', - 10: 'neon', - 18: 'argon', + 2: 'helium', + 10: 'neon', + 18: 'argon', }; ``` -The following code samples provide an overview of the -basic actions that you can perform on a Dart `Map`. -The first example shows how to retrieve a value from -a `Map` using the index operator: +The following code samples provide an overview of the basic actions that +you can perform on a Dart `Map`. +The following example shows how to retrieve a value from a `Map` using +the index operator. {:.include-lang} ```dart @@ -1514,11 +1587,10 @@ final gift = gifts['first']; ``` {{site.alert.note}} - The index operator (`[]`) returns a **nullable** value. +If the map does not include the lookup key, the index operator returns `null`. {{site.alert.end}} -Use the `containsKey` method to check if a key -is already present in the `Map`: +Use the `containsKey` method to check if the `Map` includes a key. {:.include-lang} ```dart @@ -1526,11 +1598,10 @@ final gifts = {'first': 'partridge'}; assert(gifts.containsKey('fifth')); ``` -Use the index assignment operator (`[]=`) -to add or update an entry in the `Map`. -If the `Map` doesn't yet contain the key, -the entry is added; if the key is already present, -its value is updated. +Use the index assignment operator (`[]=`) to add or update an entry +in the `Map`. +If the `Map` doesn't yet contain the key, Dart adds the entry. +If the key exists, Dart updates its value. {:.include-lang} ```dart @@ -1539,26 +1610,25 @@ gifts['second'] = 'turtle'; // Gets added gifts['second'] = 'turtle doves'; // Gets updated ``` -Use the `addAll` method to add another `Map`; -use the `addEntries` method to add other entries to the `Map`: +Use the `addAll` method to add another `Map`. +Use the `addEntries` method to add other entries to the `Map`. {:.include-lang} ```dart final gifts = {'first': 'partridge'}; gifts['second'] = 'turtle doves'; gifts.addAll({ - 'second': 'turtle doves', - 'fifth': 'golden rings', + 'second': 'turtle doves', + 'fifth': 'golden rings', }); gifts.addEntries([ - MapEntry('second', 'turtle doves'), - MapEntry('fifth', 'golden rings'), + MapEntry('second', 'turtle doves'), + MapEntry('fifth', 'golden rings'), ]); ``` -Use the `remove` method to remove an entry from the `Map`; -remove all entries that satisfy a given test using the -`removeWhere` method: +Use the `remove` method to remove an entry from the `Map`. +Use the `removeWhere` method to remove all entries that satisfy a given test. {:.include-lang} ```dart @@ -1567,8 +1637,7 @@ gifts.remove('first'); gifts.removeWhere((key, value) => value == 'partridge'); ``` -Use `length` to obtain the number of key-value -pairs in the `Map`: +Use `length` to obtain the number of key-value pairs in the `Map`. {:.include-lang} ```dart @@ -1577,7 +1646,7 @@ gifts['fourth'] = 'calling birds'; assert(gifts.length == 2); ``` -Use `isEmpty` to check if the `Map` is empty: +Use `isEmpty` to check if the `Map` is empty. {:.include-lang} ```dart @@ -1585,7 +1654,7 @@ final gifts = {}; assert(gifts.isEmpty); ``` -Use `isNotEmpty` to check if the `Map` is not empty: +Use `isNotEmpty` to check if the `Map` is not empty. {:.include-lang} ```dart @@ -1595,9 +1664,9 @@ assert(gifts.isNotEmpty); ### Unmodifiable -Vanilla JavaScript doesn't support immutability. -Dart, however, offers multiple ways to make -collections like arrays, sets, or dictionaries immutable: +Pure JavaScript doesn't support immutability. +Dart offers multiple ways to make collections like arrays, sets, or +dictionaries immutable. * If the list is a compile-time constant and shouldn't be modified, use the `const` keyword:
    @@ -1611,7 +1680,7 @@ collections like arrays, sets, or dictionaries immutable: * Create a final version of your collection type using the `unmodifiable` constructor (as shown in the following example). - This creates a collection that cannot change its size or content: + This creates a collection that cannot change its size or content: {:.include-lang} ```dart @@ -1650,7 +1719,7 @@ var set2 = {'foo', 'baz', ...set1}; // {foo, baz, bar} ### Collection if/for In Dart, the `for` and `if` keywords have additional -functionality when it comes to collections. +functionality when it comes to collections. A collection `if` statement includes items from a list literal only when the specified condition is met: @@ -1694,31 +1763,35 @@ to their JavaScript counterparts. ### Futures -`Future` is Dart's version of a `Promise`: -an asynchronous operation that resolves at a later point. +`Future` is Dart's version of a JavaScript `Promise`. +Both are the _result_ of an asynchronous operation that resolves at a +later point. -Functions in Dart (or in packages that you use) might -return a `Future`, rather than the value they represent -directly, as the value might not be available until later. +Functions in Dart or in Dart packages might return a `Future`, +rather than the value they represent, as the value might not be +available until later. The following example shows that handling a future works -in the same way in Dart as a promise works in JavaScript: +in the same way in Dart as a promise works in JavaScript. {:.include-lang} -```dart -Future httpResponseBody = func(); +```js +const httpResponseBody = func(); -httpResponseBody.then((String value) { - print('Future resolved to a value: $value'); +httpResponseBody.then(value => { + console.log( + `Promise resolved to a value: ${value}` + ); }); ``` + {:.include-lang} -```js -const httpResponseBody = func(); +```dart +Future httpResponseBody = func(); -httpResponseBody.then(value => { - console.log(`Promise resolved to a value: ${value}`); +httpResponseBody.then((String value) { + print('Future resolved to a value: $value'); }); ``` @@ -1726,29 +1799,31 @@ Similarly, futures can fail like promises. Catching errors works the same as well: {:.include-lang} -```dart +```js httpResponseBody .then(...) - .catchError((err) { - print('Future encountered an error before resolving.'); + .catch(err => { + console.log( + "Promise encountered an error before resolving." + ); }); ``` {:.include-lang} -```js +```dart httpResponseBody .then(...) - .catch(err => { - console.log("Promise encountered an error before resolving."); + .catchError((err) { + print( + 'Future encountered an error before resolving.' + ); }); ``` -You can also create futures manually. -The easiest way to create a `Future` is by -defining and calling an `async` function, -which is discussed below. However, -when you have a value that needs to be a `Future`, -you can convert it as follows: +You can also create futures. +To create a `Future`, define and call an `async` function. +When you have a value that needs to be a `Future`, +convert the function as in the following example. {:.include-lang} ```dart @@ -1756,7 +1831,7 @@ String str = 'String Value'; Future strFuture = Future.value(str); ``` -#### Async/await +#### Async/Await If you're familiar with promises in JavaScript, you’re likely also familiar with the `async`/`await` syntax. @@ -1769,24 +1844,32 @@ it returns `Future`. The following example shows how to write an `async` function: -{:.include-lang} -```dart -// Returns a future of a string, as the method is async -Future fetchString() async { - // Typically some other async operations would be done here. - return 'String Value'; -} -``` {:.include-lang} ```js -// Returns a Promise of a string, as the method is async +// Returns a Promise of a string, +// as the method is async async fetchString() { - // Typically some other async operations would be done here. + // Typically some other async + // operations would be done here. return "String Value"; } ``` + +{:.include-lang} +```dart +// Returns a future of a string, +// as the method is async +Future fetchString() async { + // Typically some other async + // operations would be done here. + return 'String Value'; +} +``` + + + Call this `async` function as follows: {:.include-lang} @@ -1810,14 +1893,14 @@ The following example shows how to await a future for its value: {:.include-lang} ```dart // We can only await futures within an async context. -asyncFunction() async { +Future asyncFunction() async { var str = await fetchString(); print(str); // 'String Value' } ``` -For more information about `Future`s and the -`async`/`await` syntax, check out the +To learn more about `Future`s and the +`async`/`await` syntax, see the [Asynchronous programming][] codelab. [Asynchronous programming]: /codelabs/async-await @@ -1829,7 +1912,7 @@ While JavaScript has its own concept of streams, Dart's are more akin to `Observable`s, as found in the commonly used `rxjs` library. If you happen to be familiar with this library, -Dart's streams should feel familiar. +Dart's streams should feel familiar. For those not familiar with these concepts: `Stream`s basically act like `Future`s, @@ -1840,8 +1923,8 @@ and it can either complete or reach a fail state. #### Listening To listen to a stream, call its `listen` method -and provide a callback method. This method is -called whenever the stream emits a value: +and provide a callback method. Whenever the stream emits a value, +Dart calls this method: {:.include-lang} ```dart @@ -1851,7 +1934,7 @@ stream.listen((int value) { }); ``` -The `listen` method also has some optional callbacks +The `listen` method includes optional callbacks for handling errors or for when the stream completes: {:.include-lang} @@ -1897,8 +1980,8 @@ Future sumStream(Stream stream) async { When an error occurs when listening to a stream in this way, the error is rethrown at the line -containing the `await` keyword, -which you can handle with a `try-catch` statement: +containing the `await` keyword. +You can handle this error with a `try-catch` statement: {:.include-lang} ```dart @@ -1916,20 +1999,19 @@ you have several different ways to create a stream. The `Stream` class has utility constructors for creating streams from `Future`s or `Iterable`s, or for creating streams that emit values at a timed interval. -For more information, check out the [`Stream`][] API page. +To learn more, see the [`Stream`][] API page. [`Stream`]: {{site.dart-api}}/dart-async/Stream-class.html ##### StreamController -Another common way to create streams is -by using a [`StreamController`][], -a utility class that builds streams. -A `StreamController` contains a `stream` property -that exposes the stream it controls, -and multiple methods for controlling the stream, -such as emitting new items using the `add` method, -or completing the stream using the `close` method. +The utility class [`StreamController`][] can create and control streams. +Its stream property exposes the stream it controls. +Its methods provides ways to add events to that stream. + +For example, the `add` method can emit new items and the `close` method +completes the stream. + The following example shows basic usage of a stream controller: {:.include-lang} @@ -1956,11 +2038,9 @@ stream.listen((int value) { ##### Async generators -Another way to create streams is by using async generator -functions—these have the same syntax as a -synchronous generator function, but use the `async*` -keyword instead of `sync*`, -and always return a `Stream` instead of an `Iterable`. +Async generator functions can create streams. +These functions resemble a synchronous generator function +but use the `async*` keyword and return a `Stream`. In an async generator function, the `yield` keyword emits the given value to the stream. The `yield*` keyword, @@ -1976,10 +2056,10 @@ Stream asynchronousNaturalsTo(int n) async* { while (k < n) yield k++; } -Stream stream = asynchronousNaturalsTo(5); +Stream stream = asynchronousNaturalsTo(5); // Prints each of 0 1 2 3 4 in succession. -stream.listen((int value) => print(value)); +stream.forEach(print(value)); ``` Learn more about futures, streams, @@ -1988,14 +2068,14 @@ and other asynchronous functionality in the [asynchronous programming]: /tutorials/language/streams -## Classes +## Classes On the surface, classes in Dart are similar to classes in JavaScript, although JavaScript classes are technically more of a wrapper around prototypes. In Dart, classes are a standard feature of the language. This section covers defining and using classes in Dart -and how they differ from JavaScript. +and how they differ from JavaScript. ### “this” context @@ -2018,25 +2098,40 @@ a JavaScript constructor. In Dart, the `constructor` keyword is replaced by the full class name, and all parameters must be explicitly typed. In Dart, the `new` keyword was once required for creating class instances, -but is now optional and its use is no longer recommended. +but is now optional and its use is no longer recommended. {:.include-lang} ```dart class Point { - double x = 0; - double y = 0; + final double x; + final double y; - Point(double x, double y) { - // There's a better way to do this in Dart, stay tuned. - this.x = x; - this.y = y; - } + Point(double x, double y) : this.x = x, this.y = y { } } // Create a new instance of the Point class Point p = Point(3, 5); ``` +#### Initializer lists + +Use initializer lists to write your constructor. +Insert the initializer list between the constructor's parameters +and body. + +{:.include-lang} +```dart +class Point { + ... + Point.fromJson(Map json) + : x = json['x']!, + y = json['y']! { + print('In Point.fromJson(): ($x, $y)'); + } + ... +} +``` + #### Constructor parameters Writing code to assign class fields in the constructor @@ -2047,8 +2142,8 @@ so Dart has some syntactic sugar, called {:.include-lang} ```dart class Point { - double x = 0; - double y = 0; + double x; + double y; // Syntactic sugar for setting x and y // before the constructor body runs. @@ -2080,26 +2175,6 @@ class Point { } ``` -#### Initializer lists - -You can also use initializer lists, -which run after any fields that aren't set -using initializing parameters, -but run before the constructor body: - -{:.include-lang} -```dart -class Point { - ... - Point.fromJson(Map json) - : x = json['x']!, - y = json['y']! { - print('In Point.fromJson(): ($x, $y)'); - } - ... -} -``` - #### Named constructors Unlike JavaScript, Dart allows classes to have @@ -2127,10 +2202,8 @@ class Point { #### Const constructors -When your class instances are always immutable, -you can enforce this by using a `const` constructor. -Defining your constructor as `const` requires all -non-static fields in your class to be flagged as `final`: +To enable immutable class instances, use a `const` constructor. +A class with a `const` constructor can have `final` instance variables only. {:.include-lang} ```dart @@ -2143,9 +2216,8 @@ class ImmutablePoint { #### Constructor redirection -You can call constructors from other constructors, -for example to prevent code duplication or -to add additional defaults for parameters: +You can call constructors from other constructors to prevent code +duplication or to add additional defaults for parameters: {:.include-lang} ```dart @@ -2164,21 +2236,21 @@ class Point { You can use a factory constructor when you don't need to create a new class instance. -One example would be when returning a cached instance: +One example would be when returning a cached instance: {:.include-lang} ```dart class Logger { static final Map _cache = {}; - + final String name; - + // Factory constructor that returns a cached copy, // or creates a new one if it is not yet available. factory Logger(String name) { return _cache.putIfAbsent( - name, () => Logger._internal(name)); + name, () => _cache[name] ??= Logger._internal(name); } // Private constructor for internal use only @@ -2188,8 +2260,22 @@ class Logger { ### Methods -In both Dart and JavaScript, methods are -functions that provide behavior for an object. +In both Dart and JavaScript, methods serve as functions that provide +behavior for an object. + +{:.include-lang} +```js +function doSomething() { // This is a function + // Implementation.. +} + +class Example { + doSomething() { // This is a method + // Implementation.. + } +} +``` + {:.include-lang} ```dart @@ -2204,37 +2290,26 @@ class Example { } ``` -{:.include-lang} -```js -doSomething() { // This is a function - // Implementation.. -} -class Example { - doSomething() { // This is a method - // Implementation.. - } -} -``` ### Extending classes Dart allows classes to extend another class, -in the same way that JavaScript does. +in the same way that JavaScript does. {:.include-lang} ```dart class Animal { int eyes; - + Animal(this.eyes); - + makeNoise() { print('???'); } } class Cat extends Animal { - + Cat(): super(2); @override @@ -2252,7 +2327,7 @@ use the `@override` annotation. While this annotation is optional, it shows that the override is intentional. The Dart analyzer shows a warning if the method -is not actually overriding a superclass method. +is not actually overriding a superclass method. The parent method that is being overridden can still be called using the `super` keyword: @@ -2315,7 +2390,8 @@ class Cat implements Consumer { @override consume() { print('Eating mice...'); - super.consume(); // Invalid, because there’s no superclass. + super.consume(); + // Invalid. The superclass `Object` has no `consume` method. } } ``` @@ -2356,27 +2432,68 @@ consumer = Cat(); consumer.consume(); // Eating mice... ``` -### Mixins +### Mixins Mixins are used to share functionality between classes. You can use the mixin's fields and methods in the class, using their functionality as if it were part of the class. -A class can use multiple mixins, which is useful -when multiple classes share the same functionality, +A class can use multiple mixins. This helps when multiple classes share the +same functionality, without needing to inherit from each other or share a common ancestor. -A mixin is declared like a regular class, -as long as it doesn't extend any class other -than `Object` and has no constructors. -Use the `with` keyword to add one or more -comma-separated mixins to a class. -Although JavaScript doesn’t have an equivalent -for this keyword, the effect is similar to using -`Object.assign` to merge additional objects into -an existing object, after instantiating. +Use the `with` keyword to add one or more comma-separated mixins to a class. + +JavaScript has no keyword equivalent. JavaScript can use `Object.assign` +to merge additional objects into an existing object, after instantiating. + +The following examples show how JavaScript and Dart achieve similar behavior: + + +{:.include-lang} +```js +class Animal {} + +// Defining the mixins +class Flyer { + fly = () => console.log('Flaps wings'); +} +class Walker { + walk = () => console.log('Walks on legs'); +} + +class Bat extends Animal {} +class Goose extends Animal {} +class Dog extends Animal {} + +// Composing the class instances with +// their correct functionality. +const bat = + Object.assign( + new Bat(), + new Flyer() + ); +const goose = + Object.assign( + new Goose(), + new Flyer(), + new Walker() + ); +const dog = + Object.assign( + new Dog(), + new Walker() + ); + +// Correct calls +bat.fly(); +goose.fly(); +goose.walk(); +dog.walk(); +// Incorrect calls +bat.walk(); // `bat` lacks the `walk` method +dog.fly(); // `dog` lacks the `fly` method +``` -The following example shows how similar behavior -is replicated in JavaScript and how it's achieved in Dart: {:.include-lang} ```dart @@ -2387,9 +2504,9 @@ class Flyer { fly() => print('Flaps wings'); } class Walker { - walk() => print('Walks legs'); + walk() => print('Walks on legs'); } - + class Bat extends Animal with Flyer {} class Goose extends Animal with Flyer, Walker {} class Dog extends Animal with Walker {} @@ -2397,43 +2514,14 @@ class Dog extends Animal with Walker {} // Correct calls Bat().fly(); Goose().fly(); -Goose().walk(); +Goose().walk(); Dog().walk(); // Incorrect calls Bat().walk(); // Not using the Walker mixin Dog().fly(); // Not using the Flyer mixin ``` -{:.include-lang} -```js -class Animal {} -// Defining the mixins -class Flyer { - fly = () => console.log('Flaps wings'); -} -class Walker { - walk = () => console.log('Walks legs'); -} - -class Bat extends Animal {} -class Goose extends Animal {} -class Dog extends Animal {} - -// Composing the class instances with their correct functionality. -const bat = Object.assign(new Bat(), new Flyer()); -const goose = Object.assign(new Goose(), new Flyer(), new Walker()); -const dog = Object.assign(new Dog(), new Walker()); - -// Correct calls -bat.fly(); -goose.fly(); -goose.walk(); -dog.walk(); -// Incorrect calls -bat.walk(); // `bat` does not have the `walk` method -dog.fly(); // `dog` does not have the `fly` method -``` Alternatively, you can replace the `class` keyword with `mixin` to prevent the mixin from being used @@ -2453,7 +2541,7 @@ they can have overlapping methods or fields with each other when used on the same class. They can even overlap with the class that uses them, or that class's superclass. -The order in which they are added to a class matters. +The order in which they are added to a class matters. To give an example: @@ -2478,7 +2566,7 @@ However, sometimes it's useful to extend a class that already exists or is part of another library or the Dart SDK. In these cases, Dart offers the ability to write extensions -for existing classes. +for existing classes. As an example, the following extension on the `String` class from the Dart SDK allows parsing of integers: @@ -2509,6 +2597,7 @@ var age = '42'.parseInt(); // Use the extension method. Getters and setters in Dart work exactly like their JavaScript counterparts: + {:.include-lang} ```js class Person { @@ -2520,7 +2609,9 @@ class Person { set age(value) { if (value < 0) { - throw new Error('age cannot be negative'); + throw new Error( + 'age cannot be negative' + ); } this._age = value; } @@ -2531,18 +2622,21 @@ person.age = 10; console.log(person.age); ``` + {:.include-lang} ```dart class Person { int _age = 0; - + int get age { return _age; } - + set age(int value) { if (value < 0) { - throw ArgumentError('Age cannot be negative'); + throw ArgumentError( + 'Age cannot be negative' + ); } _age = value; } @@ -2555,26 +2649,25 @@ void main() { } ``` + + ### Public and private members Like JavaScript, Dart has no access modifier keywords: -all class members are public by default. +all class members are public by default. -While private class members are not yet officially -part of JavaScript because they are not part of any -published EcmaScript standard, -a proposal for this has been completed and is ready -to be included in the next publication of the standard. +JavaScript will include private class members in the next +practical revision of the EcmaScript standard. As such, implementations for this have been available in -various browsers and runtimes for a while already. +various browsers and runtimes for some time. -In JavaScript, you can indicate that a class member is private -by adding a pound symbol (`#`) as a prefix to its name: +To make a class member private in JavaScript, +prefix its name with a pound (or hash) symbol (`#`). {:.include-lang} ```js class Animal { - eyes; // Public field + eyes; // Public field #paws; // Private field #printEyes() { // Private method @@ -2587,14 +2680,13 @@ class Animal { } ``` -Similarly, Dart allows developers to make a -class member private by prefixing its name -with an underscore (`_`): +To make a class member private in Dart, prefix its name +with an underscore (`_`). {:.include-lang} ```dart class Animal { - int eyes; // Public field + int eyes; // Public field int _paws; // Private field void _printEyes() { // Private method @@ -2607,113 +2699,87 @@ class Animal { } ``` -In JavaScript, this is a convention, -but in Dart this is a full language feature -enforced by the compiler. +JavaScript uses the hash as a convention. +Dart's compiler enforces use of the underscore for this feature. -A difference that should be noted is that in Dart, -private members are not private to the class, -but are private to the library, -meaning that private members can still be accessed -from code that is considered part of the same library. -By default, this is possible anywhere in the same file, -so private class members can still be accessed from code -in the same file. While you can expand this library scope -beyond a single file using the `part` directive, -it's generally advised to [avoid doing so][] and is usually -reserved for code generators. +Dart makes private members private to the library, not the class. +This means that you can access private members from code in the same library. +By default, Dart limits access to private class members to code in the same file. +To expand the scope of a library beyond one file, add the `part` directive. +When possible, [avoid using `part`][]. Reserve using `part` for code generators. -[avoid doing so]: /guides/libraries/create-library-packages#organizing-a-library-package +[avoid using `part`]: /guides/libraries/create-library-packages#organizing-a-library-package ### Late variables -Assign the `late` keyword to class fields to -indicate they are initialized at a later point, -while remaining non-nullable. This is useful -for cases where a variable is never observed -before being initialized, allowing it to be initialized later. -This has several advantages over just labeling the field as nullable: +To indicate that Dart initializes class fields at a later point, +assign the `late` keyword to those class fields. +Those class fields remain non-nullable. +Do this when a variable doesn't need to observed or accessed immediately +and can be initialized later. +This differs from labeling the field as nullable. * (Non-nullable) late fields cannot have null assigned at a later point. * (Non-nullable) late fields throw a runtime error when - accessed before they are initialized. + accessed before they initialize. This should be avoided. {:.include-lang} ```dart -// Using null safety: -class Coffee { - late String _temperature; - - void heat() { _temperature = 'hot'; } - void chill() { _temperature = 'iced'; } - - String serve() => _temperature + ' coffee'; +class PetOwner { + final String name; + late final Pet _pet; + PetOwner(this.name, String petName) { + // Cyclic object graph, cannot set _pet before owner exists. + _pet = Pet(petName, this); + } + Pet get pet => _pet; +} +class Pet { + final String name; + final PetOwner owner; + Pet(this.name, this.owner); } ``` -In this case, `_temperature` is only initialized -after calling `heat()` or `chill()`. -If `serve()` is called before either are called, -a runtime exception occurs. -The `_temperature` field can never be assigned `null`. - -You can use the `late` keyword to make initialization _lazy_, -when combined with an initializer: +Use `late` for local variables only if unclear code results +in the compiler being unable determine if the code initialized the variable. {:.include-lang} ```dart -class Weather { - late int _temperature = _readThermometer(); +doSomething(int n, bool capture) { + late List captures; + if (capture) captures = []; + for (var i = 0; i < n; i++) { + var foo = something(i); + if (capture) captures.add(foo); + } } ``` -In this example, `_readThermometer()` only runs -when the field is first accessed, -rather than on initialization. - -Lastly, use the `late` keyword to delay initialization -of `final` variables. While you don't need to immediately -initialize the final variable when marking it as `late`, -it still allows the variable to be initialized only once. -A second assignment results in a runtime error. - -{:.include-lang} -```dart -late final int a; -a = 1; -a = 2; // Throws a runtime exception `a` is already initialized. -``` +In the preceding example, the compiler does not know to assign +`captures` if `capture` is true. Using `late` delays the normal +"assigned" checks until runtime. -## Generics +## Generics -While Vanilla JavaScript doesn’t offer generics, -they are available in Dart to improve type safety -and reduce code duplication. +While JavaScript doesn’t offer generics, +Dart does to improve type safety and reduce code duplication. -### Generic methods +### Generic methods You can apply generics to methods. -To define a generic type, place it between `< >` -symbols after the method name. -This type can then be used within the method -(as the return type), or within the method’s parameters: +To define a generic type parameter, place it between angle brackets `< >` +after the method name. +You can then use this type within the method +as the return type or within the method’s parameters: {:.include-lang} ```dart -// Defining a method that uses generics. -T transform(T param) { - // E.g. doing some transformation on `param`... - return param; -} -// Calling the method. Variable `str` is of type String. -var str = transform('string value'); +Map _cache = {}; +T cache(T value) => (_cache[value] ??= value) as T; ``` -In this case, passing `String` to the `transform` method -ensures that it returns a `String`. Likewise, -if an `int` is provided, the return value is an `int`. - Define multiple generic types by separating them with a comma: {:.include-lang} @@ -2731,11 +2797,10 @@ transform(5, 'string value'); ### Generic classes Generics can also be applied to classes. -You can include the type to use when calling a constructor, -which allows you to tailor reusable classes to specific types. +You can include the type to use when calling a constructor. +This allows you to tailor reusable classes to specific types. -In the following example, the `Cache` class is for -caching specific types: +In the following example, the `Cache` class caches specific types: {:.include-lang} ```dart @@ -2749,8 +2814,8 @@ stringCache.setByKey('Foo', 'Bar'); // Valid, setting a string value. stringCache.setByKey('Baz', 5); // Invalid, int type does not match generic. ``` -If the type declaration is omitted, -the runtime type will be `Cache` +If you omit the type declaration, +the runtime type becomes `Cache` and both calls to `setByKey` are valid. ### Restricting generics @@ -2766,20 +2831,19 @@ class NumberManager { ... } // Valid. -var manager = NumberManager(); -var manager = NumberManager(); +var manager = NumberManager(); +var manager = NumberManager(); // Invalid, String nor its parent classes extend num. -var manager = NumberManager(); +var manager = NumberManager(); ``` ### Generics in literals -`Map`, `Set`, and `List` literals can explicitly -declare generic types, which is useful when the -type isn’t inferred or is incorrectly inferred. +`Map`, `Set`, and `List` literals can accept type arguments. +This helps when Dart cannot infer the type or infer the type correctly. For example, the `List` class has a generic definition: -`class List`. Generic type `E` refers to the type of +`class List`. The type parameter `E` refers to the type of the list’s contents. Normally, this type is automatically inferred, which is used in some `List` class’s member types. (For example, its first getter returns a value of type `E`.) @@ -2842,13 +2906,13 @@ int get length => ... This guide has introduced you to the major differences between Dart and JavaScript. At this point, -you might consider moving to the general documentation -for Dart or [Flutter]({{site.flutter}}) -(an open-source framework that -uses Dart for building beautiful, natively compiled, -multi-platform applications from a single codebase), -where you'll find in-depth information about the -language and practical ways of getting started. +consider reading the Dart documentation. +You could also read the [Flutter]({{site.flutter}}) docs. +Built with Dart, Flutter is an open-source framework that +uses Dart for building natively compiled, +multi-platform applications from a single codebase. +These docs provide in-depth information about the +language and practical ways of getting started. Some possible next steps: diff --git a/src/_guides/language/effective-dart/index.md b/src/_guides/language/effective-dart/index.md index 0ab5c97f3..334957b10 100644 --- a/src/_guides/language/effective-dart/index.md +++ b/src/_guides/language/effective-dart/index.md @@ -47,24 +47,6 @@ write consistent, robust, fast code too. There are two overarching themes: [code golf]: https://en.wikipedia.org/wiki/Code_golf -The Dart analyzer has a linter to help you write good, consistent code. -If a linter rule exists that can help you follow a guideline, -then the guideline links to that rule. Here's an example: - -Dart Analyzer 中有一个 Linter 工具,该工具可以帮助你编写优秀的、一致性的代码。 -如果存在一个 Linter 规则可以帮助你遵循某个指南准则, -那么该指南准则将链接到该规则。比如下面的示例: - -{% include linter-rule-mention.md rule="prefer_collection_literals" %} - -For help on -[enabling linter rules](/guides/language/analysis-options#enabling-linter-rules), -see the documentation for -[customizing static analysis](/guides/language/analysis-options). - -更多关于 [开启 Linter 规则](/guides/language/analysis-options#enabling-linter-rules) 的帮助, -请查阅 [自定义静态分析](/guides/language/analysis-options) 文档。 - ## The guides ## 指南 @@ -167,6 +149,33 @@ readable and maintainable code. 大部分的准则都是常识,也符合我们的认知。 最终要达到的目标是写出优雅,可读,可维护的代码。 +The Dart analyzer provides a linter +to help you write good, consistent code +that follows these and other guidelines. +If one or more [linter rules][lints] exist +that can help you follow a guideline +then the guideline links to those rules. +The links use the following format: + +Dart 分析器提供了一个 Linter 工具, +可以帮助你编写优秀的、一致性的以及符合各种指南的代码。 +如果存在一个或者多个 [linter 规则][lints] +来帮助你遵循某个指南准则,那么这些指南的链接也会有显示。 +比如下面的示例: + +{% include linter-rule-mention.md rule="unnecessary_getters_setters" %} + +To learn how to use the linter, +see [Enabling linter rules][] +and the list of [linter rules][lints]. + +学习如何使用 linter,请查阅文档 +[启用 linter 规则][Enabling linter rules], +以及可用的各种 [linter 规则][lints]。 + +[Enabling linter rules]: /guides/language/analysis-options#enabling-linter-rules +[lints]: /tools/linter-rules + ## Glossary ## 术语表 diff --git a/src/_guides/language/language-tour.md b/src/_guides/language/language-tour.md index 139204978..13532909d 100644 --- a/src/_guides/language/language-tour.md +++ b/src/_guides/language/language-tour.md @@ -1859,11 +1859,19 @@ unless they're explicitly marked as `required`. When defining a function, use {param1, param2, …} -to specify named parameters: +to specify named parameters. +If you don't provide a default value +or mark a named parameter as `required`, +their types must be nullable +as their default value will be `null`: 定义函数时,使用 {参数1, 参数2, …} 来指定命名参数: +如果你没有提供一个默认值, +也没有使用 `required` 标记的话, +那么它一定可空的类型, +因为他们的默认值会是 `null`: ```dart @@ -1884,65 +1892,85 @@ For example: enableFlags(bold: true, hidden: false); ``` -Although it often makes sense to place positional arguments first, -named arguments can be placed anywhere in the argument list -when it suits your API: + +To define a default value for a named parameter besides `null`, +use `=` to specify a default value. +The specified value must be a compile-time constant. +For example: -尽管先使用位置参数会比较合理,但你也可以在任意位置使用命名参数, -让整个调用的方式看起来更适合你的 API: +你可以使用 `=` 来为一个命名参数指定除了 `null` 以外的默认值。 +指定的默认值必须要为编译时的常量,例如: - + ```dart -repeat(times: 2, () { - ... -}); -``` - -{{site.alert.tip}} - - If a parameter is optional but can't be `null`, - provide a [default value](#default-parameter-values). - - 如果一个参数是可选的,但是不能为 `null`, - 你需要为它提供一个 [默认值](#default-parameter-values)。 +/// Sets the [bold] and [hidden] flags ... +void enableFlags({bool bold = false, bool hidden = false}) {...} -{{site.alert.end}} +// bold will be true; hidden will be false. +enableFlags(bold: true); +``` -Although named parameters are a kind of optional parameter, -you can annotate them with `required` to indicate -that the parameter is mandatory—that users -must provide a value for the parameter. -For example: +If you instead want a named parameter to be mandatory, +requiring callers to provide a value for the parameter, +annotate them with `required`: -虽然命名参数是可选参数的一种类型, -但是你仍然可以使用 `required` 来标识一个命名参数是必须的参数, -此时调用者必须为该参数提供一个值。 -例如: +如果你希望一个命名参数是强制需要使用的,调用者需要提供它的值, +则你可以使用 `required` 进行声明: -{% prettify dart tag=pre+code %} +```dart const Scrollbar({super.key, [!required!] Widget child}); -{% endprettify %} +``` If someone tries to create a `Scrollbar` without specifying the `child` argument, then the analyzer reports an issue. -如果调用者想要通过 `Scrollbar` 的构造函数构造一个 Scrollbar 对象而不提供 `child` 参数, -则会导致编译错误。 +当你创建一个不带 `child` 参数的 `Scrollbar` 时, +分析器就会报告这里出了问题。 -{% comment %} -NULLSAFE: Rewrite this section. -{% endcomment %} +{{site.alert.note}} + + A parameter marked as `required` + can still be nullable: + + 一个标记了 `required` 的参数 + 仍然是可空的类型: + + + ```dart + const Scrollbar({super.key, required [!Widget?!] child}); + ``` +{{site.alert.end}} + +You might want to place positional arguments first, +but Dart doesn't require it. +Dart allows named arguments to be placed anywhere in the +argument list when it suits your API: + +尽管先使用位置参数会比较合理,但你也可以在任意位置使用命名参数, +让整个调用的方式看起来更适合你的 API: + + +```dart +repeat(times: 2, () { + ... +}); +``` #### Optional positional parameters #### 可选的位置参数 -Wrapping a set of function parameters in `[]` marks them as optional -positional parameters: +Wrapping a set of function parameters in `[]` +marks them as optional positional parameters. +If you don't provide a default value, +their types must be nullable +as their default value will be `null`: -使用 `[]` 将一系列参数包裹起来作为位置参数: +使用 `[]` 将一系列参数包裹起来,即可将其标记为位置参数, +因为它们的默认值是 `null`,所以如果你没有提供默认值的话, +它们的类型必须得是允许为空 (nullable) 的类型。 ```dart @@ -1955,8 +1983,8 @@ String say(String from, String msg, [String? device]) { } ``` -Here’s an example of calling this function without the optional -parameter: +Here’s an example of calling this function +without the optional parameter: 下面是不使用可选参数调用上述函数的示例 @@ -1975,64 +2003,13 @@ assert(say('Bob', 'Howdy', 'smoke signal') == 'Bob says Howdy with a smoke signal'); ``` - -#### Default parameter values - -#### 默认参数值 - -Your function can use `=` to define default values for optional parameters, -both named and positional. The default values must be compile-time constants. -If no default value is provided, the default value is `null`. - -可以用 `=` 为函数的命名参数和位置参数定义默认值,默认值必须为编译时常量, -没有指定默认值的情况下默认值为 `null`。 - -Here's an example of setting default values for named parameters: - -下面是设置可选参数默认值示例: - - -```dart -/// Sets the [bold] and [hidden] flags ... -void enableFlags({bool bold = false, bool hidden = false}) {...} - -// bold will be true; hidden will be false. -enableFlags(bold: true); -``` - -{{site.alert.secondary}} - - **Deprecation note:** Old code might use a colon (`:`) instead of `=` - to specify default values of named parameters. - The reason is that originally, only `:` was supported for named parameters. - That support is deprecated and will be removed, - so we recommend that you **[use `=` to specify default values.][use =]** - - If you have the [`prefer_equal_for_default_values`][] linter rule enabled, - you can use [`dart fix`][] to migrate to the suggested `=` syntax. - - 在老版本的 Dart 代码中会使用 冒号(`:`)而不是 `=` 来设置命名参数的默认值。 - 原因在于刚开始的时候命名参数只支持 `:`。 - 不过现在这个支持已经过时并且会被移除掉, - 所以我们建议你仅 **[使用 `=` 来指定默认值][use =]**。 - - 如果你启用了 [`prefer_equal_for_default_values`][] 这个 linter 规则, - 你可以使用 [`dart fix`][] 命令来迁移到建议的 `=` 语法。 - - [use =]: /guides/language/effective-dart/usage#do-use--to-separate-a-named-parameter-from-its-default-value - [`prefer_equal_for_default_values`]: /tools/linter-rules#prefer_equal_for_default_values - [`dart fix`]: /tools/dart-fix - -{{site.alert.end}} - -{% comment %} -TODO #2950: Update if/when we drop support for `:`. -See `defaultNamedParameter` in the language spec. -{% endcomment %} - -The next example shows how to set default values for positional parameters: +To define a default value for an optional positional parameter besides `null`, +use `=` to specify a default value. +The specified value must be a compile-time constant. +For example: -下一个示例将向你展示如何为位置参数设置默认值: +你可以使用 `=` 来为一个位置可选参数指定除了 `null` 以外的默认值。 +指定的默认值必须要为编译时的常量,例如: ```dart @@ -2044,33 +2021,6 @@ String say(String from, String msg, [String device = 'carrier pigeon']) { assert(say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon'); ``` -You can also pass lists or maps as default values. -The following example defines a function, `doStuff()`, -that specifies a default list for the `list` -parameter and a default map for the `gifts` parameter. - -List 或 Map 同样也可以作为默认值。下面的示例定义了一个名为 `doStuff()` 的函数, -并为其名为 `list` 和 `gifts` 的参数指定了一个 List 类型的值和 Map 类型的值。 - -{% comment %} -The function is called three times with different values. Click **Run** to see -list and map default values in action. -{% endcomment %} - - -```dart -void doStuff( - {List list = const [1, 2, 3], - Map gifts = const { - 'first': 'paper', - 'second': 'cotton', - 'third': 'leather' - }}) { - print('list: $list'); - print('gifts: $gifts'); -} -``` - ### The main() function ### main() 函数 @@ -2387,11 +2337,53 @@ assert(foo() == null); ## 运算符 Dart supports the operators shown in the following table. +The table shows Dart's operator associativity +and [operator precedence](#operator-precedence-example) from highest to lowest, +which are an **approximation** of Dart's operator relationships. You can implement many of these [operators as class members](#_operators). -Dart 支持下表的操作符。 +Dart 支持下表所示的操作符,它也体现了 Dart +运算符的关联性和 [优先级](#operator-precedence-example) 的从高到低的顺序。 +这也是 Dart 运算符关系的近似值。 你可以将这些运算符实现为 [一个类的成员](#_operators)。 +|-----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------| +| Description | Operator | Associativity | +|-----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------| +| unary postfix | expr++    expr--    `()`    `[]`    `?[]`    `.`    `?.`    `!` | None | +| unary prefix | -expr    !expr    ~expr    ++expr    --expr      await expr    | None | +| multiplicative | `*`    `/`    `%`  `~/` | Left | +| additive | `+`    `-` | Left | +| shift | `<<`    `>>`    `>>>` | Left | +| bitwise AND | `&` | Left | +| bitwise XOR | `^` | Left | +| bitwise OR | `|` | Left | +| relational and type test | `>=`    `>`    `<=`    `<`    `as`    `is`    `is!` | None | +| equality | `==`    `!=`    | None | +| logical AND | `&&` | Left | +| logical OR | `||` | Left | +| if null | `??` | Left | +| conditional | expr1 ? expr2 : expr3 | Right | +| cascade | `..`    `?..` | Right | +| assignment | `=`    `*=`    `/=`   `+=`   `-=`   `&=`   `^=`   etc. | Right | +{:.table .table-striped} + +{{site.alert.warning}} + + The previous table should only be used as a helpful guide. + The notion of operator precedence and associativity + is an approximation of the truth found in the language grammar. + You can find the authoritative behavior of Dart's operator relationships + in the grammar defined in the [Dart language specification][]. + + 上述的表格只是作为一个比较实用的指南, + 操作符的优先级和关联性概念是从编程语言的语法中整理发现的。 + 你可以在 [Dart 编程语言规范][Dart language specification] + 文档中找到更为权威的解释。 + +{{site.alert.end}} + +{% comment %} |--------------------------+------------------------------------------------| | 描述 | 运算符 | |--------------------------|------------------------------------------------| @@ -2411,18 +2403,12 @@ Dart 支持下表的操作符。 | 条件表达式 | 表达式 1 ? 表达式 2 : 表达式 3 | | 级联 | `..` `?..` | | 赋值 | `=` `*=` `/=` `+=` `-=` `&=` `^=` 等等…… | -{:.table .table-striped} -{{site.alert.warning}} - - Operator precedence is an approximation of the behavior of a Dart parser. - For definitive answers, consult the grammar in the - [Dart language specification][]. +#TODO +先让英文原文完成编译,然后再动 markdown 表格吧,在源代码中看着太乱了。 - 上述运算符优先级是对 Dart 解析器行为的效仿。更准确的描述, - 请参阅 [Dart 语言规范][Dart language specification] 中的语法。 +{% endcomment %} -{{site.alert.end}} When you use operators, you create expressions. Here are some examples of operator expressions: @@ -2439,6 +2425,7 @@ c ? a : b a is T ``` + In the [operator table](#operators), each operator has higher precedence than the operators in the rows that follow it. For example, the multiplicative operator `%` has higher @@ -6457,8 +6444,6 @@ defining a `@Todo` annotation that takes two arguments: ```dart -library todo; - class Todo { final String who; final String what; @@ -6473,11 +6458,9 @@ And here’s an example of using that `@Todo` annotation: ```dart -import 'todo.dart'; - -@Todo('seth', 'make this do something') +@Todo('Dash', 'Implement this function') void doSomething() { - print('do something'); + print('Do something'); } ``` diff --git a/src/_sass/main.scss b/src/_sass/main.scss index 5f969bf35..3aad7b18b 100644 --- a/src/_sass/main.scss +++ b/src/_sass/main.scss @@ -489,7 +489,7 @@ li.card { @include dart-style-for(runtime-success, $alert-success-bg, $alert-success-fg, '\2714 runtime: success'); @include dart-style-for(runtime-fail, $alert-danger-bg, $alert-danger-fg, '\2717 runtime: error'); @include dart-style-for('include-lang.language-dart', $pre-bg, $brand-primary, 'Dart'); -@include dart-style-for(language-js, $pre-bg, #f1a85a, 'JavaScript'); +@include dart-style-for('include-lang.language-js', $pre-bg, #f1a85a, 'JavaScript'); .muted { color: $gray; diff --git a/src/assets/img/cover/dart-apprentice-beyond-the-basics.png b/src/assets/img/cover/dart-apprentice-beyond-the-basics.png new file mode 100644 index 000000000..c9b1b44b3 Binary files /dev/null and b/src/assets/img/cover/dart-apprentice-beyond-the-basics.png differ diff --git a/src/assets/img/cover/dart-apprentice-fundamentals.png b/src/assets/img/cover/dart-apprentice-fundamentals.png new file mode 100644 index 000000000..3d288e035 Binary files /dev/null and b/src/assets/img/cover/dart-apprentice-fundamentals.png differ diff --git a/src/assets/img/cover/dart-apprentice.png b/src/assets/img/cover/dart-apprentice.png deleted file mode 100644 index 91b8de3e2..000000000 Binary files a/src/assets/img/cover/dart-apprentice.png and /dev/null differ diff --git a/src/get-dart/index.md b/src/get-dart/index.md index 0c04e39b1..2e04c69ad 100644 --- a/src/get-dart/index.md +++ b/src/get-dart/index.md @@ -110,16 +110,16 @@ Dart SDK 支持 Windows、Linux 和 macOS。 ### macOS * **Supported versions:** Latest three major versions. - As of November 2021, the following versions are supported: - - macOS 10.15 (Catalina) +Dart supports the following macOS versions as of November 2022: - macOS 11 (Big Sur) - macOS 12 (Monterey) + - macOS 13 (Ventura) **支持的版本:**最新的三个主要版本。 - 截止 2021 年 11 月,支持以下版本: - - macOS 10.15 (Catalina) + 截止 2022 年 11 月,支持 macOS 的以下版本 (macOS 10.15 的支持已被移除): - macOS 11 (Big Sur) - macOS 12 (Monterey) + - macOS 13 (Ventura) * **Supported architectures:** x64, ARM64. diff --git a/src/null-safety/faq.md b/src/null-safety/faq.md index 622771914..0d41430e6 100644 --- a/src/null-safety/faq.md +++ b/src/null-safety/faq.md @@ -447,6 +447,24 @@ _jellyPoints = [ ]; {% endprettify %} +To generate a fixed-length list, +use the [`List.generate`][] constructor +with the `growable` parameter set to `false`: + +你可以使用 [`List.generate`][] 构造加 +`growable` 参数设置为 `false` 来生成固定长度的列表: + +```dart +_jellyPoints = List.generate(jellyMax, (_) => Vec2D(), growable: false); +``` + +[`List.generate`]: {{site.dart-api}}/{{site.data.pkg-vers.SDK.channel}}/dart-core/List/List.generate.html + +{% comment %} + Would preferably suggest a language syntax here, + which is being suggested in https://github.com/dart-lang/language/issues/2477. +{% endcomment %} + ## What happened to the default List constructor? ## 默认的 List 构造有什么改动? diff --git a/src/null-safety/migration-guide.md b/src/null-safety/migration-guide.md index 5805dfbaa..de040f40e 100644 --- a/src/null-safety/migration-guide.md +++ b/src/null-safety/migration-guide.md @@ -227,13 +227,15 @@ update its dependencies to null-safe versions: Most of the changes that your code needs to be null safe are easily predictable. For example, if a variable can be `null`, -[its type needs a `?` suffix][nullable type]. -A named parameter that shouldn't be nullable -needs to be [marked `required`][required]. +[its type needs a `?` suffix][nullable type]. +If a named parameter shouldn't be nullable, +mark it [`required`][required] +or give it a [default value][]. 你的代码里大部分需要更改的代码,都是可以轻易推导的。 例如,如果一个变量可以为空,[它的类型需要 `?` 后缀][nullable type]。 -一个不可以为空的命名参数,需要使用 [`required` 标记][required]。 +一个不可以为空的命名参数,需要使用 [`required` 标记][required], +或者给定其一个 [默认值][default value]。 You have two options for migrating: @@ -259,6 +261,7 @@ You have two options for migrating: [nullable type]: /null-safety#creating-variables [required]: /null-safety/understanding-null-safety#required-named-parameters +[default value]: /guides/language/language-tour#default-parameters [migration tool]: #migration-tool [null safety FAQ]: /null-safety/faq diff --git a/src/resources/videos.md b/src/resources/videos.md index 6bcefa21d..b7ee3a18a 100644 --- a/src/resources/videos.md +++ b/src/resources/videos.md @@ -2,7 +2,6 @@ title: Videos description: Learn by watching! Here's a collection of videos about Dart. dart-playlist-id: PLjxrf2q8roU0Net_g1NT5_vOO3s_FR02J -smartherd-playlist-id: PLlxmoA0rQ-LyHW9voBdNo4gEEIh0SjG-q --- Here are some videos about the Dart language and core libraries. @@ -14,7 +13,6 @@ If you'd like other videos to be listed on this page, TODO: If the list of videos grows, consider automating this like book.md. {% endcomment %} - ## Dart videos from Google A playlist of Google-produced videos, @@ -24,13 +22,3 @@ to the Dart session from Google I/O 2019. [Playlist: Dart videos](https://www.youtube.com/playlist?list={{page.dart-playlist-id}}) - - - -## Dart tutorial for beginners (by Smartherd) - -A community-provided series of tutorial videos about the Dart language. - - - -[Playlist: Dart tutorial for beginners](https://www.youtube.com/playlist?list={{page.smartherd-playlist-id}}) diff --git a/src/tools/pub/cmd/pub-global.md b/src/tools/pub/cmd/pub-global.md index 8d52849cc..061e50ee3 100644 --- a/src/tools/pub/cmd/pub-global.md +++ b/src/tools/pub/cmd/pub-global.md @@ -103,6 +103,18 @@ $ dart pub global activate --source git https://github.com/dart-lang/async_await $ dart pub global activate -sgit https://github.com/dart-lang/async_await.git ``` +Pub expects to find the package in the root of the Git repository. +To specify a different location, +use the `--git-path` option with +a path relative to the repository root: + +Pub 会尝试在 Git 仓库的根目录寻找 package。 +你可以使用 `--git-path` 选项为 Pub 指定用于查找的相对于仓库的路径: + +```terminal +$ dart pub global activate -sgit https://github.com/dart-lang/http.git --git-path pkgs/http/ +``` + ### Activating a package on your local machine ### 激活当前设备上的 Package diff --git a/src/tools/pub/cmd/pub-outdated.md b/src/tools/pub/cmd/pub-outdated.md index 0c7a6e249..81c658f32 100644 --- a/src/tools/pub/cmd/pub-outdated.md +++ b/src/tools/pub/cmd/pub-outdated.md @@ -1,7 +1,6 @@ --- title: dart pub outdated description: Use dart pub outdated to help you update your package dependencies. -diff2html: true --- _Outdated_ is one of the commands of the [pub tool](/tools/pub/cmd). @@ -96,10 +95,6 @@ the version in the **Resolvable** column In [caret syntax][], that's **`^0.12.1`**. Here's the diff for `pubspec.yaml`: -{% comment %} - [TODO: Improve the formatting of the following diff] -{% endcomment %} - ```diff - http: ^0.11.0 + http: ^0.12.1 diff --git a/src/web/js-interop.md b/src/web/js-interop.md index 64f3fa86e..016070f67 100644 --- a/src/web/js-interop.md +++ b/src/web/js-interop.md @@ -18,13 +18,10 @@ For help using the `js` package, see the following: * [pub.dev site page][js] * [API reference][js-api] * Packages that use the `js` package: - * [firebase][] is a good example of providing a Dart-like API - to a JavaScript library. * [sass][] is an example of a more unusual use case: providing a way for JavaScript code to call Dart code. [js]: {{site.pub-pkg}}/js [js-api]: {{site.pub-api}}/js -[firebase]: {{site.pub-pkg}}/firebase [sass]: {{site.pub-pkg}}/sass