From 54caee3459cc86481dc9aeddb51f1940753dc688 Mon Sep 17 00:00:00 2001 From: flutter-skills-sync-bot Date: Fri, 25 Sep 2026 00:37:10 +0000 Subject: [PATCH] chore: auto-sync skills directory from dart-lang/skills --- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 2 +- .cursor-plugin/plugin.json | 2 +- skills/dart-use-path-package/SKILL.md | 16 ++++++---- .../examples/cross_platform_paths.dart | 5 ++-- skills/dart-use-pattern-matching/SKILL.md | 30 ++++++++++++++----- tool/.dart_skills_githash | 2 +- 7 files changed, 40 insertions(+), 19 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 394d55c5..e1cd87de 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "dart-flutter", "displayName": "Dart and Flutter", - "version": "1.0.5", + "version": "1.0.6", "description": "Official Claude plugin for Dart and Flutter that installs Flutter/Dart Skills and Dart MCP server for building natively compiled, visually stunning applications for mobile, web, desktop, and embedded devices from a single codebase", "author": { "name": "Dart and Flutter", diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index e1bb1feb..7369d9eb 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "dart-flutter", - "version": "1.0.5", + "version": "1.0.6", "description": "Official Codex plugin for Dart and Flutter that installs Flutter/Dart Skills and Dart MCP server for building natively compiled, visually stunning applications for mobile, web, desktop, and embedded devices from a single codebase.", "author": { "name": "Dart and Flutter", diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index 75c0050e..62aafca8 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "dart-flutter", "displayName": "Dart and Flutter", - "version": "1.0.5", + "version": "1.0.6", "description": "Official Cursor plugin for Dart and Flutter that installs Flutter/Dart Skills and Dart MCP server for building natively compiled, visually stunning applications for mobile, web, desktop, and embedded devices from a single codebase.", "author": { "name": "Dart and Flutter Team", diff --git a/skills/dart-use-path-package/SKILL.md b/skills/dart-use-path-package/SKILL.md index 4fa421bb..5f9fe324 100644 --- a/skills/dart-use-path-package/SKILL.md +++ b/skills/dart-use-path-package/SKILL.md @@ -4,7 +4,7 @@ description: >- Cross-platform file and directory path manipulation, segment splitting, extension extraction, and context conversion using `package:path` and `package:file`. Use when writing, inspecting, joining, splitting, or refactoring file paths, directory names, or extensions, or replacing raw string path operations (`.split('/')`, `'$dir/$file'`, `.endsWith('.ext')`, `.replaceAll('\\', '/')`). Don't use for HTTP network URI routing, database query strings, or non-path string processing. metadata: model: models/gemini-3.1-pro-preview - last_modified: Sun, 06 Sep 2026 07:14:00 GMT + last_modified: Wed, 23 Sep 2026 22:10:00 GMT --- # Safe Cross-Platform Path Manipulation in Dart @@ -60,10 +60,14 @@ metadata: false positives on partial substring names (e.g. `barfoo/`). ### Root and Directory Prefixes -* **Prefer**: `p.split(path).first == 'foo'` or `p.isWithin('foo', path)` -* **Avoid**: `path.startsWith('foo/')` -* **Why**: Fails on Windows separators and misses relative prefix variants such - as `./foo/`. +* **Prefer**: `if (p.split(path) case ['foo', ...])` (or `case ['foo', ...final rest]` when extracting tail segments), or `p.isWithin('foo', path)` +* **Avoid**: `path.startsWith('foo/')` or `p.split(path).first == 'foo'` +* **Why**: String prefix matching fails on Windows separators (`foo\bar`). Calling + `p.split(path).first` throws a `StateError` on empty lists and requires + separate `.skip(1)` slicing, whereas list patterns safely check non-emptiness, + match multi-segment prefixes, and optionally bind `...final rest` in a single + step. When unnormalized relative prefixes like `./foo/bar` may appear, use + `p.isWithin('foo', path)` (or `p.split(p.normalize(path))`). ### File Extensions * **Prefer**: `p.extension(path) == '.wasm'` @@ -188,7 +192,7 @@ String insertContentHash(String filename, String hash) { ### Path Refactoring Checklist - [ ] Replace string interpolation (`'$dir/$file'`) with `p.join(dir, file)`. -- [ ] Replace `.contains('dir/')` and `.startsWith('dir/')` with `p.split(path)` segment checks or `p.isWithin(parent, child)`. +- [ ] Replace `.contains('dir/')` and `.startsWith('dir/')` with `p.split(path)` list pattern checks (`case ['dir', ...final rest]`) or `p.isWithin(parent, child)`. - [ ] Replace `.replaceAll(r'\', '/')` with `p.posix.joinAll(p.split(path))` (or `p.url.joinAll`). - [ ] Replace `.endsWith('.ext')` on file paths with `p.extension(path) == '.ext'`. - [ ] Replace manual dot-index slicing with `p.withoutExtension(path)` and `p.extension(path, [level])`. diff --git a/skills/dart-use-path-package/examples/cross_platform_paths.dart b/skills/dart-use-path-package/examples/cross_platform_paths.dart index 3b416d40..41fa32fe 100644 --- a/skills/dart-use-path-package/examples/cross_platform_paths.dart +++ b/skills/dart-use-path-package/examples/cross_platform_paths.dart @@ -39,7 +39,8 @@ String toGitPath(String relativeNativePath) => p.posix.joinAll(p.split(relativeNativePath)); void main() { - print('Git path: ${toGitPath(r'lib\src\file.dart')}'); - print('Asset key: ${computeWebAssetKey('assets/icon.png', '.')}'); + final nativeSamplePath = p.join('lib', 'src', 'file.dart'); + print('Git path: ${toGitPath(nativeSamplePath)}'); + print('Asset key: ${computeWebAssetKey(p.join('assets', 'icon.png'), '.')}'); print('Content hash: ${insertContentHash('main.dart.js.map', 'a1b2c3')}'); } diff --git a/skills/dart-use-pattern-matching/SKILL.md b/skills/dart-use-pattern-matching/SKILL.md index 72b0b0e1..a60a5aa8 100644 --- a/skills/dart-use-pattern-matching/SKILL.md +++ b/skills/dart-use-pattern-matching/SKILL.md @@ -4,13 +4,13 @@ description: >- Applies Dart 3 pattern matching, switch expressions, and destructuring idiomatically to validate data schemas, handle algebraic data types, and decompose control flow. Use when refactoring complex if-else chains, - parsing polymorphic JSON or API responses, destructuring Records or Maps, or - enforcing exhaustiveness on sealed classes. Don't use for simple boolean - conditions, single-variable type promotion (use `is`), or basic collection - filtering. + parsing polymorphic JSON or API responses, destructuring Lists, URI/path + segments, String.split() tokens, Records, or Maps, or enforcing exhaustiveness + on sealed classes. Don't use for simple boolean conditions, single-variable + type promotion (use `is`), or basic collection filtering. metadata: model: models/gemini-3.1-pro-preview - last_modified: Sun, 06 Sep 2026 06:43:00 GMT + last_modified: Wed, 23 Sep 2026 22:10:00 GMT --- # Implementing Dart Patterns @@ -27,6 +27,7 @@ metadata: Apply specific pattern types based on the data structure and desired outcome. Follow these conditional guidelines: * **If validating and extracting from deserialized data (e.g., JSON):** Use Map, List, and Object patterns to validate schema structure and destructure properties in a single step. +* **If inspecting URL/path segments (`uri.pathSegments`, `p.split(path)`) or `String.split()` tokens:** Use List patterns with rest elements (`['api', 'comments', ...]`, `['assets', ...final rest]`, `[..., final parent, _]`) instead of manual `.length` checks, `.first`, `.skip(1)`, or `length - N` index arithmetic. * **If handling polymorphic payloads or responses:** Use `switch` expressions over map discriminant keys to deserialize into `sealed` class hierarchies. * **If handling multiple return values:** Use Record patterns to destructure fields directly into local variables. * **If executing type-specific behavior (Algebraic Data Types):** Use Object patterns combined with `sealed` classes to ensure exhaustiveness. @@ -147,10 +148,10 @@ Use standard boolean operators (`if (code >= 200 && code < 300)`) instead of `if ### Task Progress: Implementing Pattern Matching Copy this checklist to track progress when implementing complex pattern matching logic: -- [ ] Identify the data structure being evaluated (JSON, Record, Class, Enum). +- [ ] Identify the data structure being evaluated (JSON, List/Segments, Record, Class, Enum). - [ ] Select the appropriate switch construct (Expression for values, Statement for side-effects). - [ ] Define the required patterns (Object, Map, List, Record). -- [ ] Extract required data using Variable patterns (`var x`, `:var y`). +- [ ] Extract required data using Variable patterns (`var x`, `:var y`, `...final rest`). - [ ] Apply Guard clauses (`when condition`) for logic that cannot be expressed via patterns. - [ ] Handle unmatched cases using a Wildcard (`_`) or `default` clause (if not using a sealed class). - [ ] Run static analyzer for exhaustiveness and dead code (`dart analyze`). @@ -189,6 +190,21 @@ might be omitted entirely from the payload (rather than explicitly passed as `'key': null`), destructure required keys via the pattern and extract optional fields directly from the matched submap. +### List and Path Segment Destructuring +Use `if-case` with list rest elements (`...final rest`) to validate prefixes and +extract remaining elements without a 2-arm `_ => null` switch or manual `.first` +and `.skip(1)` indexing. + +```dart +String? resolveAllowedAssetSubpath(List segments) { + if (segments case ['assets', ...final rest] + when rest.isNotEmpty && !rest.contains('..')) { + return rest.join('/'); + } + return null; +} +``` + ### Algebraic Data Types (Sealed Classes) Use Object patterns with switch expressions to handle family types exhaustively. diff --git a/tool/.dart_skills_githash b/tool/.dart_skills_githash index 9f49c51e..192089b7 100644 --- a/tool/.dart_skills_githash +++ b/tool/.dart_skills_githash @@ -1 +1 @@ -26b2dcc5654cbbc3b2ec56ea94719469bc8bae9e +82a49602fe18cecfe41859592af600cb9d875e40