diff --git a/.github/ISSUE_TEMPLATE/1_page_issue.yml b/.github/ISSUE_TEMPLATE/1_page_issue.yml index 3926106cb..034feec00 100644 --- a/.github/ISSUE_TEMPLATE/1_page_issue.yml +++ b/.github/ISSUE_TEMPLATE/1_page_issue.yml @@ -1,6 +1,6 @@ name: 文档或页面问题 description: 协助改进 dart.cn 的页面内容 -title: "[PAGE ISSUE]: '{请替换为页面的标题}'" +title: '[页面问题] {请替换为页面的标题}' labels: ['E: 页面问题'] body: - type: markdown @@ -11,7 +11,7 @@ body: id: page-url attributes: label: 页面 URL - placeholder: "例如:https://dart.cn/docs" + placeholder: "例如:https://dart.cn/guides" validations: required: true - type: input @@ -42,3 +42,11 @@ body: placeholder: 任何你认为我们需要知道的额外信息。 validations: required: false + - type: checkboxes + id: volunteer + attributes: + label: 我想来解决这个问题。 + description: 如果你想自己尝试修复,请告诉我们。 + options: + - label: 我会尝试在 dart.cn 上解决这个问题。 + required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b35f63b38..eb1ba7eb5 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,19 +1,4 @@ -Thanks for your contribution! Please replace this text with a description of what this PR is changing or adding and why, list any relevant issues, and review the contribution guidelines below. +**请点击「Preview」选择提交 PR 的模板**: -Fixes - ---- - -- [ ] I’ve reviewed the contributor guide and applied the relevant portions to this PR. -- [ ] This PR doesn’t contain automatically generated corrections or text (Grammarly, LLMs, and similar). -- [ ] This PR follows the [Google Developer Documentation Style Guidelines](https://developers.google.com/style) — for example, it doesn’t use _i.e._ or _e.g._, and it avoids _I_ and _we_ (first person). -- [ ] This PR uses [semantic line breaks](https://github.com/dart-lang/site-shared/blob/main/doc/writing-for-dart-and-flutter-websites.md#semantic-line-breaks) of 80 characters or fewer. - -
- Contribution guidelines:
- - - See our [contributor guide](https://github.com/dart-lang/site-www/blob/main/CONTRIBUTING.md) for general expectations for PRs. - - Larger or significant changes should be discussed in an issue before creating a PR. - - Code changes should generally follow the [Dart style guide](https://dart.dev/effective-dart) and use `dart format`. - - Updates to [code excerpts](https://github.com/dart-lang/site-shared/blob/main/doc/code-excerpts.md) indicated by ` +- [内容修订](?template=1_cn_doc_fix.md) +- [新增翻译](?template=2_localization_submission.md) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ebea6b17c..32b5d6f07 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ env: # Keep for Dart SDK reporting PUB_ENVIRONMENT: bot.github # LTS - NODE_VERSION: '18' + NODE_VERSION: '20' # Tool location BASE_DIR: ${{ github.workspace }} TOOL_DIR: ${{ github.workspace }}/tool @@ -31,14 +31,18 @@ jobs: fail-fast: false matrix: include: +# - sdk: dev +# experimental: false + - sdk: beta + experimental: false - sdk: stable experimental: false continue-on-error: ${{ matrix.experimental }} steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: submodules: recursive - - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f + - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: ${{ matrix.sdk }} - run: dart pub get @@ -59,15 +63,15 @@ jobs: FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} FIREBASE_PROJECT: default steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: submodules: recursive - run: make build - run: make write-prod-robots - - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 + - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 with: node-version: ${{ env.NODE_VERSION }} - - uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f + - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d with: sdk: stable #- run: tool/check-links.sh diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3881a55b4..9b334692f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -29,11 +29,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 + uses: github/codeql-action/init@74483a38d39275f33fcff5f35b679b5ca4a26a99 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@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 + uses: github/codeql-action/autobuild@74483a38d39275f33fcff5f35b679b5ca4a26a99 # ℹ️ 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@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 + uses: github/codeql-action/analyze@74483a38d39275f33fcff5f35b679b5ca4a26a99 diff --git a/.github/workflows/no-response.yaml b/.github/workflows/no-response.yaml index 22a7e3940..6933d6f22 100644 --- a/.github/workflows/no-response.yaml +++ b/.github/workflows/no-response.yaml @@ -31,4 +31,4 @@ jobs: # Number of days of inactivity before an issue is closed for lack of response. daysUntilClose: 21 # Label requiring a response. - responseRequiredLabel: "waiting for customer response" + responseRequiredLabel: "act.wait-for-customer" diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 16b5d60ba..b2c41d179 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -21,12 +21,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 + uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 with: results_file: results.sarif results_format: sarif @@ -41,7 +41,7 @@ jobs: # Upload the results as artifacts (optional). - name: "Upload artifact" - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 with: name: SARIF file path: results.sarif @@ -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@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 + uses: github/codeql-action/upload-sarif@74483a38d39275f33fcff5f35b679b5ca4a26a99 with: sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index b86e7f5c3..33872d381 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,8 @@ tmp # Misc trash /src/_data/ci.yaml + +# SHA Update +# The script generates the .save file in case you need a rollback. +*.save +tool/new-dart-hashes.txt diff --git a/.gitmodules b/.gitmodules index 1ca07b61a..e870af4f0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "site-shared"] - path = site-shared - url = https://github.com/dart-lang/site-shared.git - branch = main + path = site-shared + url = https://github.com/dart-lang/site-shared + branch = main diff --git a/Dockerfile b/Dockerfile index 0d4f71514..10099e9a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,18 @@ -FROM ruby:3.2-slim-bookworm@sha256:2de48b02b2c3383799991fd5573462a7646a92a068b4afbb0e161ad166a3de9a as base +FROM ruby:3.2-slim-bookworm@sha256:adc7f93df5b83c8627b3fadcc974ce452ef9999603f65f637e32b8acec096ae1 as base + +SHELL ["/usr/bin/bash", "-c"] + +# Configure Debian mirrors. +RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources ENV DEBIAN_FRONTEND=noninteractive -ENV TZ=US/Pacific +ENV TZ=Asia/Shanghai RUN apt update && apt install -yq --no-install-recommends \ build-essential \ ca-certificates \ curl \ git \ + gnupg \ lsof \ make \ unzip \ @@ -32,27 +38,29 @@ ENV DART_SDK=/usr/lib/dart ENV PATH=$DART_SDK/bin:$PATH RUN set -eu; \ case "$(dpkg --print-architecture)_${DART_CHANNEL}" in \ + # BEGIN dart-sha amd64_stable) \ - DART_SHA256="cccd5300faa5a9abce12a5f77586e26350028cea82bb4ff8eeb55641b58a2e1d"; \ + DART_SHA256="4342ba274a4e9f8057079cf9de43b1c7bdb002016ad538313e8ebe942b61bba8"; \ SDK_ARCH="x64";; \ arm64_stable) \ - DART_SHA256="2c8eeaf0d3da60c4e14beec45ce3b39aca754f71b9fa3fb0c635ee28d6f44708"; \ + DART_SHA256="0f0e19c276c99fa3efd6428ea4bef1502f742f2a1f9772959637eec775c10ba0"; \ SDK_ARCH="arm64";; \ amd64_beta) \ - DART_SHA256="e3bdf39358dda7f0fd02b25d4d4539536fff53b4ab257da31a5fbbe42edc28c9"; \ + DART_SHA256="b3aa85b15bd13d619ba924524d5c7f082dc256a062ad34fe12ec824c9f05c2b3"; \ SDK_ARCH="x64";; \ arm64_beta) \ - DART_SHA256="7e7c2d1d4c8c8a6a47d916f422ddad2d5497307a147fa860b7b063ffdd162939"; \ + DART_SHA256="b7644435c8acf1e73da3f1ce16889b7222fbab37a75111aff225422a1cc61cab"; \ SDK_ARCH="arm64";; \ amd64_dev) \ - DART_SHA256="53368087f4c191d8b55338d13c32a70bf6cbfb0a99b6b4d86e53cb366bfce446"; \ + DART_SHA256="ae283eec0aa6e044064a79fc524af3dffec0543c48488538fc1a01a1fae7567b"; \ SDK_ARCH="x64";; \ arm64_dev) \ - DART_SHA256="474a251dfa7f6ba41f68d889b774569c4d2da5b4262f0c48fa53424e5b42f200"; \ + DART_SHA256="99153759fe1edbc5c1c6a8c5e5164fad11671eed8a8899bf127a17412b701172"; \ SDK_ARCH="arm64";; \ + # END dart-sha esac; \ SDK="dartsdk-linux-${SDK_ARCH}-release.zip"; \ - BASEURL="https://storage.googleapis.com/dart-archive/channels"; \ + BASEURL="https://storage.flutter-io.cn/dart-archive/channels"; \ URL="$BASEURL/$DART_CHANNEL/release/$DART_VERSION/sdk/$SDK"; \ curl -fsSLO "$URL"; \ echo "$DART_SHA256 *$SDK" | sha256sum --check --status --strict - || (\ @@ -78,21 +86,13 @@ CMD ["./tool/test.sh"] # ============== NODEJS INSTALL ============== FROM dart as node -RUN set -eu; \ - NODE_PPA="node_ppa.sh"; \ - NODE_SHA256=4ef190086f051a5242b8f9e7dff891d94c72bd484672d4a962f7189556977994; \ - curl -fsSL https://deb.nodesource.com/setup_lts.x -o "$NODE_PPA"; \ - echo "$NODE_SHA256 $NODE_PPA" | sha256sum --check --status --strict - || (\ - echo -e "\n\nNODE CHECKSUM FAILED! Run tool/fetch-node-ppa-sum.sh for updated values.\n\n" && \ - rm "$NODE_PPA" && \ - exit 1 \ - ); \ - sh "$NODE_PPA" && rm "$NODE_PPA"; \ - apt-get update -q && apt-get install -yq --no-install-recommends \ - nodejs \ - && rm -rf /var/lib/apt/lists/* -# Ensure latest NPM -RUN npm install -g npm + +RUN mkdir -p /etc/apt/keyrings \ + && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ + && apt-get update -yq \ + && apt-get install nodejs -yq \ + && npm install -g npm # Ensure latest npm # ============== DEV/JEKYLL SETUP ============== @@ -106,7 +106,8 @@ RUN BUNDLE_WITHOUT="test production" bundle install --jobs=4 --retry=2 ENV NODE_ENV=development COPY package.json package-lock.json ./ -RUN npm install +RUN npm install -g firebase-tools@12.8.1 +RUN npm ci COPY ./ ./ @@ -137,7 +138,7 @@ CMD ["make", "emulate"] # ============== BUILD PROD JEKYLL SITE ============== -FROM node AS build +FROM node as build WORKDIR /app ENV JEKYLL_ENV=production @@ -147,7 +148,7 @@ RUN BUNDLE_WITHOUT="test development" bundle install --jobs=4 --retry=2 --quiet ENV NODE_ENV=production COPY package.json package-lock.json ./ -RUN npm install +RUN npm ci COPY ./ ./ @@ -164,4 +165,10 @@ RUN tool/translator/build.sh # ============== DEPLOY to FIREBASE ============== FROM build as deploy +# RUN npm install -g firebase-tools@12.8.1 +# ARG FIREBASE_TOKEN +# ENV FIREBASE_TOKEN=$FIREBASE_TOKEN +# ARG FIREBASE_PROJECT=default +# ENV FIREBASE_PROJECT=$FIREBASE_PROJECT +# RUN [[ -z "$FIREBASE_TOKEN" ]] && echo "FIREBASE_TOKEN is required for container deploy!" RUN make deploy-ci diff --git a/Gemfile b/Gemfile index dd3d73731..5256034ad 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source "https://rubygems.org" -gem 'activesupport', '~> 7.0.6' +gem 'activesupport', '~> 7.1.2' gem 'jekyll', '4.3.2' gem 'jekyll-sass-converter', '~> 3.0.0' gem 'kramdown-parser-gfm' diff --git a/Gemfile.lock b/Gemfile.lock index 1a3cac039..69a17a29a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,15 +1,25 @@ GEM remote: https://rubygems.org/ specs: - activesupport (7.0.6) + activesupport (7.1.2) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) - addressable (2.8.4) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) + base64 (0.2.0) + bigdecimal (3.1.4) colorator (1.1.0) concurrent-ruby (1.2.2) + connection_pool (2.4.1) + drb (2.2.0) + ruby2_keywords em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) @@ -18,9 +28,9 @@ GEM forwardable-extended (~> 2.5) ffi (1.15.5) forwardable-extended (2.6.0) - google-protobuf (3.23.2) - google-protobuf (3.23.2-aarch64-linux) - google-protobuf (3.23.2-x86_64-linux) + google-protobuf (3.24.3) + google-protobuf (3.24.3-aarch64-linux) + google-protobuf (3.24.3-x86_64-linux) http_parser.rb (0.8.0) i18n (1.14.1) concurrent-ruby (~> 1.0) @@ -59,32 +69,34 @@ GEM rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.4.0) - mini_portile2 (2.8.2) - minitest (5.18.1) - nokogiri (1.15.2) + mini_portile2 (2.8.4) + minitest (5.20.0) + mutex_m (0.2.0) + nokogiri (1.15.4) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.15.2-aarch64-linux) + nokogiri (1.15.4-aarch64-linux) racc (~> 1.4) - nokogiri (1.15.2-x86_64-linux) + nokogiri (1.15.4-x86_64-linux) racc (~> 1.4) pathutil (0.16.2) forwardable-extended (~> 2.6) - public_suffix (5.0.1) - racc (1.7.0) + public_suffix (5.0.3) + racc (1.7.1) rake (13.0.6) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rexml (3.2.5) - rouge (4.1.2) + rexml (3.2.6) + rouge (4.1.3) + ruby2_keywords (0.0.5) safe_yaml (1.0.5) - sass-embedded (1.63.2) + sass-embedded (1.67.0) google-protobuf (~> 3.23) - rake (>= 10.0.0) - sass-embedded (1.63.2-aarch64-linux-gnu) + rake (>= 13.0.0) + sass-embedded (1.67.0-aarch64-linux-gnu) google-protobuf (~> 3.23) - sass-embedded (1.63.2-x86_64-linux-gnu) + sass-embedded (1.67.0-x86_64-linux-gnu) google-protobuf (~> 3.23) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) @@ -99,7 +111,7 @@ PLATFORMS x86_64-linux DEPENDENCIES - activesupport (~> 7.0.6) + activesupport (~> 7.1.2) jekyll (= 4.3.2) jekyll-sass-converter (~> 3.0.0) jekyll-toc (~> 0.18.0) @@ -108,4 +120,4 @@ DEPENDENCIES webrick BUNDLED WITH - 2.4.13 + 2.4.19 diff --git a/Makefile b/Makefile index dfff69d42..460ed02df 100644 --- a/Makefile +++ b/Makefile @@ -58,14 +58,26 @@ setup: --build-arg DART_CHANNEL=${DART_CHANNEL} # Serve the Jekyll site with livereload and incremental builds +# Tip: livereload is not supported serve: - bundle exec jekyll serve \ - --host ${JEKYLL_SITE_HOST} \ - --port ${JEKYLL_SITE_PORT} \ +# bundle exec jekyll serve \ +# --host ${JEKYLL_SITE_HOST} \ +# --port ${JEKYLL_SITE_PORT} \ +# --config _config.yml,_config_dev.yml \ +# --livereload \ +# --incremental \ +# --trace + bundle exec jekyll clean + bundle exec jekyll build \ --config _config.yml,_config_dev.yml \ - --livereload \ --incremental \ --trace + bash tool/translator/build.sh + bundle exec jekyll serve \ + --host ${JEKYLL_SITE_HOST} \ + --port ${JEKYLL_SITE_PORT} \ + --trace\ + --skip-initial-build # Run all tests inside a built container test: @@ -103,17 +115,26 @@ write-prod-robots: # Deploy locally deploy: - sh tool/translator/deploy-cn.sh + bash tool/translator/deploy-cn.sh ################## UTILS ################## -# Fetch SDK sums for current Dart SDKs by arch, Node PPA +# Fetch SDK sums for current Dart SDKs by arch # This outputs a bash case format to be copied to Dockerfile fetch-sums: - tool/fetch-dart-sdk-sums.sh \ + bash tool/fetch-dart-sdk-sums.sh \ --version ${DART_VERSION} \ --channel ${DART_CHANNEL} - tool/fetch-node-ppa-sum.sh + +# Check Dart sums pulls the set of Dart SDK SHA256 hashes +# and writes them to a temp file. +check-sums: + bash tool/check-dart-sdk.sh + +# Update Dart sums replaces the Dart SDK SHA256 hashes +# in the Dockerfile and deletes the temp file. +update-sums: + bash tool/update-dart-sdk.sh # Test the dev container with pure docker test-builds: @@ -127,4 +148,4 @@ test-builds: # Test stable run with volume TEST_CHANNEL =? stable test-run: - docker run --rm -it -v ${PWD}:/app ${BUILD_TAG}:${TEST_CHANNEL} bash \ No newline at end of file + docker run --rm -it -v ${PWD}:/app ${BUILD_TAG}:${TEST_CHANNEL} bash diff --git a/README.md b/README.md index 44af89240..1994a765a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The https://dart.dev site, built with [Jekyll][] and hosted on [Firebase][]. -[We welcome contributions](CONTRIBUTING.md), +[We welcome contributions](CONTRIBUTING.md), and we're [first-timer friendly][first-timers]! ## Getting started @@ -19,7 +19,7 @@ To update this site, fork the repo, make your changes, and generate a pull request. For simple changes (such as to CSS and text), you probably don't need to build this site. Often you can make changes using the GitHub UI. -> **NOTE:** If you clone this repo locally, +> **NOTE:** If you clone this repo locally, > see the instructions below on cloning with its submodule. If your change involves code samples, adds/removes pages, or affects navigation, @@ -34,239 +34,235 @@ If you want or need to build, follow the steps below. > or [file an issue](https://github.com/dart-lang/site-www/issues/new?title=README%20issue) > (or both). - ## Before you build this site -For changes beyond simple text and CSS tweaks, +For changes beyond simple text and CSS tweaks, we recommend building the site. ### 1. Get the prerequisites Install the following tools, if you don't have them already: -- **bash**, the Bourne shell. - These instructions assume you're using `bash`, +- **bash**, the Bourne shell. + These instructions assume you're using `bash`, and setup might not work if you use another shell. -- **GNU Make**. +- **GNU Make**. On Windows the easiest way to install Make is `choco install make` - using command prompt or powershell as an admin. + using command prompt or powershell as an admin. Other options include using a [subsystem][wsl]. -- **Docker**. - We use Docker for local dev, tests, and building the site. +- **Docker**. + We use Docker for local dev, tests, and building the site. Install it from https://docs.docker.com/get-docker/. -- **Firebase CLI**, for hosting the site locally. - One way to get this is to run `npm install -g firebase-tools`. - For full setup details, +- **Firebase CLI**, for hosting the site locally. + One way to get this is to run `npm install -g firebase-tools`. + For full setup details, read the [Firebase CLI documentation](https://firebase.google.com/docs/cli). ### 2. Clone this repo _and_ its submodules -> **Note:** This repo has git _submodules_, which affects how you clone it. +> **Note:** This repo has git _submodules_, which affects how you clone it. > The GitHub documentation has general help on [forking][] and [cloning][] repos. -If you're not a member of the Dart organization, -we recommend you **create a fork** of this repo under your own account, -and then submit a PR from that fork. +If you're not a member of the Dart organization, +we recommend you **create a fork** of this repo under your own account, +and then submit a PR from that fork. -Once you have a fork (or you're a Dart org member), +Once you have a fork (or you're a Dart org member), _choose one_ of the following submodule-cloning techniques: - Clone the repo and its submodule at the same time using the `--recurse-submodules` option: - ```bash + + ```terminal $ git clone --recurse-submodules https://github.com/dart-lang/site-www.git ``` *OR* - -- If you've already cloned the repo without its submodule, + +- If you've already cloned the repo without its submodule, then run this command from the repo root: - ```bash + + ```terminal $ git submodule update --init --recursive ``` -> **Note:** At any time during development +> **Note:** At any time during development > you can use the `git submodule` command to refresh submodules: -> ```bash +> +> ```terminal > $ git pull; git submodule update --init --recursive > ``` - ## Setting up your local environment and serve changes -1. _Optional:_ After cloning the repo and its submodules, +1. _Optional:_ After cloning the repo and its submodules, create a branch for your changes: - ```bash + + ```terminal $ git checkout -b ``` - -2. If the Docker Desktop application isn't already running on your machine, - start it. Look for the Docker status icon: if it has an exclamation + +2. If the Docker Desktop application isn't already running on your machine, + start it. Look for the Docker status icon: if it has an exclamation point (`!`), then update Docker Desktop before proceeding. 3. Run the initial local setup command: - ```bash + + ```terminal $ make setup ``` 4. Serve the site locally (via `docker-compose`): - ```bash + + ```terminal $ make up ``` - The site is generated, and then the development server runs in the + + The site is generated, and then the development server runs in the Docker container, with the generated `_site` directory visible locally as a mirrored volume from inside the container. 5. View your changes in the browser by navigating to `http://localhost:4000`. - > **Note:** Unless you're editing files under `site-shared`, - > you can safely ignore `ERROR: directory is already being watched` messages. + > **Note:** Unless you're editing files under `site-shared`, + > you can safely ignore `ERROR: directory is already being watched` messages. > For details, see [#1363](https://github.com/flutter/website/issues/1363). -6. Make your changes to the local repo. +6. Make your changes to the local repo. - The site will rebuild and the browser will autoreload to reflect the changes. + The site will rebuild and the browser will autoreload to reflect the changes. - > **Tip:** If you aren't seeing the changes you expect (e.g. src/_data), - > `ctrl-C` out of your running dev server and rebuild the site from scratch + > **Tip:** If you aren't seeing the changes you expect (e.g. src/_data), + > Ctrl + C out of your running dev server and rebuild the site from scratch > using the following commands: - > ```bash + > + > ```terminal > $ make down && make clean && make up > ``` - 7. Commit your changes to the branch and submit your PR. > See [Pre-push site checks](#pre-push-site-checks) 8. When you've finished developing, shut down the Docker container: - ```bash + + ```terminal $ make down ``` - -> **Tip:** To find additional commands, read the [Makefile][]. -> For example, if you need to debug the Docker setup, + +> **Tip:** To find additional commands, read the [Makefile][]. +> For example, if you need to debug the Docker setup, > you can run: -> ```bash +> +> ```terminal > $ make run > ``` - ## Pre-push site checks ### Checking documentation and example code -If you've made changes to this site's documentation and/or example code, +If you've made changes to this site's documentation and/or example code, and committed locally, then run the following command before pushing your work: -```bash +```terminal # Enter a running Docker container shell -make run +$ make run # Check/validate example code -tool/test.sh +$ tool/test.sh # Check links for 404 errors -tool/check-links.sh +$ tool/check-links.sh ``` -If these scripts report errors or warnings, -then address those issues and rerun the above commands. +If these scripts report errors or warnings, +then address those issues and rerun the above commands. Otherwise, you can push your changes. - ## Deploying to a staging site You can deploy your local edits to a personal Firebase hosting staging site as follows: -1. If you don't already have a Firebase project, - - - Navigate to the [Firebase Console](https://console.firebase.google.com) +1. If you don't already have a Firebase project, + + - Navigate to the [Firebase Console](https://console.firebase.google.com) and create your own Firebase project (for example, `dart-dev-staging`). - Head back to your local repo shell and verify that you are logged in. - ```bash + + ```terminal $ firebase login ``` - Ensure that your project exists and activate that project: - ```bash + + ```terminal $ firebase projects:list $ firebase use ``` - + 1. Build the site via Docker: - ```bash + + ```terminal $ make build ``` - This will build the site and copy it to your local `_site` directory. - If that directory previously existed, it will be replaced. + This will build the site and copy it to your local `_site` directory. + If that directory previously existed, it will be replaced. 1. Deploy to your activated Firebase project's default hosting site: - ```bash + + ```terminal $ FIREBASE_PROJECT= make deploy ``` - > **TIP:** Add your `FIREBASE_PROJECT` env var to your `.env` file + > **TIP:** Add your `FIREBASE_PROJECT` env var to your `.env` file > and it will overwrite the default every time you deploy without specifying. -1. Navigate to your PR on GitHub and update it with the location of +1. Navigate to your PR on GitHub and update it with the location of the staged version, the names of your reviewers, and so on. ## Creating and/or editing DartPad example code -Most of the code used to create [DartPad][] examples is hosted on GitHub. +Most of the code used to create [DartPad][] examples is hosted on GitHub. However, this repo also contains some `*.dart` files responsible for DartPad example code. -# Refresh DartPad HTML tooltips - -Files that require DartPad HTML to be manually updated -include instructions at the top that specify running: - -```bash -$ tool/create_code_with_tooltips.dart -``` - -Follow the instructions in those files to refresh the appropriate code. - ### DartPad picker -The DartPad example picker must be manually compiled if changes are made. +The DartPad example picker must be manually compiled if changes are made. This will regenerate the associated JavaScript file in `src/assets/dash/js`: -```bash +```terminal $ tool/compile.sh ``` - ## Dockerfile Maintenance ### Dart SDK and Node PPA Checksum values -Since both the Dart SDK and Node PPA `curl` remote files, -it's important to verify checksum values. -Both installs use `latest` and `lts` respectively, -so these files may be periodically updated. -When this happens, +Since the Dart SDK setup fetches remote files, +it's important to verify checksum values. +Both installs use `latest` and `lts` respectively, +so these files may be periodically updated. +When this happens, local checksums may fail and **This will break the Docker/Compose setup/build**. -You will see the relevant output in your shell e.g. `DART CHECKSUM FAILED!...`. +You will see the relevant output in your shell e.g. `DART CHECKSUM FAILED!...`. When this happens, run the following command: -```bash -make fetch-sums +```terminal +$ make fetch-sums ``` -This command will output the updated checksum values for both Node and Dart, -and that output will be formatted similar -or the same as what is currently in the Dockerfile. -Copy this output and replace the relevant install code in the Dockerfile, -then rerun your setup/build again. - +This command will output the updated checksum values for Dart, +and that output will be formatted similar +or the same as what is currently in the Dockerfile. +Copy this output and replace the relevant install code in the Dockerfile, +then rerun your setup/build again. [Build Status SVG]: https://github.com/dart-lang/site-www/workflows/build/badge.svg [OpenSSF Scorecard SVG]: https://api.securityscorecards.dev/projects/github.com/dart-lang/site-www/badge diff --git a/_config.yml b/_config.yml index 6190fb26d..9bd1c719d 100644 --- a/_config.yml +++ b/_config.yml @@ -1,14 +1,16 @@ # Site settings title: Dart -description: Dart is a client-optimized language for developing fast apps on any platform. +description: >- + Dart is a client-optimized language for developing fast apps on any platform. url: https://dart.cn dev-url: https://debug.dart.cn repo: this: https://github.com/cfug/dart.cn - shared: &repo-shared https://github.com/dart-lang/site-shared -branch: master + shared: https://github.com/dart-lang/site-shared +branch: main port: 4000 source: src + strict_front_matter: true liquid: error_mode: strict @@ -16,7 +18,6 @@ liquid: future: true # In support of https://github.com/dart-lang/site-www/issues/1111 sass: sass_dir: _sass - cache: false style: compressed load_paths: - ../node_modules/bootstrap-scss @@ -25,7 +26,7 @@ plugins: toc: min_level: 2 max_level: 3 - no_toc_section_class: no_toc_section # ignore if in no_toc_section element + no_toc_section_class: no_toc_section dart-site: '' @@ -40,20 +41,10 @@ dartpad: https://dartpad.cn dart-api: https://api.dart.cn flutter-api: https://api.flutter-io.cn news: https://news.dartlang.org +announce: https://groups.google.com/a/dartlang.org/g/announce show_banner: true -collections: - articles: - output: true - permalink: /articles/:path - tutorials: - output: true - permalink: /tutorials/:path - guides: - output: true - permalink: /guides/:path - defaults: - scope: path: '' diff --git a/_config_dev.yml b/_config_dev.yml index 4cd7fb644..e805d35e5 100644 --- a/_config_dev.yml +++ b/_config_dev.yml @@ -1,9 +1,6 @@ # Site settings for development mode -# url: https://dartlang-org-dev.firebaseapp.com -# url: https://dartlang-org-staging-0.firebaseapp.com # Dev url inside Docker container -url: http://0.0.0.0:4000 +url: http://127.0.0.1:4000 sass: - cache: true - style: extended \ No newline at end of file + style: extended diff --git a/_config_now.yml b/_config_now.yml deleted file mode 100644 index 7572b1b18..000000000 --- a/_config_now.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Fixed time stamp (useful when comparing generated site versions) -now: 2018-07-01 12:34:56 - -assets: - digest: false - source_maps: true diff --git a/examples/README.md b/examples/README.md index 99506c5b4..4de01987f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -10,7 +10,7 @@ and more. Site-www specific information is given below. Change directory into the example's folder and run Dart commands there. For example: -```console +```terminal $ cd examples/misc $ dart pub get $ dart analyze . @@ -21,7 +21,7 @@ $ dart analyze . Change directory into the example's folder and run Dart commands there. For example: -```console +```terminal $ cd examples/misc $ dart pub get $ dart test # Run VM tests diff --git a/examples/analysis/pubspec.yaml b/examples/analysis/pubspec.yaml index f0e00b04c..5a545cd86 100644 --- a/examples/analysis/pubspec.yaml +++ b/examples/analysis/pubspec.yaml @@ -2,10 +2,10 @@ name: examples description: dart.dev example code. environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dependencies: examples_util: {path: ../util} dev_dependencies: - lints: ^2.1.0 + lints: ^3.0.0 diff --git a/examples/analysis_alt/pubspec.yaml b/examples/analysis_alt/pubspec.yaml index 4407f3cb0..e28f11ce8 100644 --- a/examples/analysis_alt/pubspec.yaml +++ b/examples/analysis_alt/pubspec.yaml @@ -2,7 +2,7 @@ name: examples description: dart.dev example code. environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dev_dependencies: - lints: ^2.1.0 + lints: ^3.0.0 diff --git a/examples/analysis_options.yaml b/examples/analysis_options.yaml index a8e15a216..fae8e9f82 100644 --- a/examples/analysis_options.yaml +++ b/examples/analysis_options.yaml @@ -12,11 +12,8 @@ linter: - always_declare_return_types - cancel_subscriptions - close_sinks - - collection_methods_unrelated_type - combinators_ordering - comment_references - - dangling_library_doc_comments - - implicit_call_tearoffs - invalid_case_patterns - library_annotations - one_member_abstracts @@ -28,12 +25,8 @@ linter: - test_types_in_equals - throw_in_finally - type_annotate_public_apis - - type_literal_in_constant_pattern - unawaited_futures - unnecessary_breaks - unnecessary_library_directive - unnecessary_null_aware_operator_on_extension_on_nullable - - unnecessary_to_list_in_spreads - use_enums - - use_string_in_part_of_directives - - use_super_parameters diff --git a/examples/async_await/pubspec.yaml b/examples/async_await/pubspec.yaml index 0ae0d22e2..898205d9d 100644 --- a/examples/async_await/pubspec.yaml +++ b/examples/async_await/pubspec.yaml @@ -2,11 +2,11 @@ name: async_await description: dart.dev example code. environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dependencies: examples_util: {path: ../util} dev_dependencies: - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/build_runner_usage/pubspec.yaml b/examples/build_runner_usage/pubspec.yaml index 1d7df6835..b4082079c 100644 --- a/examples/build_runner_usage/pubspec.yaml +++ b/examples/build_runner_usage/pubspec.yaml @@ -2,10 +2,10 @@ name: build_runner_usage description: dart.dev build_runner example code. environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dev_dependencies: args: ^2.4.0 - build_runner: ^2.4.1 - build_test: ^2.1.7 - lints: ^2.1.0 + build_runner: ^2.4.6 + build_test: ^2.2.0 + lints: ^3.0.0 diff --git a/examples/cli/analysis_options.yaml b/examples/cli/analysis_options.yaml new file mode 100644 index 000000000..5e2133eb6 --- /dev/null +++ b/examples/cli/analysis_options.yaml @@ -0,0 +1 @@ +include: ../analysis_options.yaml diff --git a/examples/misc/bin/dcat/dcat.dart b/examples/cli/bin/dcat.dart similarity index 51% rename from examples/misc/bin/dcat/dcat.dart rename to examples/cli/bin/dcat.dart index 4b5b2b1aa..ab45a577c 100644 --- a/examples/misc/bin/dcat/dcat.dart +++ b/examples/cli/bin/dcat.dart @@ -1,16 +1,14 @@ -// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// IMPORTANT NOTE: -// 1. If you change this file, ensure that the associated tooltip data remains -// valid (*_tooltips.html). -// 2. Regenerate the HTML version of this sample, by running -// tool/create_code_with_tooltips.dart -// 3. To generate the DartPad version: (1) delete lines containing only tip -// instructions. (2) Trim //!foo markers from the end of the remaining lines, -// e.g., using this Perl regexp: / ?\/\/!.*//g +/// Simple implementation of the *nix cat utility. +/// +/// Usage: `dart run dcat.dart [-n] patterns files` +/// +/// `dcat` reads `files` sequentially, writing them to standard output. +/// The file operands are processed in command-line order. +/// If `files` is absent, `dcat` reads from the standard input until `EOF`. +/// Unlike the *nix `cat`, `dcat` does not support single dash ('-') arguments. +library; +// #docregion dcat-app import 'dart:convert'; import 'dart:io'; @@ -18,22 +16,11 @@ import 'package:args/args.dart'; const lineNumber = 'line-number'; -/// Simple implementation of the *nix cat utility. //!web-only -/// //!web-only -/// Usage: dart run dcat.dart [-n] patterns files //!web-only -/// //!web-only -/// `dcat` reads `files` sequentially, writing them to standard output. The //!web-only -/// file operands are processed in command-line order. //!web-only -/// If `files` is absent, `dcat` reads from the standard input until `EOF`. //!web-only -/// //!web-only -/// Unlike the *nix `cat`, `dcat` does not support single dash ('-') arguments. //!web-only -//!tip("List arguments") // #docregion arg-processing void main(List arguments) { - exitCode = 0; // presume success + exitCode = 0; // Presume success final parser = ArgParser()..addFlag(lineNumber, negatable: false, abbr: 'n'); - //!tip("parser.parse(arguments)") ArgResults argResults = parser.parse(arguments); final paths = argResults.rest; @@ -41,12 +28,10 @@ void main(List arguments) { } // #enddocregion arg-processing -//!tip("async") Future dcat(List paths, {bool showLineNumbers = false}) async { if (paths.isEmpty) { // No files provided as arguments. Read from stdin and print each line. // #docregion pipe - //!tip("stdin.pipe(stdout)") //!tip("await") await stdin.pipe(stdout); // #enddocregion pipe } else { @@ -54,13 +39,9 @@ Future dcat(List paths, {bool showLineNumbers = false}) async { for (final path in paths) { var lineNumber = 1; final lines = utf8.decoder - //!tip("openRead()") //!tip("File(path)") .bind(File(path).openRead()) - //!tip("transform(const LineSplitter())") .transform(const LineSplitter()); - //!tip("try") try { - //!tip("await for (final line in lines)") await for (final line in lines) { // #docregion showLineNumbers if (showLineNumbers) { @@ -69,7 +50,6 @@ Future dcat(List paths, {bool showLineNumbers = false}) async { stdout.writeln(line); // #enddocregion showLineNumbers } - //!tip("catch") } catch (_) { await _handleError(path); } @@ -78,14 +58,15 @@ Future dcat(List paths, {bool showLineNumbers = false}) async { } } -// #docregion _handleError +// #docregion handle-error Future _handleError(String path) async { - //!tip("await FileSystemEntity.isDirectory(path)") - // #docregion await-FileSystemEntity + // #docregion await-entity if (await FileSystemEntity.isDirectory(path)) { stderr.writeln('error: $path is a directory'); } else { - exitCode = 2; //!tip("exitCode = 2") + exitCode = 2; } - // #enddocregion await-FileSystemEntity + // #enddocregion await-entity } +// #enddocregion handle-error +// #enddocregion dcat-app diff --git a/examples/cli/bin/dcat_stdin.dart b/examples/cli/bin/dcat_stdin.dart new file mode 100644 index 000000000..bf21dc4ff --- /dev/null +++ b/examples/cli/bin/dcat_stdin.dart @@ -0,0 +1,7 @@ +import 'dart:io'; + +void main() { + stdout.writeln('Type something'); + final input = stdin.readLineSync(); + stdout.writeln('You typed: $input'); +} diff --git a/examples/cli/dart_test.yaml b/examples/cli/dart_test.yaml new file mode 100644 index 000000000..107d8a335 --- /dev/null +++ b/examples/cli/dart_test.yaml @@ -0,0 +1 @@ +include: ../dart_test_base.yaml diff --git a/examples/misc/lib/tutorial/cmdline.dart b/examples/cli/lib/cmdline.dart similarity index 100% rename from examples/misc/lib/tutorial/cmdline.dart rename to examples/cli/lib/cmdline.dart diff --git a/examples/cli/pubspec.yaml b/examples/cli/pubspec.yaml new file mode 100644 index 000000000..79be688c7 --- /dev/null +++ b/examples/cli/pubspec.yaml @@ -0,0 +1,12 @@ +name: cli_examples +description: Examples for CLI tutorials on dart.dev + +environment: + sdk: ^3.1.0 + +dependencies: + args: ^2.4.2 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.8 diff --git a/examples/cli/test/dcat_test.dart b/examples/cli/test/dcat_test.dart new file mode 100644 index 000000000..202081fb0 --- /dev/null +++ b/examples/cli/test/dcat_test.dart @@ -0,0 +1,42 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:test/test.dart'; + +void main() { + const pathToQuotes = 'test_data/quote.txt'; + + test('dcat', () async { + final procResult = await Process.run('dart', [ + 'run', + '--enable-asserts', + 'bin/dcat.dart', + '-n', + pathToQuotes, + ]); + expect( + procResult.stdout, + allOf( + startsWith('1'), // Line number + contains('Dr. Seuss'), + endsWith('Nietzsche\n'), + ), + ); + }); + + test('dcat1', () async { + const greeting = '¡Hola Dash!'; + final process = await Process.start('dart', [ + 'run', + '--enable-asserts', + 'bin/dcat_stdin.dart', + ]); + process.stdin.writeln(greeting); + final output = await process.stdout.transform(const Utf8Decoder()).join(''); + final errors = await process.stderr.transform(const Utf8Decoder()).join(''); + + expect(await process.exitCode, 0); + expect(output, contains('You typed: $greeting')); + expect(errors, isEmpty); + }); +} diff --git a/examples/cli/test_data/quote.txt b/examples/cli/test_data/quote.txt new file mode 100644 index 000000000..561f56eb6 --- /dev/null +++ b/examples/cli/test_data/quote.txt @@ -0,0 +1,5 @@ +Be yourself. Everyone else is taken. -Oscar Wilde +Don't cry because it's over, smile because it happened. -Dr. Seuss +You only live once, but if you do it right, once is enough. -Mae West +# This is a comment line. +That which does not kill us makes us stronger. -Nietzsche diff --git a/examples/concurrency/pubspec.yaml b/examples/concurrency/pubspec.yaml index 68f750003..6dac852f2 100644 --- a/examples/concurrency/pubspec.yaml +++ b/examples/concurrency/pubspec.yaml @@ -4,8 +4,8 @@ version: 0.0.1 publish_to: none environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dev_dependencies: - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/create_libraries/pubspec.yaml b/examples/create_libraries/pubspec.yaml index 70aab4b51..0bb10262a 100644 --- a/examples/create_libraries/pubspec.yaml +++ b/examples/create_libraries/pubspec.yaml @@ -3,8 +3,8 @@ description: dart.dev example code. version: 1.0.0 environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dev_dependencies: - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/extension_methods/pubspec.yaml b/examples/extension_methods/pubspec.yaml index 5688bf183..a79180456 100644 --- a/examples/extension_methods/pubspec.yaml +++ b/examples/extension_methods/pubspec.yaml @@ -3,8 +3,8 @@ description: dart.dev example code. version: 1.0.0 environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dev_dependencies: - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/fetch_data/pubspec.yaml b/examples/fetch_data/pubspec.yaml index c85f7a9dd..1dd4a92d2 100644 --- a/examples/fetch_data/pubspec.yaml +++ b/examples/fetch_data/pubspec.yaml @@ -3,10 +3,10 @@ description: Fetch data example version: 0.0.1 environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dependencies: - http: ^0.13.5 + http: ^1.1.0 dev_dependencies: - lints: ^2.1.0 + lints: ^3.0.0 diff --git a/examples/futures/pubspec.yaml b/examples/futures/pubspec.yaml index e729a40f5..bf6319ad1 100644 --- a/examples/futures/pubspec.yaml +++ b/examples/futures/pubspec.yaml @@ -4,11 +4,11 @@ version: 0.0.1 publish_to: none environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dependencies: examples_util: {path: ../util} dev_dependencies: - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/html/pubspec.yaml b/examples/html/pubspec.yaml index 8cad6e997..e2d252c1e 100644 --- a/examples/html/pubspec.yaml +++ b/examples/html/pubspec.yaml @@ -3,12 +3,9 @@ description: dart.dev example code. version: 0.0.1 environment: - sdk: ^3.0.0 - -dependencies: - html: any + sdk: ^3.1.0 dev_dependencies: - test: ^1.24.2 - lints: ^2.1.0 + lints: ^3.0.0 + test: ^1.24.6 examples_util: {path: ../util} diff --git a/examples/iterables/pubspec.yaml b/examples/iterables/pubspec.yaml index 5793637ef..579884a3a 100644 --- a/examples/iterables/pubspec.yaml +++ b/examples/iterables/pubspec.yaml @@ -2,9 +2,9 @@ name: iterables_examples description: dart.dev example code. environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dev_dependencies: examples_util: {path: ../util} - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/language/lib/control_flow/branches.dart b/examples/language/lib/control_flow/branches.dart index d85eed9a0..5915f4d14 100644 --- a/examples/language/lib/control_flow/branches.dart +++ b/examples/language/lib/control_flow/branches.dart @@ -1,4 +1,4 @@ -// ignore_for_file: unused_local_variable +// ignore_for_file: unused_local_variable, dead_code, unreachable_switch_case class Point { final int x; @@ -142,9 +142,14 @@ dynamic miscDeclAnalyzedButNotTested() { } { + final pair = (1, 2); // #docregion guard switch (pair) { + case (int a, int b): + if (a > b) print('First element greater'); + // If false, prints nothing and exits the switch. case (int a, int b) when a > b: + // If false, prints nothing but proceeds to next case. print('First element greater'); case (int a, int b): print('First element not greater'); diff --git a/examples/language/lib/patterns/switch.dart b/examples/language/lib/patterns/switch.dart index d920d5b89..5ec3ca3b3 100644 --- a/examples/language/lib/patterns/switch.dart +++ b/examples/language/lib/patterns/switch.dart @@ -1,3 +1,5 @@ +// ignore_for_file: pattern_never_matches_value_type + class Rect { int width; int height; @@ -48,11 +50,13 @@ void main() { case 1: print('one'); - // Matches if the value of obj is between the constant values of 'first' and 'last'. + // Matches if the value of obj is between the + // constant values of 'first' and 'last'. case >= first && <= last: print('in range'); - // Matches if obj is a record with two fields, then assigns the fields to 'a' and 'b'. + // Matches if obj is a record with two fields, + // then assigns the fields to 'a' and 'b'. case (var a, var b): print('a = $a, b = $b'); diff --git a/examples/language/pubspec.yaml b/examples/language/pubspec.yaml index 7c735c4ed..2efd0bbfb 100644 --- a/examples/language/pubspec.yaml +++ b/examples/language/pubspec.yaml @@ -2,11 +2,11 @@ name: examples description: dart.dev example code. environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dependencies: examples_util: { path: ../util } dev_dependencies: - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/misc/bin/dcat/dcat1.dart b/examples/misc/bin/dcat/dcat1.dart deleted file mode 100644 index 7e6d63fe3..000000000 --- a/examples/misc/bin/dcat/dcat1.dart +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// #docregion -import 'dart:io'; - -void main() { - stdout.writeln('Type something'); - final input = stdin.readLineSync(); - stdout.writeln('You typed: $input'); -} diff --git a/examples/misc/bin/dcat/dcat_tooltips.html b/examples/misc/bin/dcat/dcat_tooltips.html deleted file mode 100644 index fd7bf6e2e..000000000 --- a/examples/misc/bin/dcat/dcat_tooltips.html +++ /dev/null @@ -1,53 +0,0 @@ - - diff --git a/examples/misc/lib/effective_dart/design_good.dart b/examples/misc/lib/effective_dart/design_good.dart index a557a9af1..3a9b87d29 100644 --- a/examples/misc/lib/effective_dart/design_good.dart +++ b/examples/misc/lib/effective_dart/design_good.dart @@ -523,27 +523,6 @@ class Graph1 { //---------------------------------------------------------------------------- -class Control {} - -// #docregion mixin -mixin ClickableMixin implements Control { - bool _isDown = false; - - void click(); - - void mouseDown() { - _isDown = true; - } - - void mouseUp() { - if (_isDown) click(); - _isDown = false; - } -} -// #enddocregion mixin - -//---------------------------------------------------------------------------- - // #docregion one-member-abstract-class typedef Predicate = bool Function(E element); // #enddocregion one-member-abstract-class diff --git a/examples/misc/lib/language_tour/classes/point.dart b/examples/misc/lib/language_tour/classes/point.dart index 2cc39b36d..bf2ce7e12 100644 --- a/examples/misc/lib/language_tour/classes/point.dart +++ b/examples/misc/lib/language_tour/classes/point.dart @@ -11,13 +11,15 @@ class Point { final double x; final double y; + // #docregion class-with-distanceTo, named-constructor + Point(this.x, this.y); // #enddocregion class-with-distanceTo, named-constructor // Sets the x and y instance variables // before the constructor body runs. - // #docregion class-with-distanceTo, named-constructor - Point(this.x, this.y); // #enddocregion class-with-distanceTo, constructor-initializer + // #docregion named-constructor + // Named constructor Point.origin() : x = xOrigin, diff --git a/examples/misc/lib/language_tour/classes/point_alt.dart b/examples/misc/lib/language_tour/classes/point_alt.dart index dc6eb595c..d9cb09ea5 100644 --- a/examples/misc/lib/language_tour/classes/point_alt.dart +++ b/examples/misc/lib/language_tour/classes/point_alt.dart @@ -4,18 +4,14 @@ /// - A constructor initializing fields in the body "the long way" /// - A named constructor with initializers, and a print statement in the body. /// -// #docregion constructor-long-way +// #docregion idiomatic-constructor class Point { double x = 0; double y = 0; - Point(double x, double y) { - // See initializing formal parameters for a better way - // to initialize instance variables. - this.x = x; - this.y = y; - } - // #enddocregion constructor-long-way + // Generative constructor with initializing formal parameters: + Point(this.x, this.y); + // #enddocregion idiomatic-constructor // #docregion initializer-list // Initializer list sets instance variables before @@ -35,5 +31,5 @@ class Point { } // #enddocregion initializer-list-with-assert -// #docregion constructor-long-way +// #docregion idiomatic-constructor } diff --git a/examples/misc/lib/language_tour/classes/super_initializer_parameters.dart b/examples/misc/lib/language_tour/classes/super_initializer_parameters.dart index b8ef2f5f2..42c3c311e 100644 --- a/examples/misc/lib/language_tour/classes/super_initializer_parameters.dart +++ b/examples/misc/lib/language_tour/classes/super_initializer_parameters.dart @@ -24,7 +24,6 @@ class Vector3d extends Vector2d { // #docregion positional final double z; - // #enddocregion named // Forward the x and y parameters to the default super constructor like: // Vector3d(final double x, final double y, this.z) : super(x, y); Vector3d(super.x, super.y, this.z); diff --git a/examples/misc/pubspec.yaml b/examples/misc/pubspec.yaml index 0dd5bc42d..c7bc8ca9b 100644 --- a/examples/misc/pubspec.yaml +++ b/examples/misc/pubspec.yaml @@ -2,13 +2,13 @@ name: examples description: dart.dev example code. environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dependencies: - args: ^2.3.0 - characters: ^1.2.1 + args: ^2.4.2 + characters: ^1.3.0 examples_util: { path: ../util } dev_dependencies: - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/misc/test/dcat_test.dart b/examples/misc/test/dcat_test.dart deleted file mode 100644 index fedc7e231..000000000 --- a/examples/misc/test/dcat_test.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:test/test.dart'; - -void main() { - const pathToQuotes = 'test_data/quote.txt'; - - test('dcat', () async { - final procResult = await Process.run( - 'dart', ['--enable-asserts', 'bin/dcat/dcat.dart', '-n', pathToQuotes]); - expect( - procResult.stdout, - allOf( - startsWith('1'), // Line number - contains('Dr. Seuss'), - endsWith('Nietzsche\n'), - )); - }); - - test('dcat1', () async { - const greeting = '¡Hola, Mundo!'; - final process = await Process.start( - 'dart', ['--enable-asserts', 'bin/dcat/dcat1.dart']); - process.stdin.writeln(greeting); - final output = await process.stdout.transform(Utf8Decoder()).join(''); - final errors = await process.stderr.transform(Utf8Decoder()).join(''); - - expect(await process.exitCode, 0); - expect(output, contains('You typed: $greeting')); - expect(errors, isEmpty); - }); -} diff --git a/examples/non_promotion/pubspec.yaml b/examples/non_promotion/pubspec.yaml index fd0737da2..2587cb5b7 100644 --- a/examples/non_promotion/pubspec.yaml +++ b/examples/non_promotion/pubspec.yaml @@ -3,7 +3,7 @@ description: dart.dev non-promotion examples. version: 0.0.1 environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dev_dependencies: - lints: ^2.1.0 + lints: ^3.0.0 diff --git a/examples/null_safety_codelab/pubspec.yaml b/examples/null_safety_codelab/pubspec.yaml index 670d0872a..0d8825b08 100644 --- a/examples/null_safety_codelab/pubspec.yaml +++ b/examples/null_safety_codelab/pubspec.yaml @@ -2,9 +2,9 @@ name: null_safety_codelab_examples description: dart.dev example code for null safety codelab environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dev_dependencies: examples_util: {path: ../util} - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/type_system/lib/incorrect_animal.dart b/examples/type_system/lib/incorrect_animal.dart new file mode 100644 index 000000000..1d3fd128b --- /dev/null +++ b/examples/type_system/lib/incorrect_animal.dart @@ -0,0 +1,29 @@ +// ignore_for_file: unused_local_variable, unused_element +import 'animal.dart'; + +// #docregion chase-mouse +class Mouse extends Animal {/* ... */} + +class Cat extends Animal { + @override + // ignore: invalid_override + void chase(Mouse a) {/* ... */} +} +// #enddocregion chase-mouse + +void notTypeSafeChase() { + // #docregion would-not-be-type-safe + Animal a = Cat(); + a.chase(Alligator()); // Not type safe or feline safe. + // #enddocregion would-not-be-type-safe +} + +void invalidDynamicList() { + // #docregion invalid-dynamic-list + void main() { + // ignore: invalid_assignment + List foo = [Dog()]; // Error + List bar = [Dog(), Cat()]; // OK + } + // #enddocregion invalid-dynamic-list +} diff --git a/examples/type_system/pubspec.yaml b/examples/type_system/pubspec.yaml index 7fe3129e2..31eba0fc7 100644 --- a/examples/type_system/pubspec.yaml +++ b/examples/type_system/pubspec.yaml @@ -2,11 +2,11 @@ name: type_system_examples description: dart.dev type system examples. environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dependencies: examples_util: {path: ../util} dev_dependencies: - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 diff --git a/examples/util/pubspec.yaml b/examples/util/pubspec.yaml index 341825e57..6d9a48f08 100644 --- a/examples/util/pubspec.yaml +++ b/examples/util/pubspec.yaml @@ -3,10 +3,10 @@ description: dart.dev example utilities. version: 0.0.2 environment: - sdk: ^3.0.0 + sdk: ^3.1.0 dependencies: - test: ^1.24.2 + test: ^1.24.6 dev_dependencies: - lints: ^2.1.0 + lints: ^3.0.0 diff --git a/examples/vector_victor/pubspec.yaml b/examples/vector_victor/pubspec.yaml index fabd60d4a..4fc023c2f 100644 --- a/examples/vector_victor/pubspec.yaml +++ b/examples/vector_victor/pubspec.yaml @@ -4,14 +4,14 @@ version: 1.0.0 # homepage: https://www.example.com environment: - sdk: ^3.0.0 + sdk: ^3.1.0 # dependencies: # path: ^1.8.0 dev_dependencies: - lints: ^2.1.0 - test: ^1.24.2 + lints: ^3.0.0 + test: ^1.24.6 dependencies: vector_math: ^2.1.4 diff --git a/firebase.json b/firebase.json index c258d1d31..a221ab2cc 100644 --- a/firebase.json +++ b/firebase.json @@ -30,6 +30,7 @@ { "source": "/\\)", "destination": "/", "type": 301 }, { "source": "/angular{,/**}", "destination": "https://github.com/angulardart", "type": 301 }, { "source": "/api", "destination": "https://api.dart.dev", "type": 301 }, + { "source": "/articles", "destination": "https://medium.com/dartlang", "type": 301 }, { "source": "/articles/api-naming-guide{,/**}", "destination": "/effective-dart/design", "type": 301 }, { "source": "/articles/archive/dart-2", "destination": "/guides/language/evolution#dart-20", "type": 301 }, { "source": "/articles/archive/event-loop", "destination": "https://medium.com/dartlang/dart-asynchronous-programming-isolates-and-event-loops-bffc3e296a6a", "type": 301 }, @@ -55,12 +56,11 @@ { "source": "/articles/language/await-async", "destination": "/codelabs/async-await", "type": 301 }, { "source": "/articles/language/mixins", "destination": "/language/mixins", "type": 301 }, { "source": "/articles/language/optional-types", "destination": "/resources/faq#types", "type": 301 }, - { "source": "/articles/libraries", "destination": "/articles", "type": 301 }, + { "source": "/articles/libraries", "destination": "/guides/libraries/library-tour", "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 }, + { "source": "/articles/m*{,/**}", "destination": "/guides/language/evolution", "type": 301 }, { "source": "/articles/mixins", "destination": "/language/mixins", "type": 301 }, { "source": "/articles/mocking-with-dart", "destination": "https://pub.dev/packages/mockito", "type": 301 }, { "source": "/articles/native-extensions-for-standalone-dart-vm", "destination": "/server/c-interop-native-extensions", "type": 301 }, @@ -79,6 +79,8 @@ { "source": "/books", "destination": "/resources/books", "type": 301 }, { "source": "/bug", "destination": "https://dartbug.com", "type": 301 }, { "source": "/bug/:rest*", "destination": "https://dartbug.com/:rest*", "type": 301 }, + { "source": "/cl", "destination": "https://dart-review.googlesource.com/q/status:open+-is:wip", "type": 301 }, + { "source": "/cl/:rest*", "destination": "https://dart-review.googlesource.com/c/sdk/+/:rest*", "type": 301 }, { "source": "/cloud{,/**}", "destination": "/server/google-cloud", "type": 301 }, { "source": "/codelabs/server{,/**}", "destination": "/tutorials/server/httpserver", "type": 301 }, { "source": "/code-of-conduct", "destination": "/community/code-of-conduct", "type": 301 }, @@ -156,10 +158,20 @@ { "source": "/go/false-secrets", "destination": "/tools/pub/pubspec#false_secrets", "type": 301 }, { "source": "/go/ffi", "destination": "/guides/libraries/c-interop", "type": 301 }, { "source": "/go/flutter-upper-bound-deprecation", "destination": "https://github.com/flutter/flutter/issues/68143", "type": 301 }, + { "source": "/go/non-promo-conflicting-getter", "destination": "/tools/non-promotion-reasons", "type": 301 }, + { "source": "/go/non-promo-conflicting-non-promotable-field", "destination": "/tools/non-promotion-reasons", "type": 301 }, + { "source": "/go/non-promo-conflicting-noSuchMethod-forwarder", "destination": "/tools/non-promotion-reasons", "type": 301 }, + { "source": "/go/non-promo-external-field", "destination": "/tools/non-promotion-reasons", "type": 301 }, + { "source": "/go/non-promo-field-promotion-unavailable", "destination": "/tools/non-promotion-reasons", "type": 301 }, + { "source": "/go/non-promo-non-field", "destination": "/tools/non-promotion-reasons", "type": 301 }, + { "source": "/go/non-promo-non-final-field", "destination": "/tools/non-promotion-reasons", "type": 301 }, { "source": "/go/non-promo-property", "destination": "/tools/non-promotion-reasons#property-or-this", "type": 301 }, + { "source": "/go/non-promo-public-field", "destination": "/tools/non-promotion-reasons", "type": 301 }, { "source": "/go/non-promo-this", "destination": "/tools/non-promotion-reasons#property-or-this", "type": 301 }, { "source": "/go/non-promo-write", "destination": "/tools/non-promotion-reasons#write", "type": 301 }, + { "source": "/go/null-safety-migration", "destination": "/null-safety/migration-guide", "type": 301 }, + { "source": "/go/package-discontinue", "destination": "/tools/pub/publishing#discontinue", "type": 301 }, { "source": "/go/package-retraction", "destination": "/tools/pub/publishing#retract", "type": 301 }, { "source": "/go/pub-cache", "destination": "/tools/pub/cmd/pub-cache", "type": 301 }, { "source": "/go/pubignore", "destination": "/tools/pub/publishing#what-files-are-published", "type": 301 }, @@ -173,6 +185,7 @@ { "source": "/googleapis", "destination": "https://github.com/dart-lang/googleapis", "type": 301 }, { "source": "/guides/get-started", "destination": "/overview", "type": 301 }, { "source": "/guides/language/analysis-options", "destination": "/tools/analysis", "type": 301 }, + { "source": "/guides/language/cheatsheet", "destination": "/language", "type": 301 }, { "source": "/guides/language/common-prob", "destination": "/guides/language/sound-problems", "type": 301 }, { "source": "/guides/language/concurrency", "destination": "/language/concurrency", "type": 301 }, { "source": "/guides/language/effective-dart", "destination": "/effective-dart", "type": 301 }, diff --git a/pubspec.yaml b/pubspec.yaml index 51b4a9aa7..28890d4d0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,15 +4,13 @@ publish_to: none homepage: https://dart.dev environment: - sdk: ^3.0.1 + sdk: ^3.1.0 dev_dependencies: - build_runner: ^2.4.4 + build_runner: ^2.4.6 code_excerpt_updater: path: site-shared/packages/code_excerpt_updater code_excerpter: path: site-shared/packages/code_excerpter linkcheck: ^3.0.0 - lints: ^2.1.0 - logging: ^1.2.0 - path: ^1.8.3 + lints: ^3.0.0 diff --git a/site-shared b/site-shared index 992976e42..1eb779898 160000 --- a/site-shared +++ b/site-shared @@ -1 +1 @@ -Subproject commit 992976e4265a60ac6262e41c5a9c168a6db15b05 +Subproject commit 1eb779898ebf50063b36f565f4d95b5ed8f62d54 diff --git a/src/404.html b/src/404.html index 1b5af05bd..3f4201d11 100644 --- a/src/404.html +++ b/src/404.html @@ -2,7 +2,6 @@ layout: error title: "404: Page not found" description: "dart.dev's 404 page." -permalink: /404 sitemap: false ---
@@ -14,7 +13,7 @@

Page not found

- +
diff --git a/src/_articles/archive/images/both-queues.png b/src/_articles/archive/images/both-queues.png deleted file mode 100644 index e5bc24e84..000000000 Binary files a/src/_articles/archive/images/both-queues.png and /dev/null differ diff --git a/src/_articles/archive/images/scheduling-tasks.png b/src/_articles/archive/images/scheduling-tasks.png deleted file mode 100644 index e1d2665d9..000000000 Binary files a/src/_articles/archive/images/scheduling-tasks.png and /dev/null differ diff --git a/src/_articles/archive/images/test-annotated.png b/src/_articles/archive/images/test-annotated.png deleted file mode 100644 index b5a93deba..000000000 Binary files a/src/_articles/archive/images/test-annotated.png and /dev/null differ diff --git a/src/_articles/archive/images/test-queue-output.png b/src/_articles/archive/images/test-queue-output.png deleted file mode 100644 index f10a7dcbc..000000000 Binary files a/src/_articles/archive/images/test-queue-output.png and /dev/null differ diff --git a/src/_articles/index.md b/src/_articles/index.md deleted file mode 100644 index 1ca3d5712..000000000 --- a/src/_articles/index.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: Articles -description: Read early articles about the Dart libraries. -toc: false ---- - -Read these articles for insight into the Dart libraries. -To find newer articles, see the -[Dart publication on medium.com.](https://medium.com/dartlang) - -
- {% assign articles = site.articles | where: 'categories', 'libraries' | sort: 'date' | reverse %} - -
- -Also see: - -* [Effective Dart](/effective-dart) -* [Tutorials](/tutorials) diff --git a/src/_data/linter_rules.json b/src/_data/linter_rules.json index 661c604b0..a4f6e1a35 100644 --- a/src/_data/linter_rules.json +++ b/src/_data/linter_rules.json @@ -114,6 +114,17 @@ "details": "**AVOID** using a parameter name that is the same as an existing type.\n\n**BAD:**\n```dart\nm(f(int));\n```\n\n**GOOD:**\n```dart\nm(f(int v));\n```\n\n", "sinceDartSdk": "2.0.0" }, + { + "name": "avoid_unstable_final_fields", + "description": "Avoid overriding a final field to return different values if called multiple times.", + "group": "errors", + "state": "experimental", + "incompatible": [], + "sets": [], + "fixStatus": "noFix", + "details": "**AVOID** overriding or implementing a final field as a getter which could\nreturn different values if it is invoked multiple times on the same receiver.\nThis could occur because the getter is an implicitly induced getter of a\nnon-final field, or it could be an explicitly declared getter with a body\nthat isn't known to return the same value each time it is called.\n\nThe underlying motivation for this rule is that if it is followed then a final\nfield is an immutable property of an object. This is important for correctness\nbecause it is then safe to assume that the value does not change during the\nexecution of an algorithm. In contrast, it may be necessary to re-check any\nother getter repeatedly if it is not known to have this property. Similarly,\nit is safe to cache the immutable property in a local variable and promote it,\nbut for any other property it is necessary to check repeatedly that the\nunderlying property hasn't changed since it was promoted.\n\n**BAD:**\n```dart\nclass A {\n final int i;\n A(this.i);\n}\n\nvar j = 0;\n\nclass B1 extends A {\n int get i => ++j + super.i; // LINT.\n B1(super.i);\n}\n\nclass B2 implements A {\n int i; // LINT.\n B2(this.i);\n}\n```\n\n**GOOD:**\n```dart\nclass C {\n final int i;\n C(this.i);\n}\n\nclass D1 implements C {\n late final int i = someExpression; // OK.\n}\n\nclass D2 extends C {\n int get i => super.i + 1; // OK.\n D2(super.i);\n}\n\nclass D3 implements C {\n final int i; // OK.\n D3(this.i);\n}\n```\n\n", + "sinceDartSdk": "3.3.0-wip" + }, { "name": "avoid_web_libraries_in_flutter", "description": "Avoid using web-only libraries outside Flutter web plugin packages.", @@ -135,7 +146,7 @@ "incompatible": [], "sets": [], "fixStatus": "noFix", - "details": "**DO** invoke `cancel` on instances of `dart.async.StreamSubscription`.\n\nCancelling instances of StreamSubscription prevents memory leaks and unexpected\nbehavior.\n\n**BAD:**\n```dart\nclass A {\n StreamSubscription _subscriptionA; // LINT\n void init(Stream stream) {\n _subscriptionA = stream.listen((_) {});\n }\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction() {\n StreamSubscription _subscriptionF; // LINT\n}\n```\n\n**GOOD:**\n```dart\nclass B {\n StreamSubscription _subscriptionB; // OK\n void init(Stream stream) {\n _subscriptionB = stream.listen((_) {});\n }\n\n void dispose(filename) {\n _subscriptionB.cancel();\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunctionOK() {\n StreamSubscription _subscriptionB; // OK\n _subscriptionB.cancel();\n}\n```\n\n", + "details": "**DO** invoke `cancel` on instances of `dart.async.StreamSubscription`.\n\nCancelling instances of StreamSubscription prevents memory leaks and unexpected\nbehavior.\n\n**BAD:**\n```dart\nclass A {\n StreamSubscription _subscriptionA; // LINT\n void init(Stream stream) {\n _subscriptionA = stream.listen((_) {});\n }\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction() {\n StreamSubscription _subscriptionF; // LINT\n}\n```\n\n**GOOD:**\n```dart\nclass B {\n StreamSubscription _subscriptionB; // OK\n void init(Stream stream) {\n _subscriptionB = stream.listen((_) {});\n }\n\n void dispose(filename) {\n _subscriptionB.cancel();\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunctionOK() {\n StreamSubscription _subscriptionB; // OK\n _subscriptionB.cancel();\n}\n```\n\n**Known limitations**\n\nThis rule does not track all patterns of StreamSubscription instantiations and\ncancellations. See [linter#317](https://github.com/dart-lang/linter/issues/317)\nfor more information.\n\n", "sinceDartSdk": "2.0.0" }, { @@ -146,7 +157,7 @@ "incompatible": [], "sets": [], "fixStatus": "noFix", - "details": "**DO** invoke `close` on instances of `dart.core.Sink`.\n\nClosing instances of Sink prevents memory leaks and unexpected behavior.\n\n**BAD:**\n```dart\nclass A {\n IOSink _sinkA;\n void init(filename) {\n _sinkA = File(filename).openWrite(); // LINT\n }\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction() {\n IOSink _sinkF; // LINT\n}\n```\n\n**GOOD:**\n```dart\nclass B {\n IOSink _sinkB;\n void init(filename) {\n _sinkB = File(filename).openWrite(); // OK\n }\n\n void dispose(filename) {\n _sinkB.close();\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunctionOK() {\n IOSink _sinkFOK; // OK\n _sinkFOK.close();\n}\n```\n\n", + "details": "**DO** invoke `close` on instances of `dart.core.Sink`.\n\nClosing instances of Sink prevents memory leaks and unexpected behavior.\n\n**BAD:**\n```dart\nclass A {\n IOSink _sinkA;\n void init(filename) {\n _sinkA = File(filename).openWrite(); // LINT\n }\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction() {\n IOSink _sinkF; // LINT\n}\n```\n\n**GOOD:**\n```dart\nclass B {\n IOSink _sinkB;\n void init(filename) {\n _sinkB = File(filename).openWrite(); // OK\n }\n\n void dispose(filename) {\n _sinkB.close();\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunctionOK() {\n IOSink _sinkFOK; // OK\n _sinkFOK.close();\n}\n```\n\n**Known limitations**\n\nThis rule does not track all patterns of Sink instantiations and\nclosures. See [linter#1381](https://github.com/dart-lang/linter/issues/1381)\nfor more information.\n\n", "sinceDartSdk": "2.0.0" }, { @@ -155,7 +166,11 @@ "group": "errors", "state": "stable", "incompatible": [], - "sets": [], + "sets": [ + "core", + "recommended", + "flutter" + ], "fixStatus": "noFix", "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": "2.19.0" @@ -168,7 +183,7 @@ "incompatible": [], "sets": [], "fixStatus": "noFix", - "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", + "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 up the name and\nlink to its docs. For this all to work, ensure that all identifiers in docs\nwrapped 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 comments to\nrefer to declarations using a fairly natural format but does not allow\n*arbitrary expressions*. In particular, code references within square brackets\ncan consist of either\n\n- a single identifier where the identifier is any identifier in scope for the\n 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\n of a class that is in scope and the second is the name of a member declared in\n the class,\n- a single identifier followed by a pair of parentheses where the identifier is\n the name of a class that is in scope (used to refer to the unnamed constructor\n for the class), or\n- two identifiers separated by a period and followed by a pair of parentheses\n where the first identifier is the name of a class that is in scope and the\n second is the name of a named constructor (not strictly necessary, but allowed\n for consistency).\n\n**Known limitations**\n\nThe `comment_references` linter rule aligns with the Dart analyzer's notion of\ncomment references, which is separate from Dartdoc's notion of comment\nreferences. The linter rule may report comment references which cannot be\nresolved by the analyzer, but which Dartdoc can. See\n[dartdoc#1142](https://github.com/dart-lang/linter/issues/1142) for more\ninformation.\n\n", "sinceDartSdk": "2.0.0" }, { @@ -255,7 +270,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "Using an `interface`, `base`, `final`, or `sealed` modifier on a class,\nor a `base` modifier on a mixin,\nauthors can control whether classes and mixins allow being implemented,\nextended, and/or mixed in from outside of the library where they're defined.\nIn some cases, it's possible for an author to inadvertently relax these controls\nand implicitly \"reopen\" a class. (A similar reopening cannot occur with a mixin.)\n\nThis lint guards against unintentionally reopening a class by requiring such\ncases to be made explicit with the \n[`@reopen`](https://pub.dev/documentation/meta/latest/meta/reopen-constant.html)\nannotation in `package:meta`.\n\n**BAD:**\n```dart\ninterface class I {}\n\nclass C extends I {} // LINT\n```\n\n**GOOD:**\n```dart\ninterface class I {}\n\nfinal class C extends I {}\n```\n\n```dart\ninterface class I {}\n\nfinal class C extends I {}\n```\n\n```dart\nimport 'package:meta/meta.dart';\n\ninterface class I {}\n\n@reopen\nclass C extends I {}\n```\n", + "details": "Using an `interface`, `base`, `final`, or `sealed` modifier on a class,\nor a `base` modifier on a mixin,\nauthors can control whether classes and mixins allow being implemented,\nextended, and/or mixed in from outside of the library where they're defined.\nIn some cases, it's possible for an author to inadvertently relax these controls\nand implicitly \"reopen\" a class. (A similar reopening cannot occur with a mixin.)\n\nThis lint guards against unintentionally reopening a class by requiring such\ncases to be made explicit with the\n[`@reopen`](https://pub.dev/documentation/meta/latest/meta/reopen-constant.html)\nannotation in `package:meta`.\n\n**BAD:**\n```dart\ninterface class I {}\n\nclass C extends I {} // LINT\n```\n\n**GOOD:**\n```dart\ninterface class I {}\n\nfinal class C extends I {}\n```\n\n```dart\nimport 'package:meta/meta.dart';\n\ninterface class I {}\n\n@reopen\nclass C extends I {}\n```\n", "sinceDartSdk": "3.0.0" }, { @@ -286,11 +301,7 @@ "group": "errors", "state": "deprecated", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DON'T** invoke `contains` on `Iterable` with an instance of different type\nthan the parameter type.\n\nDoing this will invoke `==` on its elements and most likely will return `false`.\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 someFunction3() {\n List list = [];\n if (list.contains('1')) print('someFunction3'); // LINT\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction8() {\n List list = [];\n DerivedClass3 instance;\n if (list.contains(instance)) print('someFunction8'); // LINT\n}\n```\n\n**BAD:**\n```dart\nabstract class SomeIterable implements Iterable {}\n\nabstract class MyClass implements SomeIterable {\n bool badMethod(String thing) => this.contains(thing); // LINT\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction10() {\n var list = [];\n if (list.contains(1)) print('someFunction10'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction1() {\n var list = [];\n if (list.contains(1)) print('someFunction1'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction4() {\n List list = [];\n if (list.contains(1)) print('someFunction4'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction5() {\n List list = [];\n DerivedClass1 instance;\n if (list.contains(instance)) print('someFunction5'); // OK\n}\n\nabstract class ClassBase {}\n\nclass DerivedClass1 extends ClassBase {}\n```\n\n**GOOD:**\n```dart\nvoid someFunction6() {\n List list = [];\n DerivedClass2 instance;\n if (list.contains(instance)) print('someFunction6'); // OK\n}\n\nabstract class ClassBase {}\n\nabstract class Mixin {}\n\nclass DerivedClass2 extends ClassBase with Mixin {}\n```\n\n**GOOD:**\n```dart\nvoid someFunction7() {\n List list = [];\n DerivedClass3 instance;\n if (list.contains(instance)) print('someFunction7'); // OK\n}\n\nabstract class ClassBase {}\n\nabstract class Mixin {}\n\nclass DerivedClass3 extends ClassBase implements Mixin {}\n```\n\n**DEPRECATED:** This rule is deprecated in favor of\n`collection_methods_unrelated_type`.\nThe rule will be removed in a future Dart release.\n\n", "sinceDartSdk": "2.0.0" @@ -301,11 +312,7 @@ "group": "errors", "state": "deprecated", "incompatible": [], - "sets": [ - "core", - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DON'T** invoke `remove` on `List` with an instance of different type than\nthe parameter type.\n\nDoing this will invoke `==` on its elements and most likely will\nreturn `false`.\n\n**BAD:**\n```dart\nvoid someFunction() {\n var list = [];\n if (list.remove('1')) print('someFunction'); // LINT\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction3() {\n List list = [];\n if (list.remove('1')) print('someFunction3'); // LINT\n}\n```\n\n**BAD:**\n```dart\nvoid someFunction8() {\n List list = [];\n DerivedClass3 instance;\n if (list.remove(instance)) print('someFunction8'); // LINT\n}\n```\n\n**BAD:**\n```dart\nabstract class SomeList implements List {}\n\nabstract class MyClass implements SomeList {\n bool badMethod(String thing) => this.remove(thing); // LINT\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction10() {\n var list = [];\n if (list.remove(1)) print('someFunction10'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction1() {\n var list = [];\n if (list.remove(1)) print('someFunction1'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction4() {\n List list = [];\n if (list.remove(1)) print('someFunction4'); // OK\n}\n```\n\n**GOOD:**\n```dart\nvoid someFunction5() {\n List list = [];\n DerivedClass1 instance;\n if (list.remove(instance)) print('someFunction5'); // OK\n}\n\nabstract class ClassBase {}\n\nclass DerivedClass1 extends ClassBase {}\n```\n\n**GOOD:**\n```dart\nvoid someFunction6() {\n List list = [];\n DerivedClass2 instance;\n if (list.remove(instance)) print('someFunction6'); // OK\n}\n\nabstract class ClassBase {}\n\nabstract class Mixin {}\n\nclass DerivedClass2 extends ClassBase with Mixin {}\n```\n\n**GOOD:**\n```dart\nvoid someFunction7() {\n List list = [];\n DerivedClass3 instance;\n if (list.remove(instance)) print('someFunction7'); // OK\n}\n\nabstract class ClassBase {}\n\nabstract class Mixin {}\n\nclass DerivedClass3 extends ClassBase implements Mixin {}\n```\n\n**DEPRECATED:** This rule is deprecated in favor of\n`collection_methods_unrelated_type`.\nThe rule will be removed in a future Dart release.\n\n", "sinceDartSdk": "2.0.0" @@ -369,7 +376,7 @@ "sets": [], "fixStatus": "needsEvaluation", "details": "**DON'T** assign a variable to itself. Usually this is a mistake.\n\n**BAD:**\n```dart\nclass C {\n int x;\n\n C(int x) {\n x = x;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass C {\n int x;\n\n C(int x) : x = x;\n}\n```\n\n**GOOD:**\n```dart\nclass C {\n int x;\n\n C(int x) {\n this.x = x;\n }\n}\n```\n\n**BAD:**\n```dart\nclass C {\n int _x = 5;\n\n int get x => _x;\n\n set x(int x) {\n _x = x;\n _customUpdateLogic();\n }\n\n void _customUpdateLogic() {\n print('updated');\n }\n\n void example() {\n x = x;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass C {\n int _x = 5;\n\n int get x => _x;\n\n set x(int x) {\n _x = x;\n _customUpdateLogic();\n }\n\n void _customUpdateLogic() {\n print('updated');\n }\n\n void example() {\n _customUpdateLogic();\n }\n}\n```\n\n**BAD:**\n```dart\nclass C {\n int x = 5;\n\n void update(C other) {\n this.x = this.x;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass C {\n int x = 5;\n\n void update(C other) {\n this.x = other.x;\n }\n}\n```\n\n", - "sinceDartSdk": "3.1.0-wip" + "sinceDartSdk": "3.1.0" }, { "name": "no_wildcard_variable_uses", @@ -380,7 +387,7 @@ "sets": [], "fixStatus": "needsEvaluation", "details": "**DON'T** use wildcard parameters or variables.\n\nWildcard parameters and local variables\n(e.g. underscore-only names like `_`, `__`, `___`, etc.) will\nbecome non-binding in a future version of the Dart language.\nAny existing code that uses wildcard parameters or variables will\nbreak. In anticipation of this change, and to make adoption easier,\nthis lint disallows wildcard and variable parameter uses.\n\n\n**BAD:**\n```dart\nvar _ = 1;\nprint(_); // LINT\n```\n\n```dart\nvoid f(int __) {\n print(__); // LINT multiple underscores too\n}\n```\n\n**GOOD:**\n```dart\nfor (var _ in [1, 2, 3]) count++;\n```\n\n```dart\nvar [a, _, b, _] = [1, 2, 3, 4];\n```\n", - "sinceDartSdk": "3.1.0-wip" + "sinceDartSdk": "3.1.0" }, { "name": "prefer_relative_imports", @@ -401,10 +408,7 @@ "group": "errors", "state": "stable", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "hasFix", "details": "**DON'T** use the type Null where void would work.\n\n**BAD:**\n```dart\nNull f() {}\nFuture f() {}\nStream f() {}\nf(Null x) {}\n```\n\n**GOOD:**\n```dart\nvoid f() {}\nFuture f() {}\nStream f() {}\nf(void x) {}\n```\n\nSome exceptions include formulating special function types:\n\n```dart\nNull Function(Null, Null);\n```\n\nand for making empty literals which are safe to pass into read-only locations\nfor any type of map or list:\n\n```dart\n[];\n{};\n```\n", "sinceDartSdk": "2.1.0" @@ -472,7 +476,7 @@ "name": "use_build_context_synchronously", "description": "Do not use BuildContexts across async gaps.", "group": "errors", - "state": "experimental", + "state": "stable", "incompatible": [], "sets": [ "flutter" @@ -544,7 +548,11 @@ "group": "pub", "state": "stable", "incompatible": [], - "sets": [], + "sets": [ + "core", + "recommended", + "flutter" + ], "fixStatus": "noFix", "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" @@ -632,6 +640,17 @@ "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" }, + { + "name": "annotate_redeclares", + "description": "Annotate redeclared members.", + "group": "style", + "state": "experimental", + "incompatible": [], + "sets": [], + "fixStatus": "hasFix", + "details": "**DO** annotate redeclared members.\n\nThis practice improves code readability and helps protect against\nunintentionally redeclaring members or being surprised when a member ceases to\nredeclare (due for example to a rename refactoring).\n\n**BAD:**\n```dart\nclass C {\n void f() { }\n}\n\nextension type E(C c) implements C {\n void f() {\n ...\n }\n}\n```\n\n**GOOD:**\n```dart\nimport 'package:meta/meta.dart';\n\nclass C {\n void f() { }\n}\n\nextension type E(C c) implements C {\n @redeclare\n void f() {\n ...\n }\n}\n```\n", + "sinceDartSdk": "3.2.0" + }, { "name": "avoid_annotating_with_dynamic", "description": "Avoid annotating with dynamic when not required.", @@ -1139,7 +1158,11 @@ "group": "style", "state": "stable", "incompatible": [], - "sets": [], + "sets": [ + "core", + "recommended", + "flutter" + ], "fixStatus": "hasFix", "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": "2.19.0" @@ -1288,7 +1311,11 @@ "group": "style", "state": "stable", "incompatible": [], - "sets": [], + "sets": [ + "core", + "recommended", + "flutter" + ], "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": "2.19.0" @@ -1388,7 +1415,7 @@ "sets": [], "fixStatus": "needsFix", "details": "**DO** use super parameter names that match their corresponding super\nconstructor's parameter names.\n\n**BAD:**\n\n```dart\nclass Rectangle {\n final int width;\n final int height;\n \n Rectangle(this.width, this.height);\n}\n\nclass ColoredRectangle extends Rectangle {\n final Color color;\n \n ColoredRectangle(\n this.color,\n super.height, // Bad, actually corresponds to the `width` parameter.\n super.width, // Bad, actually corresponds to the `height` parameter.\n ); \n}\n```\n\n**GOOD:**\n\n```dart\nclass Rectangle {\n final int width;\n final int height;\n \n Rectangle(this.width, this.height);\n}\n\nclass ColoredRectangle extends Rectangle {\n final Color color;\n \n ColoredRectangle(\n this.color,\n super.width,\n super.height, \n ); \n}\n```\n", - "sinceDartSdk": "3.1.0-wip" + "sinceDartSdk": "3.0.0" }, { "name": "missing_whitespace_between_adjacent_strings", @@ -1449,7 +1476,7 @@ "sets": [], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-true-or-false-in-equality-operations):\n\n**DON'T** use `true` or `false` in equality operations.\n\nThis lint applies only if the expression is of a non-nullable `bool` type.\n\n**BAD:**\n```dart\nif (someBool == true) {\n}\nwhile (someBool == false) {\n}\n```\n\n**GOOD:**\n```dart\nif (someBool) {\n}\nwhile (!someBool) {\n}\n```\n", - "sinceDartSdk": "3.1.0-wip" + "sinceDartSdk": "3.0.0" }, { "name": "no_runtimeType_toString", @@ -1459,7 +1486,7 @@ "incompatible": [], "sets": [], "fixStatus": "noFix", - "details": "Calling `toString` on a runtime type is a non-trivial operation that can\nnegatively impact performance. It's better to avoid it.\n\n**BAD:**\n```dart\nclass A {\n String toString() => '$runtimeType()';\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n String toString() => 'A()';\n}\n```\n\nThis lint has some exceptions where performance is not a problem or where real\ntype information is more important than performance:\n\n* in assertion\n* in throw expressions\n* in catch clauses\n* in mixin declaration\n* in abstract class\n\n", + "details": "Calling `toString` on a runtime type is a non-trivial operation that can\nnegatively impact performance. It's better to avoid it.\n\n**BAD:**\n```dart\nclass A {\n String toString() => '$runtimeType()';\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n String toString() => 'A()';\n}\n```\n\nThis lint has some exceptions where performance is not a problem or where real\ntype information is more important than performance:\n\n* in an assertion\n* in a throw expression\n* in a catch clause\n* in a mixin declaration\n* in an abstract class declaration\n\n", "sinceDartSdk": "2.8.1" }, { @@ -1661,7 +1688,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "**DO** use collection literals when possible.\n\n**BAD:**\n```dart\nvar addresses = Map();\nvar uniqueNames = Set();\nvar ids = LinkedHashSet();\nvar coordinates = LinkedHashMap();\n```\n\n**GOOD:**\n```dart\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 addresses = Map();\nvar uniqueNames = Set();\nvar ids = LinkedHashSet();\nvar coordinates = LinkedHashMap();\n```\n\n**GOOD:**\n```dart\nvar addresses = {};\nvar uniqueNames = {};\nvar ids = {};\nvar coordinates = {};\n```\n\n**EXCEPTIONS:**\n\nWhen a `LinkedHashSet` or `LinkedHashMap` is expected, a collection literal is\nnot preferred (or allowed).\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" }, { @@ -1774,10 +1801,7 @@ "group": "style", "state": "removed", "incompatible": [], - "sets": [ - "recommended", - "flutter" - ], + "sets": [], "fixStatus": "noFix", "details": "**DO** use `=` to separate a named parameter from its default value.\n\n**BAD:**\n```dart\nm({a: 1})\n```\n\n**GOOD:**\n```dart\nm({a = 1})\n```\n", "sinceDartSdk": "2.0.0" @@ -2186,7 +2210,7 @@ "incompatible": [], "sets": [], "fixStatus": "needsFix", - "details": "Use `SizedBox.shrink(...)` and `SizedBox.expand(...)` constructors appropriately.\n\nThe `SizedBox.shrink(...)` and `SizedBox.expand(...)` constructors should be used\ninstead of the more general `SizedBox(...)` constructor when the named constructors\ncapture the intent of the code more succinctly.\n\n**Examples**\n\n**BAD:**\n```dart\nWidget buildLogo() {\n return SizedBox(\n height: 0,\n width: 0,\n child: const MyLogo(),\n );\n}\n```\n\n```dart\nWidget buildLogo() {\n return SizedBox(\n height: double.infinity,\n width: double.infinity,\n child: const MyLogo(),\n );\n}\n```\n\n**GOOD:**\n```dart\nWidget buildLogo() {\n return SizedBox.shrink(\n child: const MyLogo(),\n );\n}\n```\n\n```dart\nWidget buildLogo() {\n return SizedBox.expand(\n child: const MyLogo(),\n );\n}\n```\n", + "details": "Use `SizedBox.shrink(...)` and `SizedBox.expand(...)` constructors\nappropriately.\n\nEither the `SizedBox.shrink(...)` or `SizedBox.expand(...)` constructor should\nbe used instead of the more general `SizedBox(...)` constructor when one of the\nnamed constructors capture the intent of the code more succinctly.\n\n**Examples**\n\n**BAD:**\n```dart\nWidget buildLogo() {\n return SizedBox(\n height: 0,\n width: 0,\n child: const MyLogo(),\n );\n}\n```\n\n```dart\nWidget buildLogo() {\n return SizedBox(\n height: double.infinity,\n width: double.infinity,\n child: const MyLogo(),\n );\n}\n```\n\n**GOOD:**\n```dart\nWidget buildLogo() {\n return SizedBox.shrink(\n child: const MyLogo(),\n );\n}\n```\n\n```dart\nWidget buildLogo() {\n return SizedBox.expand(\n child: const MyLogo(),\n );\n}\n```\n", "sinceDartSdk": "2.16.0" }, { @@ -2291,7 +2315,11 @@ "group": "style", "state": "stable", "incompatible": [], - "sets": [], + "sets": [ + "core", + "recommended", + "flutter" + ], "fixStatus": "hasFix", "details": "If you meant to test if the object has type `Foo`, instead write `Foo _`.\n\n**BAD:**\n```dart\nvoid f(Object? x) {\n if (x case num) {\n print('int or double');\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid f(Object? x) {\n if (x case num _) {\n print('int or double');\n }\n}\n```\n\nIf you do mean to test that the matched value (which you expect to have the\ntype `Type`) is equal to the type literal `Foo`, then this lint can be\nsilenced using `const (Foo)`.\n\n**BAD:**\n```dart\nvoid f(Object? x) {\n if (x case int) {\n print('int');\n }\n}\n```\n\n**GOOD:**\n```dart\nvoid f(Object? x) {\n if (x case const (int)) {\n print('int');\n }\n}\n```\n", "sinceDartSdk": "3.0.0" @@ -2589,7 +2617,7 @@ "flutter" ], "fixStatus": "hasFix", - "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-this-when-not-needed-to-avoid-shadowing):\n\n**DON'T** use `this` when not needed to avoid shadowing.\n\n**BAD:**\n```dart\nclass Box {\n var value;\n void update(new_value) {\n this.value = new_value;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Box {\n var value;\n void update(new_value) {\n value = new_value;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Box {\n var value;\n void update(value) {\n this.value = value;\n }\n}\n```\n\n", + "details": "From [Effective Dart](https://dart.dev/effective-dart/usage#dont-use-this-when-not-needed-to-avoid-shadowing):\n\n**DON'T** use `this` when not needed to avoid shadowing.\n\n**BAD:**\n```dart\nclass Box {\n int value;\n void update(int newValue) {\n this.value = newValue;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Box {\n int value;\n void update(int newValue) {\n value = newValue;\n }\n}\n```\n\n**GOOD:**\n```dart\nclass Box {\n int value;\n void update(int value) {\n this.value = value;\n }\n}\n```\n\n", "sinceDartSdk": "2.0.0" }, { @@ -2598,7 +2626,10 @@ "group": "style", "state": "stable", "incompatible": [], - "sets": [], + "sets": [ + "recommended", + "flutter" + ], "fixStatus": "hasFix", "details": "Unnecessary `toList()` in spreads.\n\n**BAD:**\n```dart\nchildren: [\n ...['foo', 'bar', 'baz'].map((String s) => Text(s)).toList(),\n]\n```\n\n**GOOD:**\n```dart\nchildren: [\n ...['foo', 'bar', 'baz'].map((String s) => Text(s)),\n]\n```\n\n", "sinceDartSdk": "2.18.0" @@ -2610,8 +2641,8 @@ "state": "stable", "incompatible": [], "sets": [], - "fixStatus": "noFix", - "details": "Top-level members and static members in an executable library should be used\ndirectly inside this library. An executable library is a library that contains\na `main` top-level function or that contains a top-level function annotated with\n`@pragma('vm:entry-point')`). Executable libraries are not usually imported\nand it's better to avoid defining unused members.\n\nThis rule assumes that an executable library isn't imported by other files\nexcept to execute its `main` function.\n\n**BAD:**\n\n```dart\nmain() {}\nvoid f() {}\n```\n\n**GOOD:**\n\n```dart\nmain() {\n f();\n}\nvoid f() {}\n```\n\n", + "fixStatus": "hasFix", + "details": "Any member declared in an executable library should be used directly inside that\nlibrary. An executable library is a library that contains a `main` top-level\nfunction or that contains a top-level function annotated with\n`@pragma('vm:entry-point')`). Executable libraries are not usually imported\nand it's better to avoid defining unused members.\n\nThis rule assumes that an executable library isn't imported by other libraries\nexcept to execute its `main` function.\n\n**BAD:**\n\n```dart\nmain() {}\nvoid f() {}\n```\n\n**GOOD:**\n\n```dart\nmain() {\n f();\n}\nvoid f() {}\n```\n\n", "sinceDartSdk": "2.19.0" }, { @@ -2644,7 +2675,7 @@ "incompatible": [], "sets": [], "fixStatus": "hasFix", - "details": "Classes that look like enumerations should be declared as `enum`s.\n\n**DO** use enums where appropriate.\n\nCandidates for enums are classes that:\n * are concrete,\n * are private or have only private generative constructors,\n * have two or more static const fields with the same type as the class,\n * have generative constructors that are only invoked at the top-level of the\n initialization expression of these static fields,\n * do not define `hashCode`, `==`, `values` or `index`,\n * do not extend any class other than Object, and\n * have no subclasses declared in the defining library.\n\n**BAD:**\n```dart\nclass LogPriority {\n static const error = LogPriority._(1, 'Error');\n static const warning = LogPriority._(2, 'Warning');\n static const log = LogPriority._unknown('Log');\n\n final String prefix;\n final int priority;\n const LogPriority._(this.priority, this.prefix);\n const LogPriority._unknown(String prefix) : this._(-1, prefix);\n}\n```\n\n**GOOD:**\n```dart\nenum LogPriority {\n error(1, 'Error'),\n warning(2, 'Warning'),\n log.unknown('Log');\n\n final String prefix;\n final int priority;\n const LogPriority(this.priority, this.prefix);\n const LogPriority.unknown(String prefix) : this(-1, prefix);\n}\n```\n", + "details": "Classes that look like enumerations should be declared as `enum`s.\n\n**DO** use enums where appropriate.\n\nCandidates for enums are classes that:\n\n * are concrete,\n * are private or have only private generative constructors,\n * have two or more static const fields with the same type as the class,\n * have generative constructors that are only invoked at the top-level of the\n initialization expression of these static fields,\n * do not define `hashCode`, `==`, `values` or `index`,\n * do not extend any class other than `Object`, and\n * have no subclasses declared in the defining library.\n\nTo learn more about creating and using these enums, check out\n[Declaring enhanced enums](https://dart.dev/language/enums#declaring-enhanced-enums).\n\n**BAD:**\n```dart\nclass LogPriority {\n static const error = LogPriority._(1, 'Error');\n static const warning = LogPriority._(2, 'Warning');\n static const log = LogPriority._unknown('Log');\n\n final String prefix;\n final int priority;\n const LogPriority._(this.priority, this.prefix);\n const LogPriority._unknown(String prefix) : this._(-1, prefix);\n}\n```\n\n**GOOD:**\n```dart\nenum LogPriority {\n error(1, 'Error'),\n warning(2, 'Warning'),\n log.unknown('Log');\n\n final String prefix;\n final int priority;\n const LogPriority(this.priority, this.prefix);\n const LogPriority.unknown(String prefix) : this(-1, prefix);\n}\n```\n", "sinceDartSdk": "2.17.0" }, { @@ -2771,7 +2802,11 @@ "group": "style", "state": "stable", "incompatible": [], - "sets": [], + "sets": [ + "core", + "recommended", + "flutter" + ], "fixStatus": "hasFix", "details": "From [Effective Dart](https://dart.dev/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": "2.19.0" @@ -2782,7 +2817,10 @@ "group": "style", "state": "experimental", "incompatible": [], - "sets": [], + "sets": [ + "recommended", + "flutter" + ], "fixStatus": "hasFix", "details": "\"Forwarding constructor\"s, that do nothing except forward parameters to their \nsuperclass constructors should take advantage of super-initializer parameters \nrather than repeating the names of parameters when passing them to the \nsuperclass constructors. This makes the code more concise and easier to read\nand maintain.\n\n**DO** use super-initializer parameters where possible.\n\n**BAD:**\n```dart\nclass A {\n A({int? x, int? y});\n}\nclass B extends A {\n B({int? x, int? y}) : super(x: x, y: y);\n}\n```\n\n**GOOD:**\n```dart\nclass A {\n A({int? x, int? y});\n}\nclass B extends A {\n B({super.x, super.y});\n}\n```\n", "sinceDartSdk": "2.17.0" @@ -2824,4 +2862,4 @@ "details": "**DON'T** assign to void.\n\n**BAD:**\n```dart\nclass A {\n T value;\n void test(T arg) { }\n}\n\nvoid main() {\n A a = A();\n a.value = 1; // LINT\n a.test(1); // LINT\n}\n```\n", "sinceDartSdk": "2.0.0" } -] \ No newline at end of file +] diff --git a/src/_data/pkg-vers.json b/src/_data/pkg-vers.json index f4b9fbf84..952efc926 100644 --- a/src/_data/pkg-vers.json +++ b/src/_data/pkg-vers.json @@ -3,6 +3,6 @@ "doc-path": "install", "channel": "stable", "prev-vers": "2.19.6", - "vers": "3.0.7" + "vers": "3.1.5" } } diff --git a/src/_data/side-nav.yml b/src/_data/side-nav.yml index e34be50ba..48c6b62bf 100644 --- a/src/_data/side-nav.yml +++ b/src/_data/side-nav.yml @@ -334,6 +334,8 @@ children: - title: 常见问题 permalink: /resources/faq + - title: 破坏性改动 + permalink: /resources/breaking-changes - title: 版本演变 permalink: /guides/language/evolution - title: 语言规范 diff --git a/src/_guides/language/cheatsheet.md b/src/_guides/language/cheatsheet.md deleted file mode 100644 index 2fac147da..000000000 --- a/src/_guides/language/cheatsheet.md +++ /dev/null @@ -1,147 +0,0 @@ ---- -title: Dart language cheatsheet -title: Dart 语言速查表 -description: A one-page summary of some of Dart's most useful, interesting features. -description: 介绍 Dart 里最有用和有意思的特性。 ---- - -This cheatsheet is based on an internal document -created by Googler [Mehmet Fidanboylu](https://medium.com/@mehmetf_71205) -to help Google engineers remember the syntax for -some of Dart's commonly used features. -For an interactive guide to these features and more, see the -[Dart cheatsheet codelab](/codelabs/dart-cheatsheet). - -## Using literals - -### `‘Substitution ${val}’` - -Puts the value of `val` into a string literal. -Equivalent: `‘Substitution’ + val` - -### `[ ]` - -Creates an object of type `List`. - -### `const [1, 2, 3]` - -Creates a compile-time constant list. - -### `= { }` - -Initializes a map. -Equivalent: `new Map<>();` - -## Declaring fields - -| `var` | Generic `var` with type inference | -| `final` | Same as `var` but cannot be reassigned | -| `const` | Compile-time constant | -{:.table} - - -## Checking types - -| `as` | Typecast | -| `is` | instanceof | -| `is!` | !instanceof | -{:.table} - - -## Chaining method calls - -### `a..b = true..c = 5;` - -Cascade used for chaining access to methods and other members. -Equivalent: `a.b = true; a.c = 5;` - - -## Dealing with null - -### `b ??= val;` - -If `b` is null, assign the value of `val` to `b`; -otherwise, `b` stays the same. - -### `a = value ?? 0;` - -If value is null, set `a` to 0. -Otherwise, set `a` to value. - -### `a?.b` - -Conditional access. -Equivalent: `a == null ? null : a.b` - - -## Implementing functions - -### `fn({bool bold = false, bool hidden = false})` - -Named params with default values. - -### `int incr(int a) => a + 1;` - -Single return statement can be abbreviated. - -## Handling exceptions - -```dart -try {...} -on MyException {...} -catch (e) {...} -finally {...} -``` - -Use `on` to catch a type. -Use `catch` to catch an instance. - -## Implementing constructors - -### Normal constructor - -```dart -Point(this.x, this.y); -``` - -### Factory constructor - -```dart -factory Point(int x, int y) => ...; -``` - -Use `factory` when implementing a constructor that -doesn’t always create a new instance. - - -### Named constructor - -```dart -Point.fromJson(Map json) { - x = json['x']; - y = json['y']; - } -``` - -### Delegating constructor - -```dart -Point.alongXAxis(num x) : this(x, 0); -``` - -### Const constructor - -```dart -const ImmutablePoint(this.x, this.y); -``` - -Produces an object that will never change. All fields have to be final. - -### Initializer list - -```dart -Point.fromJson(Map jsonMap) - : x = jsonMap['x'], y = jsonMap['y']; -``` - -Initializer lists are handy when setting up final fields. diff --git a/src/_includes/article_summary.html b/src/_includes/article_summary.html deleted file mode 100644 index 97739a207..000000000 --- a/src/_includes/article_summary.html +++ /dev/null @@ -1,3 +0,0 @@ -

