Dart Use Path Package
Marketing & SEO7.6K installs
What it does
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…
Install
npx skills add https://github.com/flutter/agent-plugins --skill dart-use-path-packageWebsite
www.skills.sh/flutter/agent-plugins/dart-use-path-packageDetails
From the skill’s SKILL.md or README, by its authors. View the original
Safe Cross-Platform Path Manipulation in Dart
Contents
- 1. Core Principles & Cross-Platform Rules
- 2. Recommended package:path Idioms vs. String Anti-Patterns
- 3. Bridging Native Paths to POSIX, Git, & URL Contexts
- 4. Mockable File Systems (
package:filevs. Globalp.*) - 5. Extensions, Compound Extensions & Stem Extraction
- 6. Workflows & Audit Checklist
- References & Examples
1. Core Principles & Cross-Platform Rules
Avoid Treating File Paths as Raw Strings
- Native file paths on Windows use backslashes (
\), whereas macOS and Linux use forward slashes (/). - String operations like
.contains('foo/'),.startsWith('foo/'), or.split('/')silently fail on Windows native paths. - String interpolation like
'$dir/$file'injects forward slashes on Windows and produces duplicate slashes (//) when$dirends with a trailing slash.
Rule: Always decompose paths into segments using p.split(path) before inspecting directory hierarchy or segment names, and always join path components using p.join(...).
Pragmatic Boundary Joining vs. Multi-Segment Decomposition (p.join)
- Cross-Platform Libraries (Windows + POSIX): Pass individual path segments to
p.join(dir, 'sub', 'file.json')sopackage:pathinserts OS-native separators (\on Windows,/on POSIX) between every component. - POSIX-Only Tools & Static Subpath Greppability: In codebases exclusively targeting Linux/macOS (or when joining a dynamic base path to a known static subpath), decomposing 5–6 static segments into separate arguments (
p.join(home, '.local', 'share', 'app', 'bin', 'config.json')) causesdart formatto wrap across 6–8 vertical lines and destroys substring greppability (grep/code_searchfor.local/share/app/bin). - Rule for POSIX Targets: Prefer 2-argument boundary joining (
p.join(home, '.local/share/app/bin/config.json')). This prevents duplicate-slash bugs (//) at variable boundaries while preserving single-line readability and exact string searchability.
Normalization vs. Canonicalization (p.normalize vs. p.canonicalize)
p.normalize(path)resolves.and..segments purely lexically without consulting the filesystem or standardizing case.- When deduplicating directory paths or comparing physical file identity across symlinks, relative roots, or case-insensitive filesystems, use
p.canonicalize(path).
Strip Location Specifiers & Convert URIs Safely
- Strings formatted as
:-or:are not pure file paths. Passing them directly top.normalizeorUri.parsecauses bugs (on Windows,Uri.parsemistakesC:for a URI scheme and:linefor a port). - Extract the trailing
:line-colsuffix via regular expression (RegExp(r'^(.*?):(\d+(?:-\d+)?)$')) before passing the file path topackage:path. - URI Boundary Conversions: When converting between file paths and
Uriobjects, always usep.toUri(path)andp.fromUri(uri)rather thanUri.parse(path)or manual string concatenation.
2. Recommended package:path Idioms vs. String Anti-Patterns
Path Joining
- Prefer:
p.join(dir, file) - Avoid:
'$dir/$file'or'a/$b' - Why: String interpolation injects
/on Windows and creates duplicate
slashes (//) when $dir ends with a trailing separator.
Segment Matching
- Prefer:
p.split(path).contains('foo') - Avoid:
path.contains('foo/') - Why: String matching fails on Windows backslashes (
foo\bar) and produces
false positives on partial substring names (e.g. barfoo/).
Root and Directory Prefixes
- Prefer:
if (p.split(path) case ['foo', ...])(orcase ['foo', ...final rest]when extracting tail segments), orp.isWithin('foo', path) - Avoid:
path.startsWith('foo/')orp.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' - Avoid:
path.endsWith('.wasm') - Why: Substring suffix matching falsely matches directories (
foo.wasm/)
or non-extension suffixes.
Extension Slicing and Compound Extensions
- Prefer:
p.withoutExtension(path)andp.extension(path, 2) - Avoid:
path.lastIndexOf('.')and manualsubstringslicing - Why: Manual arithmetic breaks on hidden dotfiles (
.gitignore) and
compound extensions (.js.map, .tar.gz).
POSIX and URL Path Conversion
- Prefer:
p.posix.joinAll(p.split(path))orp.url.joinAll(p.split(path)) - Avoid:
path.replaceAll(r'\', '/') - Why: Ad-hoc separator replacement fails on root drives and mixes OS
context with POSIX or URL targets.
URI Conversion
- Prefer:
p.toUri(path)andp.fromUri(uri) - Avoid:
Uri.parse(path)anduri.path - Why: Direct URI parsing fails on Windows drive letters (
C:) and leaks
percent-encoding (e.g. %20 for spaces).
Directory Basename Helper
- Prefer:
String canonicalDirName(Directory d) => p.basename(p.normalize(d.absolute.path));
- Avoid: Repeating
p.basename(p.normalize(dir.absolute.path))inline
across files.
- Why: Centralizes canonical directory naming logic and reduces boilerplate.
3. Bridging Native Paths to POSIX, Git, & URL Contexts
Avoid calling .replaceAll('\\', '/') or .replaceAll(r'\', '/') to convert OS-native paths into POSIX paths (for Git, YAML, archive manifests) or URL segments.
Rule: Split the relative native path using p.split(...), inspect segments with Dart 3 list pattern matching, and join using p.posix.joinAll(...) or p.url.joinAll(...). Always call p.relative(filePath, from: root) first so leading root segments ('/' on POSIX or r'C:\' on Windows) do not interfere with relative prefix patterns:
import 'package:path/path.dart' as p;
String computeWebAssetKey(String filePath, String projectRoot) {
final relative = p.relative(filePath, from: projectRoot);
final segments = p.split(relative);
return switch (segments) {
['assets', ...] => p.posix.joinAll(segments),
_ => p.posix.joinAll(['assets', ...segments]),
};
}
Git Paths and Repository Metadata
- Git repository tree objects,
.gitignorepattern rules,.gitattributes,
and git-tracked symlinks strictly use POSIX forward slashes (/), even on Windows.
- Inserting native Windows backslashes (
\) into.gitignoreor git commands
causes Git to treat \ as an escape character rather than a directory separator, silently breaking pattern matching.
- When generating
.gitignoreentries, repository manifests, or symlink
targets programmatically from native file paths, convert the relative native path using p.posix.joinAll(p.split(relativePath)) or p.posix.join(...).
4. Mockable File Systems (package:file vs. Global p.*)
In codebases that use package:file (e.g., CLI applications or services tested with MemoryFileSystem), avoid calling top-level p.* functions on File or Directory paths.
- Top-level
p.*functions bind to the host operating system running the test. - If a unit test creates a
MemoryFileSystem(style: FileSystemStyle.windows)on a Linux or macOS runner, globalp.split(file.path)will split on/instead of\, breaking the test.
Rule: Always use the Context attached to the FileSystem (file.fileSystem.path):
import 'package:file/file.dart';
List listSubdirectoryNames(Directory dir) {
final pathContext = dir.fileSystem.path;
return dir
.listSync()
.whereType()
.map((d) => pathContext.basename(d.path))
.toList();
}
5. Extensions, Compound Extensions & Stem Extraction
Avoid manual .lastIndexOf('.') and .substring() arithmetic when extracting file extensions or inserting content hashes. p.extension natively supports multi-level extensions via its optional level parameter.
- Multi-Dot Stem Nuance: Calling
p.extension('main.dart.wasm', 2)returns'.dart.wasm'because it blindly captures the last two dot-separated segments. When hashing or stripping extensions on files that may have multi-dot stems (e.g.,main.dart.wasmvs.main.dart.js.map), check whetherp.extension(filename, 2)matches a known compound extension (or.endsWith('.map')) before falling back to single-levelp.extension(filename):
import 'package:path/path.dart' as p;
String insertContentHash(String filename, String hash) {
final compoundExt = p.extension(filename, 2);
// Only use the 2-level extension for true compound suffixes (e.g., '.js.map')
final ext = compoundExt.endsWith('.map')
? compoundExt
: p.extension(filename);
final stem = filename.substring(0, filename.length - ext.length);
return '$stem.$hash$ext';
}
6. Workflows & Audit Checklist
Path Refactoring Checklist
- [ ] Replace string interpolation (
'$dir/$file') withp.join(dir, file). - [ ] Replace
.contains('dir/')and.startsWith('dir/')withp.split(path)list pattern checks (case ['dir', ...final rest]) orp.isWithin(parent, child). - [ ] Replace
.replaceAll(r'\', '/')withp.posix.joinAll(p.split(path))(orp.url.joinAll). - [ ] Replace
.endsWith('.ext')on file paths withp.extension(path) == '.ext'. - [ ] Replace manual dot-index slicing with
p.withoutExtension(path)andp.extension(path, [level]). - [ ] Verify that code using
package:fileaccessesfileSystem.pathinstead of globalp.*. - [ ] Ensure Git paths,
.gitignoreentries, and symlink targets usep.posixforward slashes.
References & Examples
- Cross-Platform Path & POSIX Conversion Examples: examples/cross_platform_paths.dart
- Mockable FileSystem Path Context Example: examples/file_system_context.dart
More Marketing & SEO skills
See allMarketing & SEO
Find Reddit threads where people are genuinely asking for what you offer, then draft short, genuinely helpful replies — disclosing your affiliation honestly and naming your product only when it truly answers the question. Two moves: discovery — scan the right subreddits for…
1.3M installsnpx skills add https://github.com/flowkit-labs/skills --skill reddit-automationMarketing & SEO
When the user wants to audit, review, or diagnose SEO issues on their site. Also use when the user mentions "SEO audit," "technical SEO," "why am I not ranking," "SEO issues," "on-page SEO," "meta tags review," "SEO health check," "my traffic dropped," "lost rankings," "not…
249.6K installsnpx skills add https://github.com/coreyhaines31/marketingskills --skill seo-auditMarketing & SEO
When the user wants to write, rewrite, or improve marketing copy for any page, including homepage, landing pages, pricing pages, feature pages, about pages, or product pages. Also use when the user says "write copy for," "improve this copy," "rewrite this page," "marketing…
249.5K installsnpx skills add https://github.com/coreyhaines31/marketingskills --skill copywritingMarketing & SEO
When the user wants to apply psychological principles, mental models, or behavioral science to marketing. Also use when the user mentions 'psychology,' 'mental models,' 'cognitive bias,' 'persuasion,' 'behavioral science,' 'why people buy,' 'decision-making,' 'consumer…
173.8K installsnpx skills add https://github.com/coreyhaines31/marketingskills --skill marketing-psychology
Skills are shared by members and not reviewed by us. Read a skill’s code before you install it.