{{article.title}}

-{{ article.original-date | default: article.date | date: '%B %Y' }} {% if article.original-date %}(updated: {{ article.date | date: '%B %Y' }}){% endif %} -

{{article.description}}

diff --git a/src/_includes/author.html b/src/_includes/author.html deleted file mode 100644 index 6d8411aa0..000000000 --- a/src/_includes/author.html +++ /dev/null @@ -1,39 +0,0 @@ -
- {% if page.rel.me or page.author.twitter %} -
-

Follow {{page.author.fname}}

- -
- {% endif %} - -
-

Bio

- {{bio}} -
- - {% assign empty_list = true %} - {% for article in site.pages %} - {% if article.rel and article.rel.author == page.author.key %} - {% assign article_url = article.url | remove:'index.html' %} - {% if empty_list %} - {% assign empty_list = false %} -
-

On this site

-
    - {% endif %} -
  • {{article.title}}
  • - {% endif %} - {% endfor %} - {% if empty_list == false %} -
-
- {% endif %} - -
diff --git a/src/_includes/banner.html b/src/_includes/banner.html index d6806a95b..69250805f 100644 --- a/src/_includes/banner.html +++ b/src/_includes/banner.html @@ -1,10 +1,7 @@ diff --git a/src/_includes/breadcrumbs.html b/src/_includes/breadcrumbs.html new file mode 100644 index 000000000..b55a20b46 --- /dev/null +++ b/src/_includes/breadcrumbs.html @@ -0,0 +1,33 @@ +{% comment %} +Embeds breadcrumb RDFa, follows ARIA guidelines. References: +- https://developers.google.com/search/docs/data-types/breadcrumb +- https://schema.org/BreadcrumbList +- https://www.w3.org/TR/wai-aria-practices/examples/breadcrumb/index.html +- https://search.google.com/structured-data/testing-tool +{% endcomment %} + +{% assign url = page.url | regex_replace: '/index$|/index.html$|/$' -%} + +{% if url.size > 0 -%} + +{%- endif -%} diff --git a/src/_includes/get-sdk.md b/src/_includes/get-sdk.md index 188b68a27..4f0c2bc00 100644 --- a/src/_includes/get-sdk.md +++ b/src/_includes/get-sdk.md @@ -1,4 +1,4 @@ -Once you’re ready to move beyond DartPad and develop real apps, +Once you're ready to move beyond DartPad and develop real apps, you need an SDK. You can either download the Dart SDK directly (as described below) diff --git a/src/_includes/head.html b/src/_includes/head.html index ac8594950..5f2b79dc1 100644 --- a/src/_includes/head.html +++ b/src/_includes/head.html @@ -13,8 +13,11 @@ - - {% assign desc = page.description | default: page.excerpt | default: site.description | strip_html | strip_newlines | truncate: 160 -%} + {% assign desc = page.description | strip_html | strip_newlines | truncate: 160 -%} + {% unless desc and desc != '' -%} + {% assign error = page.url | append: ' must have a description specified!' -%} + {{ error | throw_error }} + {% endunless %} {% if page.short-title %}{{page.short-title}}{% else %}{{page.title}}{% endif %} | {{site.title}} @@ -89,9 +92,11 @@ - {% for css in page.css -%} - + {% if page.css -%} + {% for cssFile in page.css -%} + {% endfor -%} + {% endif -%} - {% for js in page.js -%} - + {% if page.js -%} + {% for jsFile in page.js -%} + {% endfor -%} + {% endif -%} {% include analytics.html %} diff --git a/src/_includes/linter-page-content.md b/src/_includes/linter-page-content.md index 5ea8547f3..d26e0128e 100644 --- a/src/_includes/linter-page-content.md +++ b/src/_includes/linter-page-content.md @@ -2,7 +2,7 @@ {{lint.description}} -{% if lint.sinceDartSdk == "Unreleased" %} +{% if lint.sinceDartSdk == "Unreleased" or lint.sinceDartSdk contains "-wip" %} _This rule is currently **experimental** and not yet available in a stable SDK._ {% elsif lint.state == "removed" %} diff --git a/src/_includes/linter-rules-section.md b/src/_includes/linter-rules-section.md index b3ab80b3d..75f54c6ab 100644 --- a/src/_includes/linter-rules-section.md +++ b/src/_includes/linter-rules-section.md @@ -1,6 +1,6 @@ {% for lint in site.data.linter_rules %} -{% if lint.group == include.type %} +{% if lint.group == include.type and lint.state != "internal" %} {% assign badges = "" %} diff --git a/src/_includes/navigation-main.html b/src/_includes/navigation-main.html index 3d436a77b..c24287f75 100644 --- a/src/_includes/navigation-main.html +++ b/src/_includes/navigation-main.html @@ -36,7 +36,7 @@ + id="search-main" autocomplete="off" placeholder="Search" aria-label="Search"> diff --git a/src/_includes/navigation-side.html b/src/_includes/navigation-side.html index 83672c447..4477c7fa5 100644 --- a/src/_includes/navigation-side.html +++ b/src/_includes/navigation-side.html @@ -1,7 +1,7 @@
@@ -28,6 +28,6 @@ - {% include shared/sidenav-level-1.html nav=site.data.side-nav %} + {% include sidenav-level-1.html nav=site.data.side-nav %}
diff --git a/src/_includes/navigation-toc.html b/src/_includes/navigation-toc.html index 6002eb2dc..f5fa4d614 100644 --- a/src/_includes/navigation-toc.html +++ b/src/_includes/navigation-toc.html @@ -12,6 +12,7 @@ {% endif %} {% if include.extendToc -%} {% assign toc = toc | underscore_breaker: true %} + {% assign toc = toc | replace: 'id="toc" ', '' %} {% assign toc = toc | replace: '
    ', '