diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index 311a09affd437aab19b3c39990fb20b4d5ae9429..39b8052e74c4e163e45e84ce03ddd28f777dcbdc 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-b4bfd459865a8d636f26aca0d330ae297c006c3c
+f6344b75dcf861d8bf1f1322780b8811f982e31a
diff --git a/dartdoc_options.yaml b/dartdoc_options.yaml
index fc6bafd1bd7345cbd31b524701e3171bf9a274db..204755d6a4a691a98558c227f43320ddc0f8a2d0 100644
--- a/dartdoc_options.yaml
+++ b/dartdoc_options.yaml
@@ -5,13 +5,13 @@ dartdoc:
   # The dev/bots/docs.sh script does this automatically.
   tools:
     snippet:
-      command: ["bin/cache/dart-sdk/bin/dart", "pub", "global", "run", "snippets", "--output-directory=doc/snippets", "--type=snippet"]
+      command: ["bin/cache/artifacts/snippets/snippets", "--output-directory=doc/snippets", "--type=snippet"]
       description: "Creates sample code documentation output from embedded documentation samples."
     sample:
-      command: ["bin/cache/dart-sdk/bin/dart", "pub", "global", "run", "snippets", "--output-directory=doc/snippets", "--type=sample"]
+      command: ["bin/cache/artifacts/snippets/snippets", "--output-directory=doc/snippets", "--type=sample"]
       description: "Creates full application sample code documentation output from embedded documentation samples."
     dartpad:
-      command: ["bin/cache/dart-sdk/bin/dart", "pub", "global", "run", "snippets", "--output-directory=doc/snippets", "--type=dartpad"]
+      command: ["bin/cache/artifacts/snippets/snippets", "--output-directory=doc/snippets", "--type=dartpad"]
       description: "Creates full application sample code documentation output from embedded documentation samples and displays it in an embedded DartPad."
   errors:
     ## Default errors of dartdoc:
diff --git a/dev/bots/docs.sh b/dev/bots/docs.sh
index e82ed0b1a4f4dea2344f8dc3e836c6386139dfc4..a91cc0086e50a0efdd231ab6d410daf45afbbd26 100755
--- a/dev/bots/docs.sh
+++ b/dev/bots/docs.sh
@@ -107,16 +107,25 @@ function parse_args() {
   fi
 }
 
+function build_snippets_tool() (
+  local snippets_dir="$FLUTTER_ROOT/dev/snippets"
+  local output_dir="$FLUTTER_BIN/cache/artifacts/snippets"
+  echo "Building snippets tool executable."
+  command cd "$snippets_dir"
+  mkdir -p "$output_dir"
+  dart pub get
+  dart compile exe -o "$output_dir/snippets" bin/snippets.dart
+)
+
 function generate_docs() {
     # Install and activate dartdoc.
     # When updating to a new dartdoc version, please also update
     # `dartdoc_options.yaml` to include newly introduced error and warning types.
     "$DART" pub global activate dartdoc 8.0.6
 
-    # Install and activate the snippets tool, which resides in the
-    # assets-for-api-docs repo:
-    # https://github.com/flutter/assets-for-api-docs/tree/main/packages/snippets
-    "$DART" pub global activate snippets 0.4.3
+    # Build and install the snippets tool, which resides in
+    # the dev/docs/snippets directory.
+    build_snippets_tool
 
     # This script generates a unified doc set, and creates
     # a custom index.html, placing everything into DOC_DIR.
diff --git a/dev/snippets/README.md b/dev/snippets/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ce1f731f1d3002c634b3446e8a9b76396fcf1797
--- /dev/null
+++ b/dev/snippets/README.md
@@ -0,0 +1,204 @@
+# Dartdoc Sample Generation
+
+The Flutter API documentation contains code blocks that help provide context or
+a good starting point when learning to use any of Flutter's APIs.
+
+To generate these code blocks, Flutter uses dartdoc tools to turn documentation
+in the source code into API documentation, as seen on [https://api.flutter.dev/]
+
+## Table of Contents
+
+- [Types of code blocks](#types-of-code-blocks)
+  - [Snippet tool](#snippet-tool)
+  - [Sample tool](#sample-tool)
+- [Skeletons](#skeletons)
+- [Test Doc Generation Workflow](#test-doc-generation-workflow)
+
+## Types of code blocks
+
+There are three kinds of code blocks.
+
+- A `snippet`, which is a more or less context-free code snippet that we
+  magically determine how to analyze.
+
+- A `dartpad` sample, which gets placed into a full-fledged application, and can
+  be executed inline in the documentation on the web page using
+  DartPad.
+
+- A `sample`, which gets placed into a full-fledged application, but isn't
+  placed into DartPad in the documentation because it doesn't make sense to do
+  so.
+
+Ideally, every sample is a DartPad sample, but some samples don't have any visual
+representation and some just don't make sense that way (for example, sample
+code for setting the system UI's notification area color on Android won't do
+anything on the web).
+
+### Snippet Tool
+
+![Code snippet image](assets/code_snippet.png)
+
+The code `snippet` tool generates a block containing a description and example
+code. Here is an example of the code `snippet` tool in use:
+
+```dart
+/// {@tool snippet}
+///
+/// If the avatar is to have an image, the image should be specified in the
+/// [backgroundImage] property:
+///
+/// ```dart
+/// CircleAvatar(
+///   backgroundImage: NetworkImage(userAvatarUrl),
+/// )
+/// ```
+/// {@end-tool}
+```
+
+This will generate sample code that can be copied to the clipboard and added to
+existing applications.
+
+This uses the skeleton for `snippet` snippets when generating the HTML to put
+into the Dart docs. You can find this [template in the Flutter
+repo](https://github.com/flutter/flutter/blob/main/dev/snippets/config/skeletons/snippet.html).
+
+#### Analysis
+
+The
+[`analyze_sample_code.dart`](https://github.com/flutter/flutter/blob/main/dev/bots/analyze_sample_code.dart)
+script finds code inside the `@tool
+snippet` sections and uses the Dart analyzer to check them.
+
+There are several kinds of sample code you can specify:
+
+- Constructor calls, typically showing what might exist in a build method. These
+  will be inserted into an assignment expression assigning to a variable of type
+  "dynamic" and followed by a semicolon, for analysis.
+
+- Class definitions. These start with "class", and are analyzed verbatim.
+
+- Other code. It gets included verbatim, though any line that says `// ...` is
+  considered to separate the block into multiple blocks to be processed
+  individually.
+
+The above means that it's tricky to include verbatim imperative code (e.g. a
+call to a method) since it won't be valid to have such code at the top level.
+Instead, wrap it in a function or even a whole class, or make it a valid
+variable declaration.
+
+You can declare code that should be included in the analysis but not shown in
+the API docs by adding a comment "// Examples can assume:" to the file (usually
+at the top of the file, after the imports), following by one or more
+commented-out lines of code. That code is included verbatim in the analysis. For
+example:
+
+```dart
+// Examples can assume:
+// final BuildContext context;
+// final String userAvatarUrl;
+```
+
+You can assume that the entire Flutter framework and most common
+`dart:*` packages are imported and in scope; `dart:math` as `math` and
+`dart:ui` as `ui`.
+
+### Sample Tool
+
+![Code sample image](assets/code_sample.png)
+
+The code `sample` and `dartpad` tools can expand sample code into full Flutter
+applications. These sample applications can be directly copied and used to
+demonstrate the API's functionality in a sample application, or used with the
+`flutter create` command to create a local project with the sample code. The
+`dartpad` samples are embedded into the API docs web page and are live
+applications in the API documentation.
+
+This uses the skeleton for [application](https://github.com/flutter/flutter/blob/main/dev/snippets/config/skeletons/sample.html)
+snippets in the Flutter repo.
+
+The `sample` and `dartpad` tools also allow for quick Flutter app generation
+using the following command:
+
+```bash
+flutter create --sample=[directory.File.sampleNumber] [name_of_project_directory]
+```
+
+This command is displayed as part of the sample in the API docs.
+
+#### Sample Analysis
+
+The [`../bots/analyze_sample_code.dart`](../bots/analyze_sample_code.dart)
+script finds code inside the `@tool sample` sections and uses the Dart analyzer
+to check the sample code.
+
+## Skeletons
+
+A skeleton (concerning this tool) is an HTML template into which the Dart
+code blocks and descriptions are interpolated.
+
+There is currently one skeleton for
+[application](https://github.com/flutter/flutter/blob/main/dev/snippets/config/skeletons/sample.html)
+samples, one for
+[dartpad](https://github.com/flutter/flutter/blob/main/dev/snippets/config/skeletons/dartpad-sample.html),
+and one for
+[snippet](https://github.com/flutter/flutter/blob/main/dev/snippets/config/skeletons/snippet.html)
+code samples, but there could be more.
+
+Skeletons use mustache notation (e.g. `{{code}}`) to mark where components will
+be interpolated into the template. It doesn't use the mustache
+package since these are simple string substitutions, but it uses the same
+syntax.
+
+The code block generation tools that process the source input and emit HTML for
+output, which dartdoc places back into the documentation. Any options given to
+the `{@tool ...}` directive are passed on verbatim to the tool.
+
+The `snippets` tool renders these examples through a combination of markdown
+and HTML using the `{@inject-html}` dartdoc directive.
+
+## Test Doc Generation Workflow
+
+If you are making changes to an existing code block or are creating a new code
+block, follow these steps to generate a local copy of the API docs and verify
+that your code blocks are showing up correctly:
+
+1. Make an update to a code block or create a new code block.
+2. From the root directory, run `./dev/bots/docs.sh`. This should start
+   generating a local copy of the API documentation.
+   Supplying the "--output" argument allows you to specify the output zip file
+   for the completed documentation. Defaults to `api_docs.zip`` in the current
+   directory.
+3. Once complete, unzip the files to the desired location and open the `index.html`
+   within.
+
+Note that generating the sample output will not allow you to run your code in
+DartPad, because DartPad pulls the code it runs from the appropriate docs server
+(main or stable).
+
+Copy the generated code and paste it into a regular DartPad instance to test if
+it runs in DartPad. To get the code that will be produced by your documentation
+changes, run sample analysis locally (see the next section) and paste the output
+into a DartPad at [https://dartpad.dartlang.org].
+
+## Running sample analysis locally
+
+If all you want to do is analyze the sample code you have written locally, then
+generating the entire docs output takes a long time.
+
+Instead, you can run the analysis locally with this command from the Flutter root:
+
+```bash
+TMPDIR=/tmp bin/cache/dart-sdk/bin/dart dev/bots/analyze_sample_code.dart --temp=samples
+```
+
+This will analyze the samples, and leave the generated files in `/tmp/samples`
+
+You can find the sample you are working on in `/tmp/samples`. It is named using the
+path to the file it is in, and the line of the file that the `{@tool ...}` directive
+is on.
+
+For example, the file `sample.src.widgets.animated_list.52.dart` points to the sample
+in `packages/flutter/src/widgets/animated_list.dart` at line 52. You can then take the
+contents of that file, and paste it into [Dartpad](https://dartpad.dev) and see if it
+works. If the sample relies on new features that have just landed, it may not work
+until the features make it into the `dev` branch.
diff --git a/dev/snippets/bin/snippets.dart b/dev/snippets/bin/snippets.dart
new file mode 100644
index 0000000000000000000000000000000000000000..eb73a4b8ffb1b9f77ac3b4029f1da87b5bea6204
--- /dev/null
+++ b/dev/snippets/bin/snippets.dart
@@ -0,0 +1,286 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:io' show ProcessResult, exitCode, stderr;
+
+import 'package:args/args.dart';
+import 'package:file/file.dart';
+import 'package:file/local.dart';
+import 'package:path/path.dart' as path;
+import 'package:platform/platform.dart';
+import 'package:process/process.dart';
+import 'package:snippets/snippets.dart';
+
+const String _kElementOption = 'element';
+const String _kFormatOutputOption = 'format-output';
+const String _kHelpOption = 'help';
+const String _kInputOption = 'input';
+const String _kLibraryOption = 'library';
+const String _kOutputDirectoryOption = 'output-directory';
+const String _kOutputOption = 'output';
+const String _kPackageOption = 'package';
+const String _kSerialOption = 'serial';
+const String _kTypeOption = 'type';
+
+class GitStatusFailed implements Exception {
+  GitStatusFailed(this.gitResult);
+
+  final ProcessResult gitResult;
+
+  @override
+  String toString() {
+    return 'git status exited with a non-zero exit code: '
+        '${gitResult.exitCode}:\n${gitResult.stderr}\n${gitResult.stdout}';
+  }
+}
+
+/// A singleton filesystem that can be set by tests to a memory filesystem.
+FileSystem filesystem = const LocalFileSystem();
+
+/// A singleton snippet generator that can be set by tests to a mock, so that
+/// we can test the command line parsing.
+SnippetGenerator snippetGenerator = SnippetGenerator();
+
+/// A singleton platform that can be set by tests for use in testing command line
+/// parsing.
+Platform platform = const LocalPlatform();
+
+/// A singleton process manager that can be set by tests for use in testing.
+ProcessManager processManager = const LocalProcessManager();
+
+/// Get the name of the channel these docs are from.
+///
+/// First check env variable LUCI_BRANCH, then refer to the currently
+/// checked out git branch.
+String getChannelName({
+  Platform platform = const LocalPlatform(),
+  ProcessManager processManager = const LocalProcessManager(),
+}) {
+  final String? envReleaseChannel = platform.environment['LUCI_BRANCH']?.trim();
+  if (<String>['master', 'stable', 'main'].contains(envReleaseChannel)) {
+    // Backward compatibility: Still support running on "master", but pretend it is "main".
+    if (envReleaseChannel == 'master') {
+      return 'main';
+    }
+    return envReleaseChannel!;
+  }
+
+  final RegExp gitBranchRegexp = RegExp(r'^## (?<branch>.*)');
+  final ProcessResult gitResult = processManager.runSync(
+      <String>['git', 'status', '-b', '--porcelain'],
+      // Use the FLUTTER_ROOT, if defined.
+      workingDirectory: platform.environment['FLUTTER_ROOT']?.trim() ??
+          filesystem.currentDirectory.path,
+      // Adding extra debugging output to help debug why git status inexplicably fails
+      // (random non-zero error code) about 2% of the time.
+      environment: <String, String>{'GIT_TRACE': '2', 'GIT_TRACE_SETUP': '2'});
+  if (gitResult.exitCode != 0) {
+    throw GitStatusFailed(gitResult);
+  }
+
+  final RegExpMatch? gitBranchMatch = gitBranchRegexp
+      .firstMatch((gitResult.stdout as String).trim().split('\n').first);
+  return gitBranchMatch == null
+      ? '<unknown>'
+      : gitBranchMatch.namedGroup('branch')!.split('...').first;
+}
+
+const List<String> sampleTypes = <String>[
+  'snippet',
+  'sample',
+  'dartpad',
+];
+
+// This is a hack to workaround the fact that git status inexplicably fails
+// (with random non-zero error code) about 2% of the time.
+String getChannelNameWithRetries({
+  Platform platform = const LocalPlatform(),
+  ProcessManager processManager = const LocalProcessManager(),
+}) {
+  int retryCount = 0;
+
+  while (retryCount < 2) {
+    try {
+      return getChannelName(platform: platform, processManager: processManager);
+    } on GitStatusFailed catch (e) {
+      retryCount += 1;
+      stderr.write(
+          'git status failed, retrying ($retryCount)\nError report:\n$e');
+    }
+  }
+
+  return getChannelName(platform: platform, processManager: processManager);
+}
+
+/// Generates snippet dartdoc output for a given input, and creates any sample
+/// applications needed by the snippet.
+void main(List<String> argList) {
+  final Map<String, String> environment = platform.environment;
+  final ArgParser parser = ArgParser();
+
+  parser.addOption(
+    _kTypeOption,
+    defaultsTo: 'dartpad',
+    allowed: sampleTypes,
+    allowedHelp: <String, String>{
+      'dartpad':
+          'Produce a code sample application for using in Dartpad.',
+      'sample':
+          'Produce a code sample application.',
+      'snippet':
+          'Produce a nicely formatted piece of sample code.',
+    },
+    help: 'The type of snippet to produce.',
+  );
+  parser.addOption(
+    _kOutputOption,
+    help: 'The output name for the generated sample application. Overrides '
+        'the naming generated by the --$_kPackageOption/--$_kLibraryOption/--$_kElementOption '
+        'arguments. Metadata will be written alongside in a .json file. '
+        'The basename of this argument is used as the ID. If this is a '
+        'relative path, will be placed under the --$_kOutputDirectoryOption location.',
+  );
+  parser.addOption(
+    _kOutputDirectoryOption,
+    defaultsTo: '.',
+    help: 'The output path for the generated sample application.',
+  );
+  parser.addOption(
+    _kInputOption,
+    defaultsTo: environment['INPUT'],
+    help: 'The input file containing the sample code to inject.',
+  );
+  parser.addOption(
+    _kPackageOption,
+    defaultsTo: environment['PACKAGE_NAME'],
+    help: 'The name of the package that this sample belongs to.',
+  );
+  parser.addOption(
+    _kLibraryOption,
+    defaultsTo: environment['LIBRARY_NAME'],
+    help: 'The name of the library that this sample belongs to.',
+  );
+  parser.addOption(
+    _kElementOption,
+    defaultsTo: environment['ELEMENT_NAME'],
+    help: 'The name of the element that this sample belongs to.',
+  );
+  parser.addOption(
+    _kSerialOption,
+    defaultsTo: environment['INVOCATION_INDEX'],
+    help: 'A unique serial number for this snippet tool invocation.',
+  );
+  parser.addFlag(
+    _kFormatOutputOption,
+    defaultsTo: true,
+    help: 'Applies the Dart formatter to the published/extracted sample code.',
+  );
+  parser.addFlag(
+    _kHelpOption,
+    negatable: false,
+    help: 'Prints help documentation for this command',
+  );
+
+  final ArgResults args = parser.parse(argList);
+
+  if (args[_kHelpOption]! as bool) {
+    stderr.writeln(parser.usage);
+    exitCode = 0;
+    return;
+  }
+
+  final String sampleType = args[_kTypeOption]! as String;
+
+  if (args[_kInputOption] == null) {
+    stderr.writeln(parser.usage);
+    errorExit(
+        'The --$_kInputOption option must be specified, either on the command '
+        'line, or in the INPUT environment variable.');
+    return;
+  }
+
+  final File input = filesystem.file(args['input']! as String);
+  if (!input.existsSync()) {
+    errorExit('The input file ${input.path} does not exist.');
+    return;
+  }
+
+  final bool formatOutput = args[_kFormatOutputOption]! as bool;
+  final String packageName = args[_kPackageOption] as String? ?? '';
+  final String libraryName = args[_kLibraryOption] as String? ?? '';
+  final String elementName = args[_kElementOption] as String? ?? '';
+  final String serial = args[_kSerialOption] as String? ?? '';
+  late String id;
+  File? output;
+  final Directory outputDirectory =
+      filesystem.directory(args[_kOutputDirectoryOption]! as String).absolute;
+
+  if (args[_kOutputOption] != null) {
+    id = path.basenameWithoutExtension(args[_kOutputOption]! as String);
+    final File outputPath = filesystem.file(args[_kOutputOption]! as String);
+    if (outputPath.isAbsolute) {
+      output = outputPath;
+    } else {
+      output =
+          filesystem.file(path.join(outputDirectory.path, outputPath.path));
+    }
+  } else {
+    final List<String> idParts = <String>[];
+    if (packageName.isNotEmpty && packageName != 'flutter') {
+      idParts.add(packageName.replaceAll(RegExp(r'\W'), '_').toLowerCase());
+    }
+    if (libraryName.isNotEmpty) {
+      idParts.add(libraryName.replaceAll(RegExp(r'\W'), '_').toLowerCase());
+    }
+    if (elementName.isNotEmpty) {
+      idParts.add(elementName);
+    }
+    if (serial.isNotEmpty) {
+      idParts.add(serial);
+    }
+    if (idParts.isEmpty) {
+      errorExit('Unable to determine ID. At least one of --$_kPackageOption, '
+          '--$_kLibraryOption, --$_kElementOption, -$_kSerialOption, or the environment variables '
+          'PACKAGE_NAME, LIBRARY_NAME, ELEMENT_NAME, or INVOCATION_INDEX must be non-empty.');
+      return;
+    }
+    id = idParts.join('.');
+    output = outputDirectory.childFile('$id.dart');
+  }
+  output.parent.createSync(recursive: true);
+
+  final int? sourceLine = environment['SOURCE_LINE'] != null
+      ? int.tryParse(environment['SOURCE_LINE']!)
+      : null;
+  final String sourcePath = environment['SOURCE_PATH'] ?? 'unknown.dart';
+  final SnippetDartdocParser sampleParser = SnippetDartdocParser(filesystem);
+  final SourceElement element = sampleParser.parseFromDartdocToolFile(
+    input,
+    startLine: sourceLine,
+    element: elementName,
+    sourceFile: filesystem.file(sourcePath),
+    type: sampleType,
+  );
+  final Map<String, Object?> metadata = <String, Object?>{
+    'channel': getChannelNameWithRetries(
+        platform: platform, processManager: processManager),
+    'serial': serial,
+    'id': id,
+    'package': packageName,
+    'library': libraryName,
+    'element': elementName,
+  };
+
+  for (final CodeSample sample in element.samples) {
+    sample.metadata.addAll(metadata);
+    snippetGenerator.generateCode(
+      sample,
+      output: output,
+      formatOutput: formatOutput,
+    );
+    print(snippetGenerator.generateHtml(sample));
+  }
+
+  exitCode = 0;
+}
diff --git a/dev/snippets/lib/snippets.dart b/dev/snippets/lib/snippets.dart
new file mode 100644
index 0000000000000000000000000000000000000000..116ae7970b4ec2c4bcf65a021f9307081f7e99d5
--- /dev/null
+++ b/dev/snippets/lib/snippets.dart
@@ -0,0 +1,11 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export 'src/analysis.dart';
+export 'src/configuration.dart';
+export 'src/data_types.dart';
+export 'src/import_sorter.dart';
+export 'src/snippet_generator.dart';
+export 'src/snippet_parser.dart';
+export 'src/util.dart';
diff --git a/dev/snippets/lib/src/analysis.dart b/dev/snippets/lib/src/analysis.dart
new file mode 100644
index 0000000000000000000000000000000000000000..73a871ae427840c40e4b5dec024fed6bab5d7c3c
--- /dev/null
+++ b/dev/snippets/lib/src/analysis.dart
@@ -0,0 +1,361 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/utilities.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/file_system/file_system.dart' as afs;
+import 'package:analyzer/file_system/physical_file_system.dart' as afs;
+import 'package:analyzer/source/line_info.dart';
+import 'package:file/file.dart';
+
+import 'data_types.dart';
+import 'util.dart';
+
+/// Gets an iterable over all of the blocks of documentation comments in a file
+/// using the analyzer.
+///
+/// Each entry in the list is a list of source lines corresponding to the
+/// documentation comment block.
+Iterable<List<SourceLine>> getFileDocumentationComments(File file) {
+  return getDocumentationComments(getFileElements(file));
+}
+
+/// Gets an iterable over all of the blocks of documentation comments from an
+/// iterable over the [SourceElement]s involved.
+Iterable<List<SourceLine>> getDocumentationComments(
+    Iterable<SourceElement> elements) {
+  return elements
+      .where((SourceElement element) => element.comment.isNotEmpty)
+      .map<List<SourceLine>>((SourceElement element) => element.comment);
+}
+
+/// Gets an iterable over the comment [SourceElement]s in a file.
+Iterable<SourceElement> getFileCommentElements(File file) {
+  return getCommentElements(getFileElements(file));
+}
+
+/// Filters the source `elements` to only return the comment elements.
+Iterable<SourceElement> getCommentElements(Iterable<SourceElement> elements) {
+  return elements.where((SourceElement element) => element.comment.isNotEmpty);
+}
+
+/// Reads the file content from a string, to avoid having to read the file more
+/// than once if the caller already has the content in memory.
+///
+/// The `file` argument is used to tag the lines with a filename that they came from.
+Iterable<SourceElement> getElementsFromString(String content, File file) {
+  final ParseStringResult parseResult = parseString(
+      featureSet: FeatureSet.fromEnableFlags2(
+        sdkLanguageVersion: FlutterInformation.instance.getDartSdkVersion(),
+        flags: <String>[],
+      ),
+      content: content);
+  final _SourceVisitor<CompilationUnit> visitor =
+      _SourceVisitor<CompilationUnit>(file);
+  visitor.visitCompilationUnit(parseResult.unit);
+  visitor.assignLineNumbers();
+  return visitor.elements;
+}
+
+/// Gets an iterable over the [SourceElement]s in the given `file`.
+///
+/// Takes an optional [ResourceProvider] to allow reading from a memory
+/// filesystem.
+Iterable<SourceElement> getFileElements(File file,
+    {afs.ResourceProvider? resourceProvider}) {
+  resourceProvider ??= afs.PhysicalResourceProvider.INSTANCE;
+  final ParseStringResult parseResult = parseFile(
+      featureSet: FeatureSet.fromEnableFlags2(
+        sdkLanguageVersion: FlutterInformation.instance.getDartSdkVersion(),
+        flags: <String>[],
+      ),
+      path: file.absolute.path,
+      resourceProvider: resourceProvider);
+  final _SourceVisitor<CompilationUnit> visitor =
+      _SourceVisitor<CompilationUnit>(file);
+  visitor.visitCompilationUnit(parseResult.unit);
+  visitor.assignLineNumbers();
+  return visitor.elements;
+}
+
+class _SourceVisitor<T> extends RecursiveAstVisitor<T> {
+  _SourceVisitor(this.file) : elements = <SourceElement>{};
+
+  final Set<SourceElement> elements;
+  String enclosingClass = '';
+
+  File file;
+
+  void assignLineNumbers() {
+    final String contents = file.readAsStringSync();
+    final LineInfo lineInfo = LineInfo.fromContent(contents);
+
+    final Set<SourceElement> removedElements = <SourceElement>{};
+    final Set<SourceElement> replacedElements = <SourceElement>{};
+    for (final SourceElement element in elements) {
+      final List<SourceLine> newLines = <SourceLine>[];
+      for (final SourceLine line in element.comment) {
+        final CharacterLocation intervalLine =
+            lineInfo.getLocation(line.startChar);
+        newLines.add(line.copyWith(line: intervalLine.lineNumber));
+      }
+      final int elementLine = lineInfo.getLocation(element.startPos).lineNumber;
+      replacedElements
+          .add(element.copyWith(comment: newLines, startLine: elementLine));
+      removedElements.add(element);
+    }
+    elements.removeAll(removedElements);
+    elements.addAll(replacedElements);
+  }
+
+  List<SourceLine> _processComment(String element, Comment comment) {
+    final List<SourceLine> result = <SourceLine>[];
+    if (comment.tokens.isNotEmpty) {
+      for (final Token token in comment.tokens) {
+        result.add(SourceLine(
+          token.toString(),
+          element: element,
+          file: file,
+          startChar: token.charOffset,
+          endChar: token.charEnd,
+        ));
+      }
+    }
+    return result;
+  }
+
+  @override
+  T? visitCompilationUnit(CompilationUnit node) {
+    elements.clear();
+    return super.visitCompilationUnit(node);
+  }
+
+  static bool isPublic(String name) {
+    return !name.startsWith('_');
+  }
+
+  static bool isInsideMethod(AstNode startNode) {
+    AstNode? node = startNode.parent;
+    while (node != null) {
+      if (node is MethodDeclaration) {
+        return true;
+      }
+      node = node.parent;
+    }
+    return false;
+  }
+
+  @override
+  T? visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+    for (final VariableDeclaration declaration in node.variables.variables) {
+      if (!isPublic(declaration.name.lexeme)) {
+        continue;
+      }
+      List<SourceLine> comment = <SourceLine>[];
+      if (node.documentationComment != null &&
+          node.documentationComment!.tokens.isNotEmpty) {
+        comment = _processComment(
+            declaration.name.lexeme, node.documentationComment!);
+      }
+      elements.add(
+        SourceElement(
+          SourceElementType.topLevelVariableType,
+          declaration.name.lexeme,
+          node.beginToken.charOffset,
+          file: file,
+          className: enclosingClass,
+          comment: comment,
+        ),
+      );
+    }
+    return super.visitTopLevelVariableDeclaration(node);
+  }
+
+  @override
+  T? visitGenericTypeAlias(GenericTypeAlias node) {
+    if (isPublic(node.name.lexeme)) {
+      List<SourceLine> comment = <SourceLine>[];
+      if (node.documentationComment != null &&
+          node.documentationComment!.tokens.isNotEmpty) {
+        comment = _processComment(node.name.lexeme, node.documentationComment!);
+      }
+      elements.add(
+        SourceElement(
+          SourceElementType.typedefType,
+          node.name.lexeme,
+          node.beginToken.charOffset,
+          file: file,
+          comment: comment,
+        ),
+      );
+    }
+    return super.visitGenericTypeAlias(node);
+  }
+
+  @override
+  T? visitFieldDeclaration(FieldDeclaration node) {
+    for (final VariableDeclaration declaration in node.fields.variables) {
+      if (!isPublic(declaration.name.lexeme) || !isPublic(enclosingClass)) {
+        continue;
+      }
+      List<SourceLine> comment = <SourceLine>[];
+      if (node.documentationComment != null &&
+          node.documentationComment!.tokens.isNotEmpty) {
+        assert(enclosingClass.isNotEmpty);
+        comment = _processComment('$enclosingClass.${declaration.name.lexeme}',
+            node.documentationComment!);
+      }
+      elements.add(
+        SourceElement(
+          SourceElementType.fieldType,
+          declaration.name.lexeme,
+          node.beginToken.charOffset,
+          file: file,
+          className: enclosingClass,
+          comment: comment,
+          override: _isOverridden(node),
+        ),
+      );
+      return super.visitFieldDeclaration(node);
+    }
+    return null;
+  }
+
+  @override
+  T? visitConstructorDeclaration(ConstructorDeclaration node) {
+    final String fullName =
+        '$enclosingClass${node.name == null ? '' : '.${node.name}'}';
+    if (isPublic(enclosingClass) &&
+        (node.name == null || isPublic(node.name!.lexeme))) {
+      List<SourceLine> comment = <SourceLine>[];
+      if (node.documentationComment != null &&
+          node.documentationComment!.tokens.isNotEmpty) {
+        comment = _processComment(
+            '$enclosingClass.$fullName', node.documentationComment!);
+      }
+      elements.add(
+        SourceElement(
+          SourceElementType.constructorType,
+          fullName,
+          node.beginToken.charOffset,
+          file: file,
+          className: enclosingClass,
+          comment: comment,
+        ),
+      );
+    }
+    return super.visitConstructorDeclaration(node);
+  }
+
+  @override
+  T? visitFunctionDeclaration(FunctionDeclaration node) {
+    if (isPublic(node.name.lexeme)) {
+      List<SourceLine> comment = <SourceLine>[];
+      // Skip functions that are defined inside of methods.
+      if (!isInsideMethod(node)) {
+        if (node.documentationComment != null &&
+            node.documentationComment!.tokens.isNotEmpty) {
+          comment =
+              _processComment(node.name.lexeme, node.documentationComment!);
+        }
+        elements.add(
+          SourceElement(
+            SourceElementType.functionType,
+            node.name.lexeme,
+            node.beginToken.charOffset,
+            file: file,
+            comment: comment,
+            override: _isOverridden(node),
+          ),
+        );
+      }
+    }
+    return super.visitFunctionDeclaration(node);
+  }
+
+  @override
+  T? visitMethodDeclaration(MethodDeclaration node) {
+    if (isPublic(node.name.lexeme) && isPublic(enclosingClass)) {
+      List<SourceLine> comment = <SourceLine>[];
+      if (node.documentationComment != null &&
+          node.documentationComment!.tokens.isNotEmpty) {
+        assert(enclosingClass.isNotEmpty);
+        comment = _processComment(
+            '$enclosingClass.${node.name.lexeme}', node.documentationComment!);
+      }
+      elements.add(
+        SourceElement(
+          SourceElementType.methodType,
+          node.name.lexeme,
+          node.beginToken.charOffset,
+          file: file,
+          className: enclosingClass,
+          comment: comment,
+          override: _isOverridden(node),
+        ),
+      );
+    }
+    return super.visitMethodDeclaration(node);
+  }
+
+  bool _isOverridden(AnnotatedNode node) {
+    return node.metadata.where((Annotation annotation) {
+      return annotation.name.name == 'override';
+    }).isNotEmpty;
+  }
+
+  @override
+  T? visitMixinDeclaration(MixinDeclaration node) {
+    enclosingClass = node.name.lexeme;
+    if (!node.name.lexeme.startsWith('_')) {
+      enclosingClass = node.name.lexeme;
+      List<SourceLine> comment = <SourceLine>[];
+      if (node.documentationComment != null &&
+          node.documentationComment!.tokens.isNotEmpty) {
+        comment = _processComment(node.name.lexeme, node.documentationComment!);
+      }
+      elements.add(
+        SourceElement(
+          SourceElementType.classType,
+          node.name.lexeme,
+          node.beginToken.charOffset,
+          file: file,
+          comment: comment,
+        ),
+      );
+    }
+    final T? result = super.visitMixinDeclaration(node);
+    enclosingClass = '';
+    return result;
+  }
+
+  @override
+  T? visitClassDeclaration(ClassDeclaration node) {
+    enclosingClass = node.name.lexeme;
+    if (!node.name.lexeme.startsWith('_')) {
+      enclosingClass = node.name.lexeme;
+      List<SourceLine> comment = <SourceLine>[];
+      if (node.documentationComment != null &&
+          node.documentationComment!.tokens.isNotEmpty) {
+        comment = _processComment(node.name.lexeme, node.documentationComment!);
+      }
+      elements.add(
+        SourceElement(
+          SourceElementType.classType,
+          node.name.lexeme,
+          node.beginToken.charOffset,
+          file: file,
+          comment: comment,
+        ),
+      );
+    }
+    final T? result = super.visitClassDeclaration(node);
+    enclosingClass = '';
+    return result;
+  }
+}
diff --git a/dev/snippets/lib/src/configuration.dart b/dev/snippets/lib/src/configuration.dart
new file mode 100644
index 0000000000000000000000000000000000000000..cd6e1e3faaa92c912d6c88925674fd9a4c191b23
--- /dev/null
+++ b/dev/snippets/lib/src/configuration.dart
@@ -0,0 +1,53 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/local.dart';
+import 'package:path/path.dart' as path;
+
+// Represents the locations of all of the data for snippets.
+class SnippetConfiguration {
+  const SnippetConfiguration({
+    required this.configDirectory,
+    required this.skeletonsDirectory,
+    this.filesystem = const LocalFileSystem(),
+  });
+
+  final FileSystem filesystem;
+
+  /// This is the configuration directory for the snippets system, containing
+  /// the skeletons and templates.
+  final Directory configDirectory;
+
+  /// The directory containing the HTML skeletons to be filled out with metadata
+  /// and returned to dartdoc for insertion in the output.
+  final Directory skeletonsDirectory;
+
+  /// Gets the skeleton file to use for the given [SampleType] and DartPad
+  /// preference.
+  File getHtmlSkeletonFile(String type) {
+    final String filename =
+        type == 'dartpad' ? 'dartpad-sample.html' : '$type.html';
+    return filesystem.file(path.join(skeletonsDirectory.path, filename));
+  }
+}
+
+/// A class to compute the configuration of the snippets input and output
+/// locations based in the current location of the snippets main.dart.
+class FlutterRepoSnippetConfiguration extends SnippetConfiguration {
+  FlutterRepoSnippetConfiguration({required this.flutterRoot, super.filesystem})
+      : super(
+          configDirectory: _underRoot(filesystem, flutterRoot,
+              const <String>['dev', 'snippets', 'config']),
+          skeletonsDirectory: _underRoot(filesystem, flutterRoot,
+              const <String>['dev', 'snippets', 'config', 'skeletons']),
+        );
+
+  final Directory flutterRoot;
+
+  static Directory _underRoot(
+          FileSystem fs, Directory flutterRoot, List<String> dirs) =>
+      fs.directory(path.canonicalize(
+          path.joinAll(<String>[flutterRoot.absolute.path, ...dirs])));
+}
diff --git a/dev/snippets/lib/src/data_types.dart b/dev/snippets/lib/src/data_types.dart
new file mode 100644
index 0000000000000000000000000000000000000000..451910762258c2bcf2f5233c3f9a9afb4aeb3f5d
--- /dev/null
+++ b/dev/snippets/lib/src/data_types.dart
@@ -0,0 +1,567 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:args/args.dart';
+import 'package:file/file.dart';
+
+import 'util.dart';
+
+/// A class to represent a line of input code, with associated line number, file
+/// and element name.
+class SourceLine {
+  const SourceLine(
+    this.text, {
+    this.file,
+    this.element,
+    this.line = -1,
+    this.startChar = -1,
+    this.endChar = -1,
+    this.indent = 0,
+  });
+  final File? file;
+  final String? element;
+  final int line;
+  final int startChar;
+  final int endChar;
+  final int indent;
+  final String text;
+
+  String toStringWithColumn(int column) =>
+      '$file:$line:${column + indent}: $text';
+
+  SourceLine copyWith({
+    String? element,
+    String? text,
+    File? file,
+    int? line,
+    int? startChar,
+    int? endChar,
+    int? indent,
+  }) {
+    return SourceLine(
+      text ?? this.text,
+      element: element ?? this.element,
+      file: file ?? this.file,
+      line: line ?? this.line,
+      startChar: startChar ?? this.startChar,
+      endChar: endChar ?? this.endChar,
+      indent: indent ?? this.indent,
+    );
+  }
+
+  bool get hasFile => file != null;
+
+  @override
+  String toString() => '$file:${line == -1 ? '??' : line}: $text';
+}
+
+/// A class containing the name and contents associated with a code block inside of a
+/// code sample, for named injection into a template.
+class SkeletonInjection {
+  SkeletonInjection(this.name, this.contents, {this.language = ''});
+  final String name;
+  final List<SourceLine> contents;
+  final String language;
+  Iterable<String> get stringContents =>
+      contents.map<String>((SourceLine line) => line.text.trimRight());
+  String get mergedContent => stringContents.join('\n');
+}
+
+/// A base class to represent a block of any kind of sample code, marked by
+/// "{@tool (snippet|sample|dartdoc) ...}...{@end-tool}".
+abstract class CodeSample {
+  CodeSample(
+    this.args,
+    this.input, {
+    required this.index,
+    required SourceLine lineProto,
+  })  : assert(args.isNotEmpty),
+        _lineProto = lineProto,
+        sourceFile = null;
+
+  CodeSample.fromFile(
+    this.args,
+    this.input,
+    this.sourceFile, {
+    required this.index,
+    required SourceLine lineProto,
+  })  : assert(args.isNotEmpty),
+        _lineProto = lineProto;
+
+  final File? sourceFile;
+  final List<String> args;
+  final List<SourceLine> input;
+  final SourceLine _lineProto;
+  String? _sourceFileContents;
+  String get sourceFileContents {
+    if (sourceFile != null && _sourceFileContents == null) {
+      // Strip lines until the first non-comment line. This gets rid of the
+      // copyright and comment directing the reader to the original source file.
+      final List<String> stripped = <String>[];
+      bool doneStrippingHeaders = false;
+      try {
+        for (final String line in sourceFile!.readAsLinesSync()) {
+          if (!doneStrippingHeaders &&
+              RegExp(r'^\s*(\/\/.*)?$').hasMatch(line)) {
+            continue;
+          }
+          // Stop skipping lines after the first line that isn't stripped.
+          doneStrippingHeaders = true;
+          stripped.add(line);
+        }
+      } on FileSystemException catch (e) {
+        throw SnippetException(
+          'Unable to read linked source file ${sourceFile!}: $e',
+          file: _lineProto.file?.absolute.path,
+        );
+      }
+      // Remove any section markers
+      final RegExp sectionMarkerRegExp = RegExp(
+        r'(\/\/\*\*+\n)?\/\/\* [▼▲]+.*$(\n\/\/\*\*+)?\n\n?',
+        multiLine: true,
+      );
+      _sourceFileContents =
+          stripped.join('\n').replaceAll(sectionMarkerRegExp, '');
+    }
+    return _sourceFileContents ?? '';
+  }
+
+  Iterable<String> get inputStrings =>
+      input.map<String>((SourceLine line) => line.text);
+  String get inputAsString => inputStrings.join('\n');
+
+  /// The index of this sample within the dartdoc comment it came from.
+  final int index;
+  String description = '';
+  String get element => start.element ?? '';
+  String output = '';
+  Map<String, Object?> metadata = <String, Object?>{};
+  List<SkeletonInjection> parts = <SkeletonInjection>[];
+  SourceLine get start => input.isEmpty ? _lineProto : input.first;
+
+  String get template {
+    final ArgParser parser = ArgParser();
+    parser.addOption('template', defaultsTo: '');
+    final ArgResults parsedArgs = parser.parse(args);
+    return parsedArgs['template']! as String;
+  }
+
+  @override
+  String toString() {
+    final StringBuffer buf = StringBuffer('${args.join(' ')}:\n');
+    for (final SourceLine line in input) {
+      buf.writeln(
+        '${(line.line == -1 ? '??' : line.line).toString().padLeft(4)}: ${line.text} ',
+      );
+    }
+    return buf.toString();
+  }
+
+  String get type;
+}
+
+/// A class to represent a snippet of sample code, marked by "{@tool
+/// snippet}...{@end-tool}".
+///
+/// Snippets are code that is not meant to be run as a complete application, but
+/// rather as a code usage example.
+class SnippetSample extends CodeSample {
+  SnippetSample(
+    List<SourceLine> input, {
+    required int index,
+    required SourceLine lineProto,
+  })  : assumptions = <SourceLine>[],
+        super(
+          <String>['snippet'],
+          input,
+          index: index,
+          lineProto: lineProto,
+        );
+
+  factory SnippetSample.combine(
+    List<SnippetSample> sections, {
+    required int index,
+    required SourceLine lineProto,
+  }) {
+    final List<SourceLine> code =
+        sections.expand((SnippetSample section) => section.input).toList();
+    return SnippetSample(code, index: index, lineProto: lineProto);
+  }
+
+  factory SnippetSample.fromStrings(SourceLine firstLine, List<String> code,
+      {required int index}) {
+    final List<SourceLine> codeLines = <SourceLine>[];
+    int startPos = firstLine.startChar;
+    for (int i = 0; i < code.length; ++i) {
+      codeLines.add(
+        firstLine.copyWith(
+          text: code[i],
+          line: firstLine.line + i,
+          startChar: startPos,
+        ),
+      );
+      startPos += code[i].length + 1;
+    }
+    return SnippetSample(
+      codeLines,
+      index: index,
+      lineProto: firstLine,
+    );
+  }
+
+  factory SnippetSample.surround(
+    String prefix,
+    List<SourceLine> code,
+    String postfix, {
+    required int index,
+  }) {
+    return SnippetSample(
+      <SourceLine>[
+        if (prefix.isNotEmpty) SourceLine(prefix),
+        ...code,
+        if (postfix.isNotEmpty) SourceLine(postfix),
+      ],
+      index: index,
+      lineProto: code.first,
+    );
+  }
+
+  List<SourceLine> assumptions;
+
+  @override
+  String get template => '';
+
+  @override
+  SourceLine get start =>
+      input.firstWhere((SourceLine line) => line.file != null);
+
+  @override
+  String get type => 'snippet';
+}
+
+/// A class to represent a plain application sample in the dartdoc comments,
+/// marked by `{@tool sample ...}...{@end-tool}`.
+///
+/// Application samples are processed separately from [SnippetSample]s, because
+/// they must be injected into templates in order to be analyzed. Each
+/// [ApplicationSample] represents one `{@tool sample ...}...{@end-tool}` block
+/// in the source file.
+class ApplicationSample extends CodeSample {
+  ApplicationSample({
+    List<SourceLine> input = const <SourceLine>[],
+    required List<String> args,
+    required int index,
+    required SourceLine lineProto,
+  })  : assert(args.isNotEmpty),
+        super(args, input, index: index, lineProto: lineProto);
+
+  ApplicationSample.fromFile({
+    List<SourceLine> input = const <SourceLine>[],
+    required List<String> args,
+    required File sourceFile,
+    required int index,
+    required SourceLine lineProto,
+  })  : assert(args.isNotEmpty),
+        super.fromFile(args, input, sourceFile,
+            index: index, lineProto: lineProto);
+
+  @override
+  String get type => 'sample';
+}
+
+/// A class to represent a Dartpad application sample in the dartdoc comments,
+/// marked by `{@tool dartpad ...}...{@end-tool}`.
+///
+/// Dartpad samples are processed separately from [SnippetSample]s, because they
+/// must be injected into templates in order to be analyzed. Each
+/// [DartpadSample] represents one `{@tool dartpad ...}...{@end-tool}` block in
+/// the source file.
+class DartpadSample extends ApplicationSample {
+  DartpadSample({
+    super.input,
+    required super.args,
+    required super.index,
+    required super.lineProto,
+  }) : assert(args.isNotEmpty);
+
+  DartpadSample.fromFile({
+    super.input,
+    required super.args,
+    required super.sourceFile,
+    required super.index,
+    required super.lineProto,
+  })  : assert(args.isNotEmpty),
+        super.fromFile();
+
+  @override
+  String get type => 'dartpad';
+}
+
+/// The different types of Dart [SourceElement]s that can be found in a source file.
+enum SourceElementType {
+  /// A class
+  classType,
+
+  /// A field variable of a class.
+  fieldType,
+
+  /// A constructor for a class.
+  constructorType,
+
+  /// A method of a class.
+  methodType,
+
+  /// A function typedef
+  typedefType,
+
+  /// A top level (non-class) variable.
+  topLevelVariableType,
+
+  /// A function, either top level, or embedded in another function.
+  functionType,
+
+  /// An unknown type used for initialization.
+  unknownType,
+}
+
+/// Converts the enun type [SourceElementType] to a human readable string.
+String sourceElementTypeAsString(SourceElementType type) {
+  switch (type) {
+    case SourceElementType.classType:
+      return 'class';
+    case SourceElementType.fieldType:
+      return 'field';
+    case SourceElementType.methodType:
+      return 'method';
+    case SourceElementType.constructorType:
+      return 'constructor';
+    case SourceElementType.typedefType:
+      return 'typedef';
+    case SourceElementType.topLevelVariableType:
+      return 'variable';
+    case SourceElementType.functionType:
+      return 'function';
+    case SourceElementType.unknownType:
+      return 'unknown';
+  }
+}
+
+/// A class that represents a Dart element in a source file.
+///
+/// The element is one of the types in [SourceElementType].
+class SourceElement {
+  /// A factory constructor for SourceElements.
+  ///
+  /// This uses a factory so that the default for the `comment` and `samples`
+  /// lists can be modifiable lists.
+  factory SourceElement(
+    SourceElementType type,
+    String name,
+    int startPos, {
+    required File file,
+    String className = '',
+    List<SourceLine>? comment,
+    int startLine = -1,
+    List<CodeSample>? samples,
+    bool override = false,
+  }) {
+    comment ??= <SourceLine>[];
+    samples ??= <CodeSample>[];
+    final List<String> commentLines =
+        comment.map<String>((SourceLine line) => line.text).toList();
+    final String commentString = commentLines.join('\n');
+    return SourceElement._(
+      type,
+      name,
+      startPos,
+      file: file,
+      className: className,
+      comment: comment,
+      startLine: startLine,
+      samples: samples,
+      override: override,
+      commentString: commentString,
+      commentStringWithoutTools: _getCommentStringWithoutTools(commentString),
+      commentStringWithoutCode: _getCommentStringWithoutCode(commentString),
+      commentLines: commentLines,
+    );
+  }
+
+  const SourceElement._(
+    this.type,
+    this.name,
+    this.startPos, {
+    required this.file,
+    this.className = '',
+    this.comment = const <SourceLine>[],
+    this.startLine = -1,
+    this.samples = const <CodeSample>[],
+    this.override = false,
+    String commentString = '',
+    String commentStringWithoutTools = '',
+    String commentStringWithoutCode = '',
+    List<String> commentLines = const <String>[],
+  })  : _commentString = commentString,
+        _commentStringWithoutTools = commentStringWithoutTools,
+        _commentStringWithoutCode = commentStringWithoutCode,
+        _commentLines = commentLines;
+
+  final String _commentString;
+  final String _commentStringWithoutTools;
+  final String _commentStringWithoutCode;
+  final List<String> _commentLines;
+
+  // Does not include the description of the sample code, just the text outside
+  // of any dartdoc tools.
+  static String _getCommentStringWithoutTools(String string) {
+    return string.replaceAll(
+        RegExp(r'(\{@tool ([^}]*)\}.*?\{@end-tool\}|/// ?)', dotAll: true), '');
+  }
+
+  // Includes the description text inside of an "@tool"-based sample, but not
+  // the code itself, or any dartdoc tags.
+  static String _getCommentStringWithoutCode(String string) {
+    return string.replaceAll(
+        RegExp(r'([`]{3}.*?[`]{3}|\{@\w+[^}]*\}|/// ?)', dotAll: true), '');
+  }
+
+  /// The type of the element
+  final SourceElementType type;
+
+  /// The name of the element.
+  ///
+  /// For example, a method called "doSomething" that is part of the class
+  /// "MyClass" would have "doSomething" as its name.
+  final String name;
+
+  /// The name of the class the element belongs to, if any.
+  ///
+  /// This is the empty string if it isn't part of a class.
+  ///
+  /// For example, a method called "doSomething" that is part of the class
+  /// "MyClass" would have "MyClass" as its `className`.
+  final String className;
+
+  /// Whether or not this element has the "@override" annotation attached to it.
+  final bool override;
+
+  /// The file that this [SourceElement] was parsed from.
+  final File file;
+
+  /// The character position in the file that this [SourceElement] starts at.
+  final int startPos;
+
+  /// The line in the file that the first position of [SourceElement] is on.
+  final int startLine;
+
+  /// The list of [SourceLine]s that make up the documentation comment for this
+  /// [SourceElement].
+  final List<SourceLine> comment;
+
+  /// The list of [CodeSample]s that are in the documentation comment for this
+  /// [SourceElement].
+  ///
+  /// This field will be populated by calling [replaceSamples].
+  final List<CodeSample> samples;
+
+  /// Get the comments as an iterable of lines.
+  Iterable<String> get commentLines => _commentLines;
+
+  /// Get the comments as a single string.
+  String get commentString => _commentString;
+
+  /// Does not include the description of the sample code, just the text outside of any dartdoc tools.
+  String get commentStringWithoutTools => _commentStringWithoutTools;
+
+  /// Includes the description text inside of an "@tool"-based sample, but not
+  /// the code itself, or any dartdoc tags.
+  String get commentStringWithoutCode => _commentStringWithoutCode;
+
+  /// The number of samples in the dartdoc comment for this element.
+  int get sampleCount => samples.length;
+
+  /// The number of [DartpadSample]s in the dartdoc comment for this element.
+  int get dartpadSampleCount => samples.whereType<DartpadSample>().length;
+
+  /// The number of [ApplicationSample]s in the dartdoc comment for this element.
+  int get applicationSampleCount => samples.where((CodeSample sample) {
+        return sample is ApplicationSample && sample is! DartpadSample;
+      }).length;
+
+  /// The number of [SnippetSample]s in the dartdoc comment for this element.
+  int get snippetCount => samples.whereType<SnippetSample>().length;
+
+  /// Count of comment lines, not including lines of code in the comment.
+  int get lineCount => commentStringWithoutCode.split('\n').length;
+
+  /// Count of comment words, not including words in any code in the comment.
+  int get wordCount {
+    return commentStringWithoutCode.split(RegExp(r'\s+')).length;
+  }
+
+  /// Count of comment characters, not including any code samples in the
+  /// comment, after collapsing each run of whitespace to a single space.
+  int get charCount =>
+      commentStringWithoutCode.replaceAll(RegExp(r'\s+'), ' ').length;
+
+  /// Whether or not this element's documentation has a "See also:" section in it.
+  bool get hasSeeAlso => commentStringWithoutTools.contains('See also:');
+
+  int get referenceCount {
+    final RegExp regex = RegExp(r'\[[. \w]*\](?!\(.*\))');
+    return regex.allMatches(commentStringWithoutCode).length;
+  }
+
+  int get linkCount {
+    final RegExp regex = RegExp(r'\[[. \w]*\]\(.*\)');
+    return regex.allMatches(commentStringWithoutCode).length;
+  }
+
+  /// Returns the fully qualified name of this element.
+  ///
+  /// For example, a method called "doSomething" that is part of the class
+  /// "MyClass" would have "MyClass.doSomething" as its `elementName`.
+  String get elementName {
+    if (type == SourceElementType.constructorType) {
+      // Constructors already have the name of the class in them.
+      return name;
+    }
+    return className.isEmpty ? name : '$className.$name';
+  }
+
+  /// Returns the type of this element as a [String].
+  String get typeAsString {
+    return '${override ? 'overridden ' : ''}${sourceElementTypeAsString(type)}';
+  }
+
+  void replaceSamples(Iterable<CodeSample> samples) {
+    this.samples.clear();
+    this.samples.addAll(samples);
+  }
+
+  /// Copy the source element, with some attributes optionally replaced.
+  SourceElement copyWith({
+    SourceElementType? type,
+    String? name,
+    int? startPos,
+    File? file,
+    String? className,
+    List<SourceLine>? comment,
+    int? startLine,
+    List<CodeSample>? samples,
+    bool? override,
+  }) {
+    return SourceElement(
+      type ?? this.type,
+      name ?? this.name,
+      startPos ?? this.startPos,
+      file: file ?? this.file,
+      className: className ?? this.className,
+      comment: comment ?? this.comment,
+      startLine: startLine ?? this.startLine,
+      samples: samples ?? this.samples,
+      override: override ?? this.override,
+    );
+  }
+}
diff --git a/dev/snippets/lib/src/import_sorter.dart b/dev/snippets/lib/src/import_sorter.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ecb9f74bfb181ae5a2fc0dfdee93d4b071f1af9e
--- /dev/null
+++ b/dev/snippets/lib/src/import_sorter.dart
@@ -0,0 +1,426 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:math';
+
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/utilities.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/source/line_info.dart';
+import 'package:meta/meta.dart';
+
+import 'util.dart';
+
+/// Read the given source code, and return the new contents after sorting the
+/// imports.
+String sortImports(String contents) {
+  final ParseStringResult parseResult = parseString(
+    content: contents,
+    featureSet: FeatureSet.fromEnableFlags2(
+      sdkLanguageVersion: FlutterInformation.instance.getDartSdkVersion(),
+      flags: <String>[],
+    ),
+  );
+  final List<AnalysisError> errors = <AnalysisError>[];
+  final _ImportOrganizer organizer =
+      _ImportOrganizer(contents, parseResult.unit, errors);
+  final List<_SourceEdit> edits = organizer.organize();
+  // Sort edits in reverse order
+  edits.sort((_SourceEdit a, _SourceEdit b) {
+    return b.offset.compareTo(a.offset);
+  });
+  // Apply edits
+  for (final _SourceEdit edit in edits) {
+    contents = contents.replaceRange(edit.offset, edit.end, edit.replacement);
+  }
+  return contents;
+}
+
+/// Organizer of imports (and other directives) in the [unit].
+// Adapted from the analysis_server package.
+// This code is largely copied from:
+// https://github.com/dart-lang/sdk/blob/c7405b9d86b4b47cf7610667491f1db72723b0dd/pkg/analysis_server/lib/src/services/correction/organize_imports.dart#L15
+// TODO(gspencergoog): If ImportOrganizer ever becomes part of the public API,
+// this class should probably be replaced.
+// https://github.com/flutter/flutter/issues/86197
+class _ImportOrganizer {
+  _ImportOrganizer(this.initialCode, this.unit, this.errors)
+      : code = initialCode {
+    endOfLine = getEOL(code);
+    hasUnresolvedIdentifierError = errors.any((AnalysisError error) {
+      return error.errorCode.isUnresolvedIdentifier;
+    });
+  }
+
+  final String initialCode;
+
+  final CompilationUnit unit;
+
+  final List<AnalysisError> errors;
+
+  String code;
+
+  String endOfLine = '\n';
+
+  bool hasUnresolvedIdentifierError = false;
+
+  /// Returns the number of characters common to the end of [a] and [b].
+  int findCommonSuffix(String a, String b) {
+    final int aLength = a.length;
+    final int bLength = b.length;
+    final int n = min(aLength, bLength);
+    for (int i = 1; i <= n; i++) {
+      if (a.codeUnitAt(aLength - i) != b.codeUnitAt(bLength - i)) {
+        return i - 1;
+      }
+    }
+    return n;
+  }
+
+  /// Return the [_SourceEdit]s that organize imports in the [unit].
+  List<_SourceEdit> organize() {
+    _organizeDirectives();
+    // prepare edits
+    final List<_SourceEdit> edits = <_SourceEdit>[];
+    if (code != initialCode) {
+      final int suffixLength = findCommonSuffix(initialCode, code);
+      final _SourceEdit edit = _SourceEdit(0, initialCode.length - suffixLength,
+          code.substring(0, code.length - suffixLength));
+      edits.add(edit);
+    }
+    return edits;
+  }
+
+  /// Organize all [Directive]s.
+  void _organizeDirectives() {
+    final LineInfo lineInfo = unit.lineInfo;
+    bool hasLibraryDirective = false;
+    final List<_DirectiveInfo> directives = <_DirectiveInfo>[];
+    for (final Directive directive in unit.directives) {
+      if (directive is LibraryDirective) {
+        hasLibraryDirective = true;
+      }
+      if (directive is UriBasedDirective) {
+        final _DirectivePriority? priority = getDirectivePriority(directive);
+        if (priority != null) {
+          int offset = directive.offset;
+          int end = directive.end;
+
+          final Token? leadingComment =
+              getLeadingComment(unit, directive, lineInfo);
+          final Token? trailingComment =
+              getTrailingComment(unit, directive, lineInfo, end);
+
+          String? leadingCommentText;
+          if (leadingComment != null) {
+            leadingCommentText =
+                code.substring(leadingComment.offset, directive.offset);
+            offset = leadingComment.offset;
+          }
+          String? trailingCommentText;
+          if (trailingComment != null) {
+            trailingCommentText =
+                code.substring(directive.end, trailingComment.end);
+            end = trailingComment.end;
+          }
+          String? documentationText;
+          final Comment? documentationComment = directive.documentationComment;
+          if (documentationComment != null) {
+            documentationText = code.substring(
+                documentationComment.offset, documentationComment.end);
+          }
+          String? annotationText;
+          final Token? beginToken = directive.metadata.beginToken;
+          final Token? endToken = directive.metadata.endToken;
+          if (beginToken != null && endToken != null) {
+            annotationText = code.substring(beginToken.offset, endToken.end);
+          }
+          final String text = code.substring(
+              directive.firstTokenAfterCommentAndMetadata.offset,
+              directive.end);
+          final String uriContent = directive.uri.stringValue ?? '';
+          directives.add(
+            _DirectiveInfo(
+              directive,
+              priority,
+              leadingCommentText,
+              documentationText,
+              annotationText,
+              uriContent,
+              trailingCommentText,
+              offset,
+              end,
+              text,
+            ),
+          );
+        }
+      }
+    }
+    // nothing to do
+    if (directives.isEmpty) {
+      return;
+    }
+    final int firstDirectiveOffset = directives.first.offset;
+    final int lastDirectiveEnd = directives.last.end;
+
+    // Without a library directive, the library comment is the comment of the
+    // first directive.
+    _DirectiveInfo? libraryDocumentationDirective;
+    if (!hasLibraryDirective && directives.isNotEmpty) {
+      libraryDocumentationDirective = directives.first;
+    }
+
+    // sort
+    directives.sort();
+    // append directives with grouping
+    String directivesCode;
+    {
+      final StringBuffer sb = StringBuffer();
+      if (libraryDocumentationDirective != null &&
+          libraryDocumentationDirective.documentationText != null) {
+        sb.write(libraryDocumentationDirective.documentationText);
+        sb.write(endOfLine);
+      }
+      _DirectivePriority currentPriority = directives.first.priority;
+      for (final _DirectiveInfo directiveInfo in directives) {
+        if (currentPriority != directiveInfo.priority) {
+          sb.write(endOfLine);
+          currentPriority = directiveInfo.priority;
+        }
+        if (directiveInfo.leadingCommentText != null) {
+          sb.write(directiveInfo.leadingCommentText);
+        }
+        if (directiveInfo != libraryDocumentationDirective &&
+            directiveInfo.documentationText != null) {
+          sb.write(directiveInfo.documentationText);
+          sb.write(endOfLine);
+        }
+        if (directiveInfo.annotationText != null) {
+          sb.write(directiveInfo.annotationText);
+          sb.write(endOfLine);
+        }
+        sb.write(directiveInfo.text);
+        if (directiveInfo.trailingCommentText != null) {
+          sb.write(directiveInfo.trailingCommentText);
+        }
+        sb.write(endOfLine);
+      }
+      directivesCode = sb.toString();
+      directivesCode = directivesCode.trimRight();
+    }
+    // prepare code
+    final String beforeDirectives = code.substring(0, firstDirectiveOffset);
+    final String afterDirectives = code.substring(lastDirectiveEnd);
+    code = beforeDirectives + directivesCode + afterDirectives;
+  }
+
+  static _DirectivePriority? getDirectivePriority(UriBasedDirective directive) {
+    final String uriContent = directive.uri.stringValue ?? '';
+    if (directive is ImportDirective) {
+      if (uriContent.startsWith('dart:')) {
+        return _DirectivePriority.IMPORT_SDK;
+      } else if (uriContent.startsWith('package:')) {
+        return _DirectivePriority.IMPORT_PKG;
+      } else if (uriContent.contains('://')) {
+        return _DirectivePriority.IMPORT_OTHER;
+      } else {
+        return _DirectivePriority.IMPORT_REL;
+      }
+    }
+    if (directive is ExportDirective) {
+      if (uriContent.startsWith('dart:')) {
+        return _DirectivePriority.EXPORT_SDK;
+      } else if (uriContent.startsWith('package:')) {
+        return _DirectivePriority.EXPORT_PKG;
+      } else if (uriContent.contains('://')) {
+        return _DirectivePriority.EXPORT_OTHER;
+      } else {
+        return _DirectivePriority.EXPORT_REL;
+      }
+    }
+    if (directive is PartDirective) {
+      return _DirectivePriority.PART;
+    }
+    return null;
+  }
+
+  /// Return the EOL to use for [code].
+  static String getEOL(String code) {
+    if (code.contains('\r\n')) {
+      return '\r\n';
+    } else {
+      return '\n';
+    }
+  }
+
+  /// Gets the first comment token considered to be the leading comment for this
+  /// directive.
+  ///
+  /// Leading comments for the first directive in a file are considered library
+  /// comments and not returned unless they contain blank lines, in which case
+  /// only the last part of the comment will be returned.
+  static Token? getLeadingComment(
+      CompilationUnit unit, UriBasedDirective directive, LineInfo lineInfo) {
+    if (directive.beginToken.precedingComments == null) {
+      return null;
+    }
+
+    Token? firstComment = directive.beginToken.precedingComments;
+    Token? comment = firstComment;
+    Token? nextComment = comment?.next;
+    // Don't connect comments that have a blank line between them
+    while (comment != null && nextComment != null) {
+      final int currentLine = lineInfo.getLocation(comment.offset).lineNumber;
+      final int nextLine = lineInfo.getLocation(nextComment.offset).lineNumber;
+      if (nextLine - currentLine > 1) {
+        firstComment = nextComment;
+      }
+      comment = nextComment;
+      nextComment = comment.next;
+    }
+
+    // Check if the comment is the first comment in the document
+    if (firstComment != unit.beginToken.precedingComments) {
+      final int previousDirectiveLine =
+          lineInfo.getLocation(directive.beginToken.previous!.end).lineNumber;
+
+      // Skip over any comments on the same line as the previous directive
+      // as they will be attached to the end of it.
+      Token? comment = firstComment;
+      while (comment != null &&
+          previousDirectiveLine ==
+              lineInfo.getLocation(comment.offset).lineNumber) {
+        comment = comment.next;
+      }
+      return comment;
+    }
+    return null;
+  }
+
+  /// Gets the last comment token considered to be the trailing comment for this
+  /// directive.
+  ///
+  /// To be considered a trailing comment, the comment must be on the same line
+  /// as the directive.
+  static Token? getTrailingComment(CompilationUnit unit,
+      UriBasedDirective directive, LineInfo lineInfo, int end) {
+    final int line = lineInfo.getLocation(end).lineNumber;
+    Token? comment = directive.endToken.next!.precedingComments;
+    while (comment != null) {
+      if (lineInfo.getLocation(comment.offset).lineNumber == line) {
+        return comment;
+      }
+      comment = comment.next;
+    }
+    return null;
+  }
+}
+
+class _DirectiveInfo implements Comparable<_DirectiveInfo> {
+  _DirectiveInfo(
+    this.directive,
+    this.priority,
+    this.leadingCommentText,
+    this.documentationText,
+    this.annotationText,
+    this.uri,
+    this.trailingCommentText,
+    this.offset,
+    this.end,
+    this.text,
+  );
+
+  final UriBasedDirective directive;
+  final _DirectivePriority priority;
+  final String? leadingCommentText;
+  final String? documentationText;
+  final String? annotationText;
+  final String uri;
+  final String? trailingCommentText;
+
+  /// The offset of the first token, usually the keyword but may include leading comments.
+  final int offset;
+
+  /// The offset after the last token, including the end-of-line comment.
+  final int end;
+
+  /// The text excluding comments, documentation and annotations.
+  final String text;
+
+  @override
+  int compareTo(_DirectiveInfo other) {
+    if (priority == other.priority) {
+      return _compareUri(uri, other.uri);
+    }
+    return priority.index - other.priority.index;
+  }
+
+  @override
+  String toString() => '(priority=$priority; text=$text)';
+
+  static int _compareUri(String a, String b) {
+    final List<String> aList = _splitUri(a);
+    final List<String> bList = _splitUri(b);
+    int result;
+    if ((result = aList[0].compareTo(bList[0])) != 0) {
+      return result;
+    }
+    if ((result = aList[1].compareTo(bList[1])) != 0) {
+      return result;
+    }
+    return 0;
+  }
+
+  /// Split the given [uri] like `package:some.name/and/path.dart` into a list
+  /// like `[package:some.name, and/path.dart]`.
+  static List<String> _splitUri(String uri) {
+    final int index = uri.indexOf('/');
+    if (index == -1) {
+      return <String>[uri, ''];
+    }
+    return <String>[uri.substring(0, index), uri.substring(index + 1)];
+  }
+}
+
+enum _DirectivePriority {
+  IMPORT_SDK,
+  IMPORT_PKG,
+  IMPORT_OTHER,
+  IMPORT_REL,
+  EXPORT_SDK,
+  EXPORT_PKG,
+  EXPORT_OTHER,
+  EXPORT_REL,
+  PART
+}
+
+/// SourceEdit
+///
+/// {
+///   "offset": int
+///   "length": int
+///   "replacement": String
+///   "id": optional String
+/// }
+///
+/// Clients may not extend, implement or mix-in this class.
+@immutable
+class _SourceEdit {
+  const _SourceEdit(this.offset, this.length, this.replacement);
+
+  /// The offset of the region to be modified.
+  final int offset;
+
+  /// The length of the region to be modified.
+  final int length;
+
+  /// The end of the region to be modified.
+  int get end => offset + length;
+
+  /// The code that is to replace the specified region in the original code.
+  final String replacement;
+}
diff --git a/dev/snippets/lib/src/snippet_generator.dart b/dev/snippets/lib/src/snippet_generator.dart
new file mode 100644
index 0000000000000000000000000000000000000000..75a0c896e2cd7bf9623e6c4fe42d8b11a86bbf8e
--- /dev/null
+++ b/dev/snippets/lib/src/snippet_generator.dart
@@ -0,0 +1,429 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io' as io;
+
+import 'package:dart_style/dart_style.dart';
+import 'package:file/file.dart';
+import 'package:file/local.dart';
+import 'package:path/path.dart' as path;
+
+import 'configuration.dart';
+import 'data_types.dart';
+import 'import_sorter.dart';
+import 'util.dart';
+
+/// Generates the snippet HTML, as well as saving the output snippet main to
+/// the output directory.
+class SnippetGenerator {
+  SnippetGenerator(
+      {SnippetConfiguration? configuration,
+      FileSystem filesystem = const LocalFileSystem(),
+      Directory? flutterRoot})
+      : flutterRoot =
+            flutterRoot ?? FlutterInformation.instance.getFlutterRoot(),
+        configuration = configuration ??
+            FlutterRepoSnippetConfiguration(
+                filesystem: filesystem,
+                flutterRoot: flutterRoot ??
+                    FlutterInformation.instance.getFlutterRoot());
+
+  final Directory flutterRoot;
+
+  /// The configuration used to determine where to get/save data for the
+  /// snippet.
+  final SnippetConfiguration configuration;
+
+  static const JsonEncoder jsonEncoder = JsonEncoder.withIndent('    ');
+
+  /// A Dart formatted used to format the snippet code and finished application
+  /// code.
+  static DartFormatter formatter =
+      DartFormatter(pageWidth: 80, fixes: StyleFix.all);
+
+  /// Interpolates the [injections] into an HTML skeleton file.
+  ///
+  /// The order of the injections is important.
+  ///
+  /// Takes into account the [type] and doesn't substitute in the id and the app
+  /// if not a [SnippetType.sample] snippet.
+  String interpolateSkeleton(
+    CodeSample sample,
+    String skeleton,
+  ) {
+    final List<String> codeParts = <String>[];
+    const HtmlEscape htmlEscape = HtmlEscape();
+    String? language;
+    for (final SkeletonInjection injection in sample.parts) {
+      if (!injection.name.startsWith('code')) {
+        continue;
+      }
+      codeParts.addAll(injection.stringContents);
+      if (injection.language.isNotEmpty) {
+        language = injection.language;
+      }
+      codeParts.addAll(<String>['', '// ...', '']);
+    }
+    if (codeParts.length > 3) {
+      codeParts.removeRange(codeParts.length - 3, codeParts.length);
+    }
+    // Only insert a div for the description if there actually is some text there.
+    // This means that the {{description}} marker in the skeleton needs to
+    // be inside of an {@inject-html} block.
+    final String description = sample.description.trim().isNotEmpty
+        ? '<div class="snippet-description">{@end-inject-html}${sample.description.trim()}{@inject-html}</div>'
+        : '';
+
+    // DartPad only supports stable or main as valid channels. Use main
+    // if not on stable so that local runs will work (although they will
+    // still take their sample code from the master docs server).
+    final String channel =
+        sample.metadata['channel'] == 'stable' ? 'stable' : 'main';
+
+    final Map<String, String> substitutions = <String, String>{
+      'description': description,
+      'code': htmlEscape.convert(codeParts.join('\n')),
+      'language': language ?? 'dart',
+      'serial': '',
+      'id': sample.metadata['id']! as String,
+      'channel': channel,
+      'element': sample.metadata['element'] as String? ?? sample.element,
+      'app': '',
+    };
+    if (sample is ApplicationSample) {
+      substitutions
+        ..['serial'] = sample.metadata['serial']?.toString() ?? '0'
+        ..['app'] = htmlEscape.convert(sample.output);
+    }
+    return skeleton.replaceAllMapped(
+        RegExp('{{(${substitutions.keys.join('|')})}}'), (Match match) {
+      return substitutions[match[1]]!;
+    });
+  }
+
+  /// Consolidates all of the snippets and the assumptions into one snippet, in
+  /// order to create a compilable result.
+  Iterable<SourceLine> consolidateSnippets(List<CodeSample> samples,
+      {bool addMarkers = false}) {
+    if (samples.isEmpty) {
+      return <SourceLine>[];
+    }
+    final Iterable<SnippetSample> snippets = samples.whereType<SnippetSample>();
+    final List<SourceLine> snippetLines = <SourceLine>[
+      ...snippets.first.assumptions,
+    ];
+    for (final SnippetSample sample in snippets) {
+      parseInput(sample);
+      snippetLines.addAll(_processBlocks(sample));
+    }
+    return snippetLines;
+  }
+
+  /// A RegExp that matches a Dart constructor.
+  static final RegExp _constructorRegExp =
+      RegExp(r'(const\s+)?_*[A-Z][a-zA-Z0-9<>._]*\(');
+
+  /// A serial number so that we can create unique expression names when we
+  /// generate them.
+  int _expressionId = 0;
+
+  List<SourceLine> _surround(
+      String prefix, Iterable<SourceLine> body, String suffix) {
+    return <SourceLine>[
+      if (prefix.isNotEmpty) SourceLine(prefix),
+      ...body,
+      if (suffix.isNotEmpty) SourceLine(suffix),
+    ];
+  }
+
+  /// Process one block of sample code (the part inside of "```" markers).
+  /// Splits any sections denoted by "// ..." into separate blocks to be
+  /// processed separately. Uses a primitive heuristic to make sample blocks
+  /// into valid Dart code.
+  List<SourceLine> _processBlocks(CodeSample sample) {
+    final List<SourceLine> block = sample.parts
+        .expand<SourceLine>((SkeletonInjection injection) => injection.contents)
+        .toList();
+    if (block.isEmpty) {
+      return <SourceLine>[];
+    }
+    return _processBlock(block);
+  }
+
+  List<SourceLine> _processBlock(List<SourceLine> block) {
+    final String firstLine = block.first.text;
+    if (firstLine.startsWith('new ') ||
+        firstLine.startsWith(_constructorRegExp)) {
+      _expressionId += 1;
+      return _surround('dynamic expression$_expressionId = ', block, ';');
+    } else if (firstLine.startsWith('await ')) {
+      _expressionId += 1;
+      return _surround(
+          'Future<void> expression$_expressionId() async { ', block, ' }');
+    } else if (block.first.text.startsWith('class ') ||
+        block.first.text.startsWith('enum ')) {
+      return block;
+    } else if ((block.first.text.startsWith('_') ||
+            block.first.text.startsWith('final ')) &&
+        block.first.text.contains(' = ')) {
+      _expressionId += 1;
+      return _surround(
+          'void expression$_expressionId() { ', block.toList(), ' }');
+    } else {
+      final List<SourceLine> buffer = <SourceLine>[];
+      int blocks = 0;
+      SourceLine? subLine;
+      final List<SourceLine> subsections = <SourceLine>[];
+      for (int index = 0; index < block.length; index += 1) {
+        // Each section of the dart code that is either split by a blank line, or with
+        // '// ...' is treated as a separate code block.
+        if (block[index].text.trim().isEmpty || block[index].text == '// ...') {
+          if (subLine == null) {
+            continue;
+          }
+          blocks += 1;
+          subsections.addAll(_processBlock(buffer));
+          buffer.clear();
+          assert(buffer.isEmpty);
+          subLine = null;
+        } else if (block[index].text.startsWith('// ')) {
+          if (buffer.length > 1) {
+            // don't include leading comments
+            // so that it doesn't start with "// " and get caught in this again
+            buffer.add(SourceLine('/${block[index].text}'));
+          }
+        } else {
+          subLine ??= block[index];
+          buffer.add(block[index]);
+        }
+      }
+      if (blocks > 0) {
+        if (subLine != null) {
+          subsections.addAll(_processBlock(buffer));
+        }
+        // Combine all of the subsections into one section, now that they've been processed.
+        return subsections;
+      } else {
+        return block;
+      }
+    }
+  }
+
+  /// Parses the input for the various code and description segments, and
+  /// returns a set of skeleton injections in the order found.
+  List<SkeletonInjection> parseInput(CodeSample sample) {
+    bool inCodeBlock = false;
+    final List<SourceLine> description = <SourceLine>[];
+    final List<SkeletonInjection> components = <SkeletonInjection>[];
+    String? language;
+    final RegExp codeStartEnd =
+        RegExp(r'^\s*```(?<language>[-\w]+|[-\w]+ (?<section>[-\w]+))?\s*$');
+    for (final SourceLine line in sample.input) {
+      final RegExpMatch? match = codeStartEnd.firstMatch(line.text);
+      if (match != null) {
+        // If we saw the start or end of a code block
+        inCodeBlock = !inCodeBlock;
+        if (match.namedGroup('language') != null) {
+          language = match[1];
+          if (match.namedGroup('section') != null) {
+            components.add(SkeletonInjection(
+                'code-${match.namedGroup('section')}', <SourceLine>[],
+                language: language!));
+          } else {
+            components.add(
+                SkeletonInjection('code', <SourceLine>[], language: language!));
+          }
+        } else {
+          language = null;
+        }
+        continue;
+      }
+      if (!inCodeBlock) {
+        description.add(line);
+      } else {
+        assert(language != null);
+        components.last.contents.add(line);
+      }
+    }
+    final List<String> descriptionLines = <String>[];
+    bool lastWasWhitespace = false;
+    for (final String line in description
+        .map<String>((SourceLine line) => line.text.trimRight())) {
+      final bool onlyWhitespace = line.trim().isEmpty;
+      if (onlyWhitespace && descriptionLines.isEmpty) {
+        // Don't add whitespace lines until we see something without whitespace.
+        lastWasWhitespace = onlyWhitespace;
+        continue;
+      }
+      if (onlyWhitespace && lastWasWhitespace) {
+        // Don't add more than one whitespace line in a row.
+        continue;
+      }
+      descriptionLines.add(line);
+      lastWasWhitespace = onlyWhitespace;
+    }
+    sample.description = descriptionLines.join('\n').trimRight();
+    sample.parts = <SkeletonInjection>[
+      if (sample is SnippetSample)
+        SkeletonInjection('#assumptions', sample.assumptions),
+      ...components,
+    ];
+    return sample.parts;
+  }
+
+  String _loadFileAsUtf8(File file) {
+    return file.readAsStringSync();
+  }
+
+  /// Generate the HTML using the skeleton file for the type of the given sample.
+  ///
+  /// Returns a string with the HTML needed to embed in a web page for showing a
+  /// sample on the web page.
+  String generateHtml(CodeSample sample) {
+    final String skeleton =
+        _loadFileAsUtf8(configuration.getHtmlSkeletonFile(sample.type));
+    return interpolateSkeleton(sample, skeleton);
+  }
+
+  // Sets the description string on the sample and in the sample metadata to a
+  // comment version of the description.
+  // Trims lines of extra whitespace, and strips leading and trailing blank
+  // lines.
+  String _getDescription(CodeSample sample) {
+    return sample.description.splitMapJoin(
+      '\n',
+      onMatch: (Match match) => match.group(0)!,
+      onNonMatch: (String nonmatch) =>
+          nonmatch.trimRight().isEmpty ? '//' : '// ${nonmatch.trimRight()}',
+    );
+  }
+
+  /// The main routine for generating code samples from the source code doc comments.
+  ///
+  /// The `sample` is the block of sample code from a dartdoc comment.
+  ///
+  /// The optional `output` is the file to write the generated sample code to.
+  ///
+  /// If `includeAssumptions` is true, then the block in the "Examples can
+  /// assume:" block will also be included in the output.
+  ///
+  /// Returns a string containing the resulting code sample.
+  String generateCode(
+    CodeSample sample, {
+    File? output,
+    String? copyright,
+    String? description,
+    bool formatOutput = true,
+    bool includeAssumptions = false,
+  }) {
+    sample.metadata['copyright'] ??= copyright;
+    final List<SkeletonInjection> snippetData = parseInput(sample);
+    sample.description = description ?? sample.description;
+    sample.metadata['description'] = _getDescription(sample);
+    switch (sample) {
+      case DartpadSample _:
+      case ApplicationSample _:
+        final String app = sample.sourceFileContents;
+        sample.output = app;
+        if (formatOutput) {
+          final DartFormatter formatter =
+              DartFormatter(pageWidth: 80, fixes: StyleFix.all);
+          try {
+            sample.output = formatter.format(sample.output);
+          } on FormatterException catch (exception) {
+            io.stderr
+                .write('Code to format:\n${_addLineNumbers(sample.output)}\n');
+            errorExit('Unable to format sample code: $exception');
+          }
+          sample.output = sortImports(sample.output);
+        }
+        if (output != null) {
+          output.writeAsStringSync(sample.output);
+
+          final File metadataFile = configuration.filesystem.file(path.join(
+              path.dirname(output.path),
+              '${path.basenameWithoutExtension(output.path)}.json'));
+          sample.metadata['file'] = path.basename(output.path);
+          final Map<String, Object?> metadata = sample.metadata;
+          if (metadata.containsKey('description')) {
+            metadata['description'] = (metadata['description']! as String)
+                .replaceAll(RegExp(r'^// ?', multiLine: true), '');
+          }
+          metadataFile.writeAsStringSync(jsonEncoder.convert(metadata));
+        }
+      case SnippetSample _:
+          String app;
+          if (sample.sourceFile == null) {
+            String templateContents;
+            if (includeAssumptions) {
+              templateContents =
+                  '${headers.map<String>((SourceLine line) {
+                    return line.text;
+                  }).join('\n')}\n{{#assumptions}}\n{{description}}\n{{code}}';
+            } else {
+              templateContents = '{{description}}\n{{code}}';
+            }
+            app = interpolateTemplate(
+              snippetData,
+              templateContents,
+              sample.metadata,
+              addCopyright: copyright != null,
+            );
+          } else {
+            app = sample.inputAsString;
+          }
+          sample.output = app;
+    }
+    return sample.output;
+  }
+
+  String _addLineNumbers(String code) {
+    final StringBuffer buffer = StringBuffer();
+    int count = 0;
+    for (final String line in code.split('\n')) {
+      count++;
+      buffer.writeln('${count.toString().padLeft(5)}: $line');
+    }
+    return buffer.toString();
+  }
+
+  /// Computes the headers needed for each snippet file.
+  ///
+  /// Not used for "sample" and "dartpad" samples, which use their own template.
+  List<SourceLine> get headers {
+    return _headers ??= <String>[
+      '// generated code',
+      '// ignore_for_file: unused_import',
+      '// ignore_for_file: unused_element',
+      '// ignore_for_file: unused_local_variable',
+      "import 'dart:async';",
+      "import 'dart:convert';",
+      "import 'dart:math' as math;",
+      "import 'dart:typed_data';",
+      "import 'dart:ui' as ui;",
+      "import 'package:flutter_test/flutter_test.dart';",
+      for (final File file in _listDartFiles(FlutterInformation.instance
+          .getFlutterRoot()
+          .childDirectory('packages')
+          .childDirectory('flutter')
+          .childDirectory('lib'))) ...<String>[
+        '',
+        '// ${file.path}',
+        "import 'package:flutter/${path.basename(file.path)}';",
+      ],
+    ].map<SourceLine>((String code) => SourceLine(code)).toList();
+  }
+
+  List<SourceLine>? _headers;
+
+  static List<File> _listDartFiles(Directory directory,
+      {bool recursive = false}) {
+    return directory
+        .listSync(recursive: recursive, followLinks: false)
+        .whereType<File>()
+        .where((File file) => path.extension(file.path) == '.dart')
+        .toList();
+  }
+}
diff --git a/dev/snippets/lib/src/snippet_parser.dart b/dev/snippets/lib/src/snippet_parser.dart
new file mode 100644
index 0000000000000000000000000000000000000000..9678d6e0ca930d2c2c85ee33b9375d98f32afec2
--- /dev/null
+++ b/dev/snippets/lib/src/snippet_parser.dart
@@ -0,0 +1,426 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:path/path.dart' as path;
+
+import 'data_types.dart';
+import 'util.dart';
+
+/// Parses [CodeSample]s from the source file given to one of the parsing routines.
+///
+/// - [parseFromDartdocToolFile] parses the output of the dartdoc `@tool`
+///   directive, which contains the dartdoc comment lines (with comment markers
+///   stripped) contained between the tool markers.
+///
+/// - [parseAndAddAssumptions] parses the assumptions in the "Examples can
+///   assume:" block at the top of the file and adds them to the code samples
+///   contained in the given [SourceElement] iterable.
+class SnippetDartdocParser {
+  SnippetDartdocParser(this.filesystem);
+
+  final FileSystem filesystem;
+
+  /// The prefix of each comment line
+  static const String _dartDocPrefix = '///';
+
+  /// The prefix of each comment line with a space appended.
+  static const String _dartDocPrefixWithSpace = '$_dartDocPrefix ';
+
+  /// A RegExp that matches the beginning of a dartdoc snippet or sample.
+  static final RegExp _dartDocSampleBeginRegex =
+      RegExp(r'\{@tool (?<type>sample|snippet|dartpad)(?:| (?<args>[^}]*))\}');
+
+  /// A RegExp that matches the end of a dartdoc snippet or sample.
+  static final RegExp _dartDocSampleEndRegex = RegExp(r'\{@end-tool\}');
+
+  /// A RegExp that matches the start of a code block within dartdoc.
+  static final RegExp _codeBlockStartRegex = RegExp(r'///\s+```dart.*$');
+
+  /// A RegExp that matches the end of a code block within dartdoc.
+  static final RegExp _codeBlockEndRegex = RegExp(r'///\s+```\s*$');
+
+  /// A RegExp that matches a linked sample pointer.
+  static final RegExp _filePointerRegex =
+      RegExp(r'\*\* See code in (?<file>[^\]]+) \*\*');
+
+  /// Parses the assumptions in the "Examples can assume:" block at the top of
+  /// the `assumptionsFile` and adds them to the code samples contained in the
+  /// given `elements` iterable.
+  void parseAndAddAssumptions(
+    Iterable<SourceElement> elements,
+    File assumptionsFile, {
+    bool silent = true,
+  }) {
+    final List<SourceLine> assumptions = parseAssumptions(assumptionsFile);
+    for (final CodeSample sample in elements
+        .expand<CodeSample>((SourceElement element) => element.samples)) {
+      if (sample is SnippetSample) {
+        sample.assumptions = assumptions;
+      }
+      sample.metadata.addAll(<String, Object?>{
+        'id': '${sample.element}.${sample.index}',
+        'element': sample.element,
+        'sourcePath': assumptionsFile.path,
+        'sourceLine': sample.start.line,
+      });
+    }
+  }
+
+  /// Parses a file containing the output of the dartdoc `@tool` directive,
+  /// which contains the dartdoc comment lines (with comment markers stripped)
+  /// between the tool markers.
+  ///
+  /// This is meant to be run as part of a dartdoc tool that handles snippets.
+  SourceElement parseFromDartdocToolFile(
+    File input, {
+    int? startLine,
+    String? element,
+    required File sourceFile,
+    String type = '',
+    bool silent = true,
+  }) {
+    final List<SourceLine> lines = <SourceLine>[];
+    int lineNumber = startLine ?? 0;
+    final List<String> inputStrings = <String>[
+      // The parser wants to read the arguments from the input, so we create a new
+      // tool line to match the given arguments, so that we can use the same parser for
+      // editing and docs generation.
+      '/// {@tool $type}',
+      // Snippet input comes in with the comment markers stripped, so we add them
+      // back to make it conform to the source format, so we can use the same
+      // parser for editing samples as we do for processing docs.
+      ...input
+          .readAsLinesSync()
+          .map<String>((String line) => '/// $line'.trimRight()),
+      '/// {@end-tool}',
+    ];
+    for (final String line in inputStrings) {
+      lines.add(
+        SourceLine(line,
+            element: element ?? '', line: lineNumber, file: sourceFile),
+      );
+      lineNumber++;
+    }
+    // No need to get assumptions: dartdoc won't give that to us.
+    final SourceElement newElement = SourceElement(
+        SourceElementType.unknownType, element!, -1,
+        file: input, comment: lines);
+    parseFromComments(<SourceElement>[newElement], silent: silent);
+    for (final CodeSample sample in newElement.samples) {
+      sample.metadata.addAll(<String, Object?>{
+        'id': '${sample.element}.${sample.index}',
+        'element': sample.element,
+        'sourcePath': sourceFile.path,
+        'sourceLine': sample.start.line,
+      });
+    }
+    return newElement;
+  }
+
+  /// This parses the assumptions in the "Examples can assume:" block from the
+  /// given `file`.
+  List<SourceLine> parseAssumptions(File file) {
+    // Whether or not we're in the file-wide preamble section ("Examples can assume").
+    bool inPreamble = false;
+    final List<SourceLine> preamble = <SourceLine>[];
+    int lineNumber = 0;
+    int charPosition = 0;
+    for (final String line in file.readAsLinesSync()) {
+      if (inPreamble && line.trim().isEmpty) {
+        // Reached the end of the preamble.
+        break;
+      }
+      if (!line.startsWith('// ')) {
+        lineNumber++;
+        charPosition += line.length + 1;
+        continue;
+      }
+      if (line == '// Examples can assume:') {
+        inPreamble = true;
+        lineNumber++;
+        charPosition += line.length + 1;
+        continue;
+      }
+      if (inPreamble) {
+        preamble.add(SourceLine(
+          line.substring(3),
+          startChar: charPosition,
+          endChar: charPosition + line.length + 1,
+          element: '#assumptions',
+          file: file,
+          line: lineNumber,
+        ));
+      }
+      lineNumber++;
+      charPosition += line.length + 1;
+    }
+    return preamble;
+  }
+
+  /// This parses the code snippets from the documentation comments in the given
+  /// `elements`, and sets the resulting samples as the `samples` member of
+  /// each element in the supplied iterable.
+  void parseFromComments(
+    Iterable<SourceElement> elements, {
+    bool silent = true,
+  }) {
+    int dartpadCount = 0;
+    int sampleCount = 0;
+    int snippetCount = 0;
+
+    for (final SourceElement element in elements) {
+      if (element.comment.isEmpty) {
+        continue;
+      }
+      parseComment(element);
+      for (final CodeSample sample in element.samples) {
+        switch (sample) {
+          case DartpadSample _:
+            dartpadCount++;
+          case ApplicationSample _:
+            sampleCount++;
+          case SnippetSample _:
+            snippetCount++;
+        }
+      }
+    }
+
+    if (!silent) {
+      print('Found:\n'
+          '  $snippetCount snippet code blocks,\n'
+          '  $sampleCount non-dartpad sample code sections, and\n'
+          '  $dartpadCount dartpad sections.\n');
+    }
+  }
+
+  /// This parses the documentation comment on a single [SourceElement] and
+  /// assigns the resulting samples to the `samples` member of the given
+  /// `element`.
+  void parseComment(SourceElement element) {
+    // Whether or not we're in a snippet code sample.
+    bool inSnippet = false;
+    // Whether or not we're in a '```dart' segment.
+    bool inDart = false;
+    bool foundSourceLink = false;
+    bool foundDartSection = false;
+    File? linkedFile;
+    List<SourceLine> block = <SourceLine>[];
+    List<String> snippetArgs = <String>[];
+    final List<CodeSample> samples = <CodeSample>[];
+    final Directory flutterRoot = FlutterInformation.instance.getFlutterRoot();
+
+    int index = 0;
+    for (final SourceLine line in element.comment) {
+      final String trimmedLine = line.text.trim();
+      if (inSnippet) {
+        if (!trimmedLine.startsWith(_dartDocPrefix)) {
+          throw SnippetException('Snippet section unterminated.',
+              file: line.file?.path, line: line.line);
+        }
+        if (_dartDocSampleEndRegex.hasMatch(trimmedLine)) {
+          switch (snippetArgs.first) {
+            case 'snippet':
+              samples.add(
+                SnippetSample(
+                  block,
+                  index: index++,
+                  lineProto: line,
+                ),
+              );
+            case 'sample':
+              if (linkedFile != null) {
+                samples.add(
+                  ApplicationSample.fromFile(
+                    input: block,
+                    args: snippetArgs,
+                    sourceFile: linkedFile,
+                    index: index++,
+                    lineProto: line,
+                  ),
+                );
+                break;
+              }
+              samples.add(
+                ApplicationSample(
+                  input: block,
+                  args: snippetArgs,
+                  index: index++,
+                  lineProto: line,
+                ),
+              );
+            case 'dartpad':
+              if (linkedFile != null) {
+                samples.add(
+                  DartpadSample.fromFile(
+                    input: block,
+                    args: snippetArgs,
+                    sourceFile: linkedFile,
+                    index: index++,
+                    lineProto: line,
+                  ),
+                );
+                break;
+              }
+              samples.add(
+                DartpadSample(
+                  input: block,
+                  args: snippetArgs,
+                  index: index++,
+                  lineProto: line,
+                ),
+              );
+            default:
+              throw SnippetException(
+                  'Unknown snippet type ${snippetArgs.first}');
+          }
+          snippetArgs = <String>[];
+          block = <SourceLine>[];
+          inSnippet = false;
+          foundSourceLink = false;
+          foundDartSection = false;
+          linkedFile = null;
+        } else if (_filePointerRegex.hasMatch(trimmedLine)) {
+          foundSourceLink = true;
+          if (foundDartSection) {
+            throw SnippetException(
+              'Snippet contains a source link and a dart section. Cannot contain both.',
+              file: line.file?.path,
+              line: line.line,
+            );
+          }
+          if (linkedFile != null) {
+            throw SnippetException(
+              'Found more than one linked sample. Only one linked file per sample is allowed.',
+              file: line.file?.path,
+              line: line.line,
+            );
+          }
+          final RegExpMatch match = _filePointerRegex.firstMatch(trimmedLine)!;
+          linkedFile = filesystem.file(
+              path.join(flutterRoot.absolute.path, match.namedGroup('file')));
+        } else {
+          block.add(line.copyWith(
+              text: line.text.replaceFirst(RegExp(r'\s*/// ?'), '')));
+        }
+      } else {
+        if (_dartDocSampleEndRegex.hasMatch(trimmedLine)) {
+          if (inDart) {
+            throw SnippetException(
+                "Dart section didn't terminate before end of sample",
+                file: line.file?.path,
+                line: line.line);
+          }
+        }
+        if (inDart) {
+          if (_codeBlockEndRegex.hasMatch(trimmedLine)) {
+            inDart = false;
+            block = <SourceLine>[];
+          } else if (trimmedLine == _dartDocPrefix) {
+            block.add(line.copyWith(text: ''));
+          } else {
+            final int index = line.text.indexOf(_dartDocPrefixWithSpace);
+            if (index < 0) {
+              throw SnippetException(
+                'Dart section inexplicably did not contain "$_dartDocPrefixWithSpace" prefix.',
+                file: line.file?.path,
+                line: line.line,
+              );
+            }
+            block.add(line.copyWith(text: line.text.substring(index + 4)));
+          }
+        } else if (_codeBlockStartRegex.hasMatch(trimmedLine)) {
+          if (foundSourceLink) {
+            throw SnippetException(
+              'Snippet contains a source link and a dart section. Cannot contain both.',
+              file: line.file?.path,
+              line: line.line,
+            );
+          }
+          assert(block.isEmpty);
+          inDart = true;
+          foundDartSection = true;
+        }
+      }
+      if (!inSnippet && !inDart) {
+        final RegExpMatch? sampleMatch =
+            _dartDocSampleBeginRegex.firstMatch(trimmedLine);
+        if (sampleMatch != null) {
+          inSnippet = sampleMatch.namedGroup('type') == 'snippet' ||
+              sampleMatch.namedGroup('type') == 'sample' ||
+              sampleMatch.namedGroup('type') == 'dartpad';
+          if (inSnippet) {
+            if (sampleMatch.namedGroup('args') != null) {
+              // There are arguments to the snippet tool to keep track of.
+              snippetArgs = <String>[
+                sampleMatch.namedGroup('type')!,
+                ..._splitUpQuotedArgs(sampleMatch.namedGroup('args')!)
+              ];
+            } else {
+              snippetArgs = <String>[
+                sampleMatch.namedGroup('type')!,
+              ];
+            }
+          }
+        }
+      }
+    }
+    for (final CodeSample sample in samples) {
+      sample.metadata.addAll(<String, Object?>{
+        'id': '${sample.element}.${sample.index}',
+        'element': sample.element,
+        'sourcePath': sample.start.file?.path ?? '',
+        'sourceLine': sample.start.line,
+      });
+    }
+    element.replaceSamples(samples);
+  }
+
+  // Helper to process arguments given as a (possibly quoted) string.
+  //
+  // First, this will split the given [argsAsString] into separate arguments,
+  // taking any quoting (either ' or " are accepted) into account, including
+  // handling backslash-escaped quotes.
+  //
+  // Then, it will prepend "--" to any args that start with an identifier
+  // followed by an equals sign, allowing the argument parser to treat any
+  // "foo=bar" argument as "--foo=bar" (which is a dartdoc-ism).
+  Iterable<String> _splitUpQuotedArgs(String argsAsString) {
+    // This function is used because the arg parser package doesn't handle
+    // quoted args.
+
+    // Regexp to take care of splitting arguments, and handling the quotes
+    // around arguments, if any.
+    //
+    // Match group 1 (option) is the "foo=" (or "--foo=") part of the option, if any.
+    // Match group 2 (quote) contains the quote character used (which is discarded).
+    // Match group 3 (value) is a quoted arg, if any, without the quotes.
+    // Match group 4 (unquoted) is the unquoted arg, if any.
+    final RegExp argMatcher = RegExp(
+        r'(?<option>[-_a-zA-Z0-9]+=)?' // option name
+        r'(?:' // Start a new non-capture group for the two possibilities.
+        r'''(?<quote>["'])(?<value>(?:\\{2})*|(?:.*?[^\\](?:\\{2})*))\2|''' // value with quotes.
+        r'(?<unquoted>[^ ]+))'); // without quotes.
+    final Iterable<RegExpMatch> matches = argMatcher.allMatches(argsAsString);
+
+    // Remove quotes around args, then for any args that look like assignments
+    // (start with valid option names followed by an equals sign), add a "--" in
+    // front so that they parse as options to support legacy dartdoc
+    // functionality of "option=value".
+    return matches.map<String>((RegExpMatch match) {
+      String option = '';
+      if (match.namedGroup('option') != null &&
+          !match.namedGroup('option')!.startsWith('-')) {
+        option = '--';
+      }
+      if (match.namedGroup('quote') != null) {
+        // This arg has quotes, so strip them.
+        return '$option'
+            '${match.namedGroup('value') ?? ''}'
+            '${match.namedGroup('unquoted') ?? ''}';
+      }
+      return '$option${match[0]}';
+    });
+  }
+}
diff --git a/dev/snippets/lib/src/util.dart b/dev/snippets/lib/src/util.dart
new file mode 100644
index 0000000000000000000000000000000000000000..e0c6f5cbc1269dd191a0a8640ab9bde2ad5fa58e
--- /dev/null
+++ b/dev/snippets/lib/src/util.dart
@@ -0,0 +1,271 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io' as io;
+
+import 'package:file/file.dart';
+import 'package:file/local.dart';
+import 'package:meta/meta.dart';
+import 'package:platform/platform.dart' show LocalPlatform, Platform;
+import 'package:process/process.dart' show LocalProcessManager, ProcessManager;
+import 'package:pub_semver/pub_semver.dart';
+
+import 'data_types.dart';
+
+/// An exception class to allow capture of exceptions generated by the Snippets
+/// package.
+class SnippetException implements Exception {
+  SnippetException(this.message, {this.file, this.line});
+  final String message;
+  final String? file;
+  final int? line;
+
+  @override
+  String toString() {
+    if (file != null || line != null) {
+      final String fileStr = file == null ? '' : '$file:';
+      final String lineStr = line == null ? '' : '$line:';
+      return '$runtimeType: $fileStr$lineStr: $message';
+    } else {
+      return '$runtimeType: $message';
+    }
+  }
+}
+
+/// Gets the number of whitespace characters at the beginning of a line.
+int getIndent(String line) => line.length - line.trimLeft().length;
+
+/// Contains information about the installed Flutter repo.
+class FlutterInformation {
+  FlutterInformation({
+    this.platform = const LocalPlatform(),
+    this.processManager = const LocalProcessManager(),
+    this.filesystem = const LocalFileSystem(),
+  });
+
+  final Platform platform;
+  final ProcessManager processManager;
+  final FileSystem filesystem;
+
+  static FlutterInformation? _instance;
+
+  static FlutterInformation get instance => _instance ??= FlutterInformation();
+
+  @visibleForTesting
+  static set instance(FlutterInformation? value) => _instance = value;
+
+  Directory getFlutterRoot() {
+    if (platform.environment['FLUTTER_ROOT'] != null) {
+      return filesystem.directory(platform.environment['FLUTTER_ROOT']);
+    }
+    return getFlutterInformation()['flutterRoot'] as Directory;
+  }
+
+  Version getFlutterVersion() =>
+      getFlutterInformation()['frameworkVersion'] as Version;
+
+  Version getDartSdkVersion() =>
+      getFlutterInformation()['dartSdkVersion'] as Version;
+
+  Map<String, dynamic>? _cachedFlutterInformation;
+
+  Map<String, dynamic> getFlutterInformation() {
+    if (_cachedFlutterInformation != null) {
+      return _cachedFlutterInformation!;
+    }
+
+    String flutterVersionJson;
+    if (platform.environment['FLUTTER_VERSION'] != null) {
+      flutterVersionJson = platform.environment['FLUTTER_VERSION']!;
+    } else {
+      String flutterCommand;
+      if (platform.environment['FLUTTER_ROOT'] != null) {
+        flutterCommand = filesystem
+            .directory(platform.environment['FLUTTER_ROOT'])
+            .childDirectory('bin')
+            .childFile('flutter')
+            .absolute
+            .path;
+      } else {
+        flutterCommand = 'flutter';
+      }
+      io.ProcessResult result;
+      try {
+        result = processManager.runSync(
+            <String>[flutterCommand, '--version', '--machine'],
+            stdoutEncoding: utf8);
+      } on io.ProcessException catch (e) {
+        throw SnippetException(
+            'Unable to determine Flutter information. Either set FLUTTER_ROOT, or place flutter command in your path.\n$e');
+      }
+      if (result.exitCode != 0) {
+        throw SnippetException(
+            'Unable to determine Flutter information, because of abnormal exit to flutter command.');
+      }
+      flutterVersionJson = (result.stdout as String).replaceAll(
+          'Waiting for another flutter command to release the startup lock...',
+          '');
+    }
+
+    final Map<String, dynamic> flutterVersion =
+        json.decode(flutterVersionJson) as Map<String, dynamic>;
+    if (flutterVersion['flutterRoot'] == null ||
+        flutterVersion['frameworkVersion'] == null ||
+        flutterVersion['dartSdkVersion'] == null) {
+      throw SnippetException(
+          'Flutter command output has unexpected format, unable to determine flutter root location.');
+    }
+
+    final Map<String, dynamic> info = <String, dynamic>{};
+    info['flutterRoot'] =
+        filesystem.directory(flutterVersion['flutterRoot']! as String);
+    info['frameworkVersion'] =
+        Version.parse(flutterVersion['frameworkVersion'] as String);
+
+    final RegExpMatch? dartVersionRegex =
+        RegExp(r'(?<base>[\d.]+)(?:\s+\(build (?<detail>[-.\w]+)\))?')
+            .firstMatch(flutterVersion['dartSdkVersion'] as String);
+    if (dartVersionRegex == null) {
+      throw SnippetException(
+          'Flutter command output has unexpected format, unable to parse dart SDK version ${flutterVersion['dartSdkVersion']}.');
+    }
+    info['dartSdkVersion'] = Version.parse(
+        dartVersionRegex.namedGroup('detail') ??
+            dartVersionRegex.namedGroup('base')!);
+    _cachedFlutterInformation = info;
+
+    return info;
+  }
+}
+
+/// Injects the [injections] into the [template], while turning the
+/// "description" injection into a comment.
+String interpolateTemplate(
+  List<SkeletonInjection> injections,
+  String template,
+  Map<String, Object?> metadata, {
+  bool addCopyright = false,
+}) {
+  String wrapSectionMarker(Iterable<String> contents, {required String name}) {
+    if (contents.join().trim().isEmpty) {
+      // Skip empty sections.
+      return '';
+    }
+    // We don't wrap some sections, because otherwise they generate invalid files.
+    final String result = <String>[
+      ...contents,
+    ].join('\n');
+    final RegExp wrappingNewlines = RegExp(r'^\n*(.*)\n*$', dotAll: true);
+    return result.replaceAllMapped(
+        wrappingNewlines, (Match match) => match.group(1)!);
+  }
+
+  return '${addCopyright ? '{{copyright}}\n\n' : ''}$template'
+      .replaceAllMapped(RegExp(r'{{([^}]+)}}'), (Match match) {
+    final String name = match[1]!;
+    final int componentIndex = injections
+        .indexWhere((SkeletonInjection injection) => injection.name == name);
+    if (metadata[name] != null && componentIndex == -1) {
+      // If the match isn't found in the injections, then just return the
+      // metadata entry.
+      return wrapSectionMarker((metadata[name]! as String).split('\n'),
+          name: name);
+    }
+    return wrapSectionMarker(
+        componentIndex >= 0
+            ? injections[componentIndex].stringContents
+            : <String>[],
+        name: name);
+  }).replaceAll(RegExp(r'\n\n+'), '\n\n');
+}
+
+class SampleStats {
+  const SampleStats({
+    this.totalSamples = 0,
+    this.dartpadSamples = 0,
+    this.snippetSamples = 0,
+    this.applicationSamples = 0,
+    this.wordCount = 0,
+    this.lineCount = 0,
+    this.linkCount = 0,
+    this.description = '',
+  });
+
+  final int totalSamples;
+  final int dartpadSamples;
+  final int snippetSamples;
+  final int applicationSamples;
+  final int wordCount;
+  final int lineCount;
+  final int linkCount;
+  final String description;
+  bool get allOneKind =>
+      totalSamples == snippetSamples ||
+      totalSamples == applicationSamples ||
+      totalSamples == dartpadSamples;
+
+  @override
+  String toString() {
+    return description;
+  }
+}
+
+Iterable<CodeSample> getSamplesInElements(Iterable<SourceElement>? elements) {
+  return elements
+          ?.expand<CodeSample>((SourceElement element) => element.samples) ??
+      const <CodeSample>[];
+}
+
+SampleStats getSampleStats(SourceElement element) {
+  if (element.comment.isEmpty) {
+    return const SampleStats();
+  }
+  final int total = element.sampleCount;
+  if (total == 0) {
+    return const SampleStats();
+  }
+  final int dartpads = element.dartpadSampleCount;
+  final int snippets = element.snippetCount;
+  final int applications = element.applicationSampleCount;
+  final String sampleCount = <String>[
+    if (snippets > 0) '$snippets snippet${snippets != 1 ? 's' : ''}',
+    if (applications > 0)
+      '$applications application sample${applications != 1 ? 's' : ''}',
+    if (dartpads > 0) '$dartpads dartpad sample${dartpads != 1 ? 's' : ''}'
+  ].join(', ');
+  final int wordCount = element.wordCount;
+  final int lineCount = element.lineCount;
+  final int linkCount = element.referenceCount;
+  final String description = <String>[
+    'Documentation has $wordCount ${wordCount == 1 ? 'word' : 'words'} on ',
+    '$lineCount ${lineCount == 1 ? 'line' : 'lines'}',
+    if (linkCount > 0 && element.hasSeeAlso) ', ',
+    if (linkCount > 0 && !element.hasSeeAlso) ' and ',
+    if (linkCount > 0)
+      'refers to $linkCount other ${linkCount == 1 ? 'symbol' : 'symbols'}',
+    if (linkCount > 0 && element.hasSeeAlso) ', and ',
+    if (linkCount == 0 && element.hasSeeAlso) 'and ',
+    if (element.hasSeeAlso) 'has a "See also:" section',
+    '.',
+  ].join();
+  return SampleStats(
+    totalSamples: total,
+    dartpadSamples: dartpads,
+    snippetSamples: snippets,
+    applicationSamples: applications,
+    wordCount: wordCount,
+    lineCount: lineCount,
+    linkCount: linkCount,
+    description: 'Has $sampleCount. $description',
+  );
+}
+
+/// Exit the app with a message to stderr.
+/// Can be overridden by tests to avoid exits.
+// ignore: prefer_function_declarations_over_variables
+void Function(String message) errorExit = (String message) {
+  io.stderr.writeln(message);
+  io.exit(1);
+};
diff --git a/dev/snippets/pubspec.yaml b/dev/snippets/pubspec.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..26408c87d19c5770f6f668d40b60ebf88d20bc70
--- /dev/null
+++ b/dev/snippets/pubspec.yaml
@@ -0,0 +1,64 @@
+name: snippets
+description: A package for parsing and manipulating code samples in Flutter repo dartdoc comments.
+
+environment:
+  sdk: '>=3.2.0-0 <4.0.0'
+
+dependencies:
+  analyzer: 6.4.1
+  args: 2.4.2
+  dart_style: 2.3.6
+  file: 7.0.0
+  meta: 1.12.0
+  path: 1.9.0
+  platform: 3.1.4
+  process: 5.0.2
+
+  _fe_analyzer_shared: 67.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  coverage: 1.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  io: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  js: 0.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  matcher: 0.12.16+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  mime: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  shelf: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  shelf_static: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  test_api: 0.7.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  test_core: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  vm_service: 14.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  web: 0.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  web_socket_channel: 2.4.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+  yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
+
+dev_dependencies:
+  test: 1.25.2
+
+executables:
+  snippets:
+
+# PUBSPEC CHECKSUM: 94f5
diff --git a/dev/snippets/test/configuration_test.dart b/dev/snippets/test/configuration_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..4659b6b1a13865136935379992bfc629506082d6
--- /dev/null
+++ b/dev/snippets/test/configuration_test.dart
@@ -0,0 +1,49 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:file/memory.dart';
+import 'package:snippets/snippets.dart';
+import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
+
+void main() {
+  group('Configuration', () {
+    final MemoryFileSystem memoryFileSystem = MemoryFileSystem();
+    late SnippetConfiguration config;
+
+    setUp(() {
+      config = FlutterRepoSnippetConfiguration(
+        flutterRoot: memoryFileSystem.directory('/flutter sdk'),
+        filesystem: memoryFileSystem,
+      );
+    });
+    test('config directory is correct', () async {
+      expect(config.configDirectory.path,
+          matches(RegExp(r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config')));
+    });
+    test('skeleton directory is correct', () async {
+      expect(
+          config.skeletonsDirectory.path,
+          matches(RegExp(
+              r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons')));
+    });
+    test('html skeleton file for sample is correct', () async {
+      expect(
+          config.getHtmlSkeletonFile('snippet').path,
+          matches(RegExp(
+              r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons[/\\]snippet.html')));
+    });
+    test('html skeleton file for app with no dartpad is correct', () async {
+      expect(
+          config.getHtmlSkeletonFile('sample').path,
+          matches(RegExp(
+              r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons[/\\]sample.html')));
+    });
+    test('html skeleton file for app with dartpad is correct', () async {
+      expect(
+          config.getHtmlSkeletonFile('dartpad').path,
+          matches(RegExp(
+              r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons[/\\]dartpad-sample.html')));
+    });
+  });
+}
diff --git a/dev/snippets/test/fake_process_manager.dart b/dev/snippets/test/fake_process_manager.dart
new file mode 100644
index 0000000000000000000000000000000000000000..db559700ebeeec193f1a0ba8d7e2cb4a7bfc49da
--- /dev/null
+++ b/dev/snippets/test/fake_process_manager.dart
@@ -0,0 +1,33 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:process/process.dart';
+
+class FakeProcessManager extends LocalProcessManager {
+  FakeProcessManager(
+      {this.stdout = '', this.stderr = '', this.exitCode = 0, this.pid = 1});
+
+  int runs = 0;
+  String stdout;
+  String stderr;
+  int exitCode;
+  int pid;
+
+  @override
+  ProcessResult runSync(
+    List<Object> command, {
+    String? workingDirectory,
+    Map<String, String>? environment,
+    bool includeParentEnvironment = true,
+    bool runInShell = false,
+    Encoding? stdoutEncoding = systemEncoding,
+    Encoding? stderrEncoding = systemEncoding,
+  }) {
+    runs++;
+    return ProcessResult(pid, exitCode, stdout, stderr);
+  }
+}
diff --git a/dev/snippets/test/filesystem_resource_provider.dart b/dev/snippets/test/filesystem_resource_provider.dart
new file mode 100644
index 0000000000000000000000000000000000000000..8e1e219d649e7b8d0c530aac1ce29c3dc016e5c8
--- /dev/null
+++ b/dev/snippets/test/filesystem_resource_provider.dart
@@ -0,0 +1,423 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:io' as io;
+import 'dart:typed_data';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/source/source_resource.dart';
+import 'package:file/file.dart' as file;
+import 'package:file/local.dart' as file;
+import 'package:meta/meta.dart';
+import 'package:path/path.dart';
+import 'package:watcher/watcher.dart';
+
+/// The name of the directory containing plugin specific subfolders used to
+/// store data across sessions.
+const String _SERVER_DIR = '.dartServer';
+
+/// Returns the path to default state location.
+///
+/// Generally this is ~/.dartServer. It can be overridden via the
+/// ANALYZER_STATE_LOCATION_OVERRIDE environment variable, in which case this
+/// method will return the contents of that environment variable.
+String? _getStandardStateLocation() {
+  final Map<String, String> env = io.Platform.environment;
+  if (env.containsKey('ANALYZER_STATE_LOCATION_OVERRIDE')) {
+    return env['ANALYZER_STATE_LOCATION_OVERRIDE'];
+  }
+
+  final String? home =
+      io.Platform.isWindows ? env['LOCALAPPDATA'] : env['HOME'];
+  return home != null && io.FileSystemEntity.isDirectorySync(home)
+      ? join(home, _SERVER_DIR)
+      : null;
+}
+
+/// A `dart:io` based implementation of [ResourceProvider].
+class FileSystemResourceProvider implements ResourceProvider {
+  FileSystemResourceProvider(this.filesystem, {String? stateLocation})
+      : _stateLocation = stateLocation ?? _getStandardStateLocation();
+
+  static final FileSystemResourceProvider instance =
+      FileSystemResourceProvider(const file.LocalFileSystem());
+
+  /// The path to the base folder where state is stored.
+  final String? _stateLocation;
+
+  final file.FileSystem filesystem;
+
+  @override
+  Context get pathContext => context;
+
+  @override
+  File getFile(String path) {
+    _ensureAbsoluteAndNormalized(path);
+    return _PhysicalFile(filesystem.file(path));
+  }
+
+  @override
+  Folder getFolder(String path) {
+    _ensureAbsoluteAndNormalized(path);
+    return _PhysicalFolder(filesystem.directory(path));
+  }
+
+  @override
+  Resource getResource(String path) {
+    _ensureAbsoluteAndNormalized(path);
+    if (filesystem.isDirectorySync(path)) {
+      return getFolder(path);
+    } else {
+      return getFile(path);
+    }
+  }
+
+  @override
+  Folder? getStateLocation(String pluginId) {
+    if (_stateLocation != null) {
+      final file.Directory directory =
+          filesystem.directory(join(_stateLocation, pluginId));
+      directory.createSync(recursive: true);
+      return _PhysicalFolder(directory);
+    }
+    return null;
+  }
+
+  /// The file system abstraction supports only absolute and normalized paths.
+  /// This method is used to validate any input paths to prevent errors later.
+  void _ensureAbsoluteAndNormalized(String path) {
+    assert(() {
+      if (!pathContext.isAbsolute(path)) {
+        throw ArgumentError('Path must be absolute : $path');
+      }
+      if (pathContext.normalize(path) != path) {
+        throw ArgumentError('Path must be normalized : $path');
+      }
+      return true;
+    }());
+  }
+}
+
+/// A `dart:io` based implementation of [File].
+class _PhysicalFile extends _PhysicalResource implements File {
+  const _PhysicalFile(io.File super.file);
+
+  @override
+  Stream<WatchEvent> get changes => FileWatcher(_entry.path).events;
+
+  @override
+  int get lengthSync {
+    try {
+      return _file.lengthSync();
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  int get modificationStamp {
+    try {
+      return _file.lastModifiedSync().millisecondsSinceEpoch;
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  /// Return the underlying file being represented by this wrapper.
+  io.File get _file => _entry as io.File;
+
+  @override
+  File copyTo(Folder parentFolder) {
+    parentFolder.create();
+    final File destination = parentFolder.getChildAssumingFile(shortName);
+    destination.writeAsBytesSync(readAsBytesSync());
+    return destination;
+  }
+
+  @override
+  Source createSource([Uri? uri]) {
+    return FileSource(this, uri ?? pathContext.toUri(path));
+  }
+
+  @override
+  bool isOrContains(String path) {
+    return path == this.path;
+  }
+
+  @override
+  Uint8List readAsBytesSync() {
+    _throwIfWindowsDeviceDriver();
+    try {
+      return _file.readAsBytesSync();
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  String readAsStringSync() {
+    _throwIfWindowsDeviceDriver();
+    try {
+      return _file.readAsStringSync();
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  File renameSync(String newPath) {
+    try {
+      return _PhysicalFile(_file.renameSync(newPath));
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  File resolveSymbolicLinksSync() {
+    try {
+      return _PhysicalFile(io.File(_file.resolveSymbolicLinksSync()));
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  Uri toUri() => Uri.file(path);
+
+  @override
+  void writeAsBytesSync(List<int> bytes) {
+    try {
+      _file.writeAsBytesSync(bytes);
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  void writeAsStringSync(String content) {
+    try {
+      _file.writeAsStringSync(content);
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  ResourceWatcher watch() {
+    throw UnimplementedError();
+  }
+}
+
+/// A `dart:io` based implementation of [Folder].
+class _PhysicalFolder extends _PhysicalResource implements Folder {
+  const _PhysicalFolder(io.Directory super.directory);
+
+  @override
+  Stream<WatchEvent> get changes =>
+      DirectoryWatcher(_entry.path).events.handleError((Object error) {},
+          test: (dynamic error) =>
+              error is io.FileSystemException &&
+              // Don't suppress "Directory watcher closed," so the outer
+              // listener can see the interruption & act on it.
+              !error.message
+                  .startsWith('Directory watcher closed unexpectedly'));
+
+  @override
+  bool get isRoot {
+    final String parentPath = provider.pathContext.dirname(path);
+    return parentPath == path;
+  }
+
+  /// Return the underlying file being represented by this wrapper.
+  io.Directory get _directory => _entry as io.Directory;
+
+  @override
+  String canonicalizePath(String relPath) {
+    return normalize(join(path, relPath));
+  }
+
+  @override
+  bool contains(String path) {
+    FileSystemResourceProvider.instance._ensureAbsoluteAndNormalized(path);
+    return pathContext.isWithin(this.path, path);
+  }
+
+  @override
+  Folder copyTo(Folder parentFolder) {
+    final Folder destination = parentFolder.getChildAssumingFolder(shortName);
+    destination.create();
+    for (final Resource child in getChildren()) {
+      child.copyTo(destination);
+    }
+    return destination;
+  }
+
+  @override
+  void create() {
+    _directory.createSync(recursive: true);
+  }
+
+  @override
+  Resource getChild(String relPath) {
+    final String canonicalPath = canonicalizePath(relPath);
+    return FileSystemResourceProvider.instance.getResource(canonicalPath);
+  }
+
+  @override
+  _PhysicalFile getChildAssumingFile(String relPath) {
+    final String canonicalPath = canonicalizePath(relPath);
+    final io.File file = io.File(canonicalPath);
+    return _PhysicalFile(file);
+  }
+
+  @override
+  _PhysicalFolder getChildAssumingFolder(String relPath) {
+    final String canonicalPath = canonicalizePath(relPath);
+    final io.Directory directory = io.Directory(canonicalPath);
+    return _PhysicalFolder(directory);
+  }
+
+  @override
+  List<Resource> getChildren() {
+    try {
+      final List<Resource> children = <Resource>[];
+      final io.Directory directory = _entry as io.Directory;
+      final List<io.FileSystemEntity> entries = directory.listSync();
+      final int numEntries = entries.length;
+      for (int i = 0; i < numEntries; i++) {
+        final io.FileSystemEntity entity = entries[i];
+        if (entity is io.Directory) {
+          children.add(_PhysicalFolder(entity));
+        } else if (entity is io.File) {
+          children.add(_PhysicalFile(entity));
+        }
+      }
+      return children;
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  bool isOrContains(String path) {
+    if (path == this.path) {
+      return true;
+    }
+    return contains(path);
+  }
+
+  @override
+  Folder resolveSymbolicLinksSync() {
+    try {
+      return _PhysicalFolder(
+          io.Directory(_directory.resolveSymbolicLinksSync()));
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  Uri toUri() => Uri.directory(path);
+
+  @override
+  ResourceWatcher watch() {
+    throw UnimplementedError();
+  }
+}
+
+/// A `dart:io` based implementation of [Resource].
+@immutable
+abstract class _PhysicalResource implements Resource {
+  const _PhysicalResource(this._entry);
+
+  final io.FileSystemEntity _entry;
+
+  @override
+  bool get exists {
+    try {
+      return _entry.existsSync();
+    } on FileSystemException {
+      return false;
+    }
+  }
+
+  @override
+  int get hashCode => path.hashCode;
+
+  @override
+  Folder get parent {
+    final String parentPath = pathContext.dirname(path);
+    return _PhysicalFolder(io.Directory(parentPath));
+  }
+
+  @override
+  Folder get parent2 {
+    final String parentPath = pathContext.dirname(path);
+    return _PhysicalFolder(io.Directory(parentPath));
+  }
+
+  @override
+  String get path => _entry.path;
+
+  /// Return the path context used by this resource provider.
+  Context get pathContext => io.Platform.isWindows ? windows : posix;
+
+  @override
+  ResourceProvider get provider => FileSystemResourceProvider.instance;
+
+  @override
+  String get shortName => pathContext.basename(path);
+
+  @override
+  bool operator ==(Object other) {
+    if (runtimeType != other.runtimeType) {
+      return false;
+    }
+    // ignore: test_types_in_equals
+    return path == (other as _PhysicalResource).path;
+  }
+
+  @override
+  void delete() {
+    try {
+      _entry.deleteSync(recursive: true);
+    } on io.FileSystemException catch (exception) {
+      throw _wrapException(exception);
+    }
+  }
+
+  @override
+  String toString() => path;
+
+  /// If the operating system is Windows and the resource references one of the
+  /// device drivers, throw a [FileSystemException].
+  ///
+  /// https://support.microsoft.com/en-us/kb/74496
+  void _throwIfWindowsDeviceDriver() {
+    if (io.Platform.isWindows) {
+      final String shortName = this.shortName.toUpperCase();
+      if (shortName == r'CON' ||
+          shortName == r'PRN' ||
+          shortName == r'AUX' ||
+          shortName == r'CLOCK$' ||
+          shortName == r'NUL' ||
+          shortName == r'COM1' ||
+          shortName == r'LPT1' ||
+          shortName == r'LPT2' ||
+          shortName == r'LPT3' ||
+          shortName == r'COM2' ||
+          shortName == r'COM3' ||
+          shortName == r'COM4') {
+        throw FileSystemException(
+            path, 'Windows device drivers cannot be read.');
+      }
+    }
+  }
+
+  FileSystemException _wrapException(io.FileSystemException e) {
+    return FileSystemException(e.path ?? path, e.message);
+  }
+}
diff --git a/dev/snippets/test/import_sorter_test.dart b/dev/snippets/test/import_sorter_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1beffe50485bca75bcffe5e774fc278fb5bb0a8d
--- /dev/null
+++ b/dev/snippets/test/import_sorter_test.dart
@@ -0,0 +1,103 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:path/path.dart' as path;
+import 'package:pub_semver/pub_semver.dart';
+import 'package:snippets/snippets.dart';
+import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
+
+class FakeFlutterInformation extends FlutterInformation {
+  FakeFlutterInformation(this.flutterRoot);
+
+  final Directory flutterRoot;
+
+  @override
+  Map<String, dynamic> getFlutterInformation() {
+    return <String, dynamic>{
+      'flutterRoot': flutterRoot,
+      'frameworkVersion': Version(2, 10, 0),
+      'dartSdkVersion': Version(2, 12, 1),
+    };
+  }
+}
+
+void main() {
+  late MemoryFileSystem memoryFileSystem = MemoryFileSystem();
+  late Directory tmpDir;
+
+  setUp(() {
+    // Create a new filesystem.
+    memoryFileSystem = MemoryFileSystem();
+    tmpDir = memoryFileSystem.systemTempDirectory
+        .createTempSync('flutter_snippets_test.');
+    final Directory flutterRoot =
+        memoryFileSystem.directory(path.join(tmpDir.absolute.path, 'flutter'));
+    FlutterInformation.instance = FakeFlutterInformation(flutterRoot);
+  });
+
+  test('Sorting packages works', () async {
+    final String result = sortImports('''
+// Unit comment
+
+// third import
+import 'packages:gamma/gamma.dart'; // third
+
+// second import
+import 'packages:beta/beta.dart'; // second
+
+// first import
+import 'packages:alpha/alpha.dart'; // first
+
+void main() {}
+''');
+    expect(result, equals('''
+// Unit comment
+
+// first import
+import 'packages:alpha/alpha.dart'; // first
+// second import
+import 'packages:beta/beta.dart'; // second
+// third import
+import 'packages:gamma/gamma.dart'; // third
+
+void main() {}
+'''));
+  });
+  test('Sorting dart and packages works', () async {
+    final String result = sortImports('''
+// Unit comment
+
+// third import
+import 'packages:gamma/gamma.dart'; // third
+
+// second import
+import 'packages:beta/beta.dart'; // second
+
+// first import
+import 'packages:alpha/alpha.dart'; // first
+
+// first dart
+import 'dart:async';
+
+void main() {}
+''');
+    expect(result, equals('''
+// Unit comment
+
+// first dart
+import 'dart:async';
+
+// first import
+import 'packages:alpha/alpha.dart'; // first
+// second import
+import 'packages:beta/beta.dart'; // second
+// third import
+import 'packages:gamma/gamma.dart'; // third
+
+void main() {}
+'''));
+  });
+}
diff --git a/dev/snippets/test/snippet_parser_test.dart b/dev/snippets/test/snippet_parser_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..3de2fbe5dbaaea4c5ee45393ce46c91085d1d009
--- /dev/null
+++ b/dev/snippets/test/snippet_parser_test.dart
@@ -0,0 +1,292 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:path/path.dart' as path;
+import 'package:pub_semver/pub_semver.dart';
+import 'package:snippets/snippets.dart';
+import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
+
+import 'filesystem_resource_provider.dart';
+
+class FakeFlutterInformation extends FlutterInformation {
+  FakeFlutterInformation(this.flutterRoot);
+
+  final Directory flutterRoot;
+
+  @override
+  Directory getFlutterRoot() {
+    return flutterRoot;
+  }
+
+  @override
+  Map<String, dynamic> getFlutterInformation() {
+    return <String, dynamic>{
+      'flutterRoot': flutterRoot,
+      'frameworkVersion': Version(2, 10, 0),
+      'dartSdkVersion': Version(2, 12, 1),
+    };
+  }
+}
+
+void main() {
+  group('Parser', () {
+    late MemoryFileSystem memoryFileSystem = MemoryFileSystem();
+    late FlutterRepoSnippetConfiguration configuration;
+    late SnippetGenerator generator;
+    late Directory tmpDir;
+    late Directory flutterRoot;
+
+    void writeSkeleton(String type) {
+      switch (type) {
+        case 'dartpad':
+          configuration.getHtmlSkeletonFile('dartpad').writeAsStringSync('''
+<div>HTML Bits (DartPad-style)</div>
+<iframe class="snippet-dartpad" src="https://dartpad.dev/embed-flutter.html?split=60&run=true&sample_id={{id}}&sample_channel={{channel}}"></iframe>
+<div>More HTML Bits</div>
+''');
+        case 'sample':
+        case 'snippet':
+          configuration.getHtmlSkeletonFile(type).writeAsStringSync('''
+<div>HTML Bits</div>
+{{description}}
+<pre>{{code}}</pre>
+<pre>{{app}}</pre>
+<div>More HTML Bits</div>
+''');
+      }
+    }
+
+    setUp(() {
+      // Create a new filesystem.
+      memoryFileSystem = MemoryFileSystem();
+      tmpDir = memoryFileSystem.systemTempDirectory
+          .createTempSync('flutter_snippets_test.');
+      flutterRoot = memoryFileSystem
+          .directory(path.join(tmpDir.absolute.path, 'flutter'));
+      configuration = FlutterRepoSnippetConfiguration(
+          flutterRoot: flutterRoot, filesystem: memoryFileSystem);
+      configuration.skeletonsDirectory.createSync(recursive: true);
+      <String>['dartpad', 'sample', 'snippet'].forEach(writeSkeleton);
+      FlutterInformation.instance = FakeFlutterInformation(flutterRoot);
+      generator = SnippetGenerator(
+          configuration: configuration,
+          filesystem: memoryFileSystem,
+          flutterRoot: configuration.skeletonsDirectory.parent);
+    });
+
+    test('parses from comments', () async {
+      final File inputFile = _createSnippetSourceFile(tmpDir, memoryFileSystem);
+      final Iterable<SourceElement> elements = getFileElements(inputFile,
+          resourceProvider: FileSystemResourceProvider(memoryFileSystem));
+      expect(elements, isNotEmpty);
+      final SnippetDartdocParser sampleParser =
+          SnippetDartdocParser(memoryFileSystem);
+      sampleParser.parseFromComments(elements);
+      sampleParser.parseAndAddAssumptions(elements, inputFile);
+      expect(elements.length, equals(7));
+      int sampleCount = 0;
+      for (final SourceElement element in elements) {
+        expect(element.samples.length, greaterThanOrEqualTo(1));
+        sampleCount += element.samples.length;
+        final String code = generator.generateCode(element.samples.first);
+        expect(code, contains('// Description'));
+        expect(
+            code,
+            contains(RegExp(
+                '''^String elementName = '${element.elementName}';\$''',
+                multiLine: true)));
+        final String html = generator.generateHtml(element.samples.first);
+        expect(
+            html,
+            contains(RegExp(
+                '''^<pre>String elementName = &#39;${element.elementName}&#39;;.*\$''',
+                multiLine: true)));
+        expect(
+            html,
+            contains(
+                '<div class="snippet-description">{@end-inject-html}Description{@inject-html}</div>\n'));
+      }
+      expect(sampleCount, equals(8));
+    });
+    test('parses dartpad samples from linked file', () async {
+      final File inputFile = _createDartpadSourceFile(
+          tmpDir, memoryFileSystem, flutterRoot,
+          linked: true);
+      final Iterable<SourceElement> elements = getFileElements(inputFile,
+          resourceProvider: FileSystemResourceProvider(memoryFileSystem));
+      expect(elements, isNotEmpty);
+      final SnippetDartdocParser sampleParser =
+          SnippetDartdocParser(memoryFileSystem);
+      sampleParser.parseFromComments(elements);
+      expect(elements.length, equals(1));
+      int sampleCount = 0;
+      for (final SourceElement element in elements) {
+        expect(element.samples.length, greaterThanOrEqualTo(1));
+        sampleCount += element.samples.length;
+        final String code =
+            generator.generateCode(element.samples.first, formatOutput: false);
+        expect(code, contains('// Description'));
+        expect(
+            code,
+            contains(RegExp('^void ${element.name}Sample\\(\\) \\{.*\$',
+                multiLine: true)));
+        final String html = generator.generateHtml(element.samples.first);
+        expect(
+            html,
+            contains(RegExp(
+                '''^<iframe class="snippet-dartpad" src="https://dartpad.dev/.*sample_id=${element.name}.0.*></iframe>.*\$''',
+                multiLine: true)));
+      }
+      expect(sampleCount, equals(1));
+    });
+    test('parses assumptions', () async {
+      final File inputFile = _createSnippetSourceFile(tmpDir, memoryFileSystem);
+      final SnippetDartdocParser sampleParser =
+          SnippetDartdocParser(memoryFileSystem);
+      final List<SourceLine> assumptions =
+          sampleParser.parseAssumptions(inputFile);
+      expect(assumptions.length, equals(1));
+      expect(assumptions.first.text, equals('int integer = 3;'));
+    });
+  });
+}
+
+File _createSnippetSourceFile(Directory tmpDir, FileSystem filesystem) {
+  return filesystem.file(path.join(tmpDir.absolute.path, 'snippet_in.dart'))
+    ..createSync(recursive: true)
+    ..writeAsStringSync(r'''
+// Copyright
+
+// @dart = 2.12
+
+import 'foo.dart';
+
+// Examples can assume:
+// int integer = 3;
+
+/// Top level variable comment
+///
+/// {@tool snippet}
+/// Description
+/// ```dart
+/// String elementName = 'topLevelVariable';
+/// ```
+/// {@end-tool}
+int topLevelVariable = 4;
+
+/// Top level function comment
+///
+/// {@tool snippet}
+/// Description
+/// ```dart
+/// String elementName = 'topLevelFunction';
+/// ```
+/// {@end-tool}
+int topLevelFunction() {
+  return integer;
+}
+
+/// Class comment
+///
+/// {@tool snippet}
+/// Description
+/// ```dart
+/// String elementName = 'DocumentedClass';
+/// ```
+/// {@end-tool}
+///
+/// {@tool snippet}
+/// Description2
+/// ```dart
+/// String elementName = 'DocumentedClass';
+/// ```
+/// {@end-tool}
+class DocumentedClass {
+  /// Constructor comment
+  /// {@tool snippet}
+  /// Description
+  /// ```dart
+  /// String elementName = 'DocumentedClass';
+  /// ```
+  /// {@end-tool}
+  const DocumentedClass();
+
+  /// Named constructor comment
+  /// {@tool snippet}
+  /// Description
+  /// ```dart
+  /// String elementName = 'DocumentedClass.name';
+  /// ```
+  /// {@end-tool}
+  const DocumentedClass.name();
+
+  /// Member variable comment
+  /// {@tool snippet}
+  /// Description
+  /// ```dart
+  /// String elementName = 'DocumentedClass.intMember';
+  /// ```
+  /// {@end-tool}
+  int intMember;
+
+  /// Member comment
+  /// {@tool snippet}
+  /// Description
+  /// ```dart
+  /// String elementName = 'DocumentedClass.member';
+  /// ```
+  /// {@end-tool}
+  void member() {}
+}
+''');
+}
+
+File _createDartpadSourceFile(
+    Directory tmpDir, FileSystem filesystem, Directory flutterRoot,
+    {bool linked = false}) {
+  final File linkedFile =
+      filesystem.file(path.join(flutterRoot.absolute.path, 'linked_file.dart'))
+        ..createSync(recursive: true)
+        ..writeAsStringSync('''
+// Copyright
+
+import 'foo.dart';
+
+// Description
+
+void DocumentedClassSample() {
+  String elementName = 'DocumentedClass';
+}
+''');
+
+  final String source = linked
+      ? '''
+/// ** See code in ${path.relative(linkedFile.path, from: flutterRoot.absolute.path)} **'''
+      : '''
+/// ```dart
+/// void DocumentedClassSample() {
+///   String elementName = 'DocumentedClass';
+/// }
+/// ```''';
+
+  return filesystem.file(path.join(tmpDir.absolute.path, 'snippet_in.dart'))
+    ..createSync(recursive: true)
+    ..writeAsStringSync('''
+// Copyright
+
+// @dart = 2.12
+
+import 'foo.dart';
+
+/// Class comment
+///
+/// {@tool dartpad --template=template}
+/// Description
+$source
+/// {@end-tool}
+class DocumentedClass {}
+''');
+}
diff --git a/dev/snippets/test/snippets_test.dart b/dev/snippets/test/snippets_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..63ec9f42a1135dab3c160d3895753a14a33195e9
--- /dev/null
+++ b/dev/snippets/test/snippets_test.dart
@@ -0,0 +1,433 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'package:file/file.dart';
+import 'package:file/memory.dart';
+import 'package:path/path.dart' as path;
+import 'package:platform/platform.dart';
+import 'package:pub_semver/pub_semver.dart';
+import 'package:snippets/snippets.dart';
+import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
+
+import '../bin/snippets.dart' as snippets_main;
+import 'fake_process_manager.dart';
+
+class FakeFlutterInformation extends FlutterInformation {
+  FakeFlutterInformation(this.flutterRoot);
+
+  final Directory flutterRoot;
+
+  @override
+  Directory getFlutterRoot() {
+    return flutterRoot;
+  }
+
+  @override
+  Map<String, dynamic> getFlutterInformation() {
+    return <String, dynamic>{
+      'flutterRoot': flutterRoot,
+      'frameworkVersion': Version(2, 10, 0),
+      'dartSdkVersion': Version(2, 12, 1),
+    };
+  }
+}
+
+void main() {
+  group('Generator', () {
+    late MemoryFileSystem memoryFileSystem = MemoryFileSystem();
+    late FlutterRepoSnippetConfiguration configuration;
+    late SnippetGenerator generator;
+    late Directory tmpDir;
+
+    void writeSkeleton(String type) {
+      switch (type) {
+        case 'dartpad':
+          configuration.getHtmlSkeletonFile('dartpad').writeAsStringSync('''
+<div>HTML Bits (DartPad-style)</div>
+<iframe class="snippet-dartpad" src="https://dartpad.dev/embed-flutter.html?split=60&run=true&sample_id={{id}}&sample_channel={{channel}}"></iframe>
+<div>More HTML Bits</div>
+''');
+        case 'sample':
+        case 'snippet':
+          configuration.getHtmlSkeletonFile(type).writeAsStringSync('''
+<div>HTML Bits</div>
+{{description}}
+<pre>{{code}}</pre>
+<pre>{{app}}</pre>
+<div>More HTML Bits</div>
+''');
+      }
+    }
+
+    setUp(() {
+      // Create a new filesystem.
+      memoryFileSystem = MemoryFileSystem();
+      tmpDir = memoryFileSystem.systemTempDirectory
+          .createTempSync('flutter_snippets_test.');
+      configuration = FlutterRepoSnippetConfiguration(
+          flutterRoot: memoryFileSystem
+              .directory(path.join(tmpDir.absolute.path, 'flutter')),
+          filesystem: memoryFileSystem);
+      configuration.skeletonsDirectory.createSync(recursive: true);
+      <String>['dartpad', 'sample', 'snippet'].forEach(writeSkeleton);
+      FlutterInformation.instance =
+          FakeFlutterInformation(configuration.flutterRoot);
+      generator = SnippetGenerator(
+          configuration: configuration,
+          filesystem: memoryFileSystem,
+          flutterRoot: configuration.skeletonsDirectory.parent);
+    });
+
+    test('generates samples', () async {
+      final File inputFile = memoryFileSystem
+          .file(path.join(tmpDir.absolute.path, 'snippet_in.txt'))
+        ..createSync(recursive: true)
+        ..writeAsStringSync(r'''
+A description of the sample.
+
+On several lines.
+
+** See code in examples/api/widgets/foo/foo_example.0.dart **
+''');
+      final String examplePath = path.join(configuration.flutterRoot.path, 'examples/api/widgets/foo/foo_example.0.dart');
+      memoryFileSystem.file(examplePath)
+        ..create(recursive: true)
+        ..writeAsStringSync('''
+// Copyright
+
+// Flutter code sample for [MyElement].
+
+void main() {
+  runApp(MaterialApp(title: 'foo'));
+}\n'''
+        );
+      final File outputFile = memoryFileSystem
+          .file(path.join(tmpDir.absolute.path, 'snippet_out.txt'));
+      final SnippetDartdocParser sampleParser =
+          SnippetDartdocParser(memoryFileSystem);
+      const String sourcePath = 'packages/flutter/lib/src/widgets/foo.dart';
+      const int sourceLine = 222;
+      final SourceElement element = sampleParser.parseFromDartdocToolFile(
+        inputFile,
+        element: 'MyElement',
+        startLine: sourceLine,
+        sourceFile: memoryFileSystem.file(sourcePath),
+        type: 'sample',
+      );
+
+      expect(element.samples, isNotEmpty);
+      element.samples.first.metadata.addAll(<String, Object?>{
+        'channel': 'stable',
+      });
+      final String code = generator.generateCode(
+        element.samples.first,
+        output: outputFile,
+      );
+      expect(code, contains("runApp(MaterialApp(title: 'foo'));"));
+      final String html = generator.generateHtml(
+        element.samples.first,
+      );
+      expect(html, contains('<div>HTML Bits</div>'));
+      expect(html, contains('<div>More HTML Bits</div>'));
+      expect(html, contains(r'''runApp(MaterialApp(title: &#39;foo&#39;));'''));
+      expect(html, isNot(contains('sample_channel=stable')));
+      expect(
+          html,
+          contains('A description of the sample.\n'
+              '\n'
+              'On several lines.{@inject-html}</div>'));
+      expect(html, contains('void main() {'));
+
+      final String outputContents = outputFile.readAsStringSync();
+      expect(outputContents, contains('void main() {'));
+    });
+
+    test('generates snippets', () async {
+      final File inputFile = memoryFileSystem
+          .file(path.join(tmpDir.absolute.path, 'snippet_in.txt'))
+        ..createSync(recursive: true)
+        ..writeAsStringSync(r'''
+A description of the snippet.
+
+On several lines.
+
+```code
+void main() {
+  print('The actual $name.');
+}
+```
+''');
+
+      final SnippetDartdocParser sampleParser =
+          SnippetDartdocParser(memoryFileSystem);
+      const String sourcePath = 'packages/flutter/lib/src/widgets/foo.dart';
+      const int sourceLine = 222;
+      final SourceElement element = sampleParser.parseFromDartdocToolFile(
+        inputFile,
+        element: 'MyElement',
+        startLine: sourceLine,
+        sourceFile: memoryFileSystem.file(sourcePath),
+        type: 'snippet',
+      );
+      expect(element.samples, isNotEmpty);
+      element.samples.first.metadata.addAll(<String, Object>{
+        'channel': 'stable',
+      });
+      final String code = generator.generateCode(element.samples.first);
+      expect(code, contains('// A description of the snippet.'));
+      final String html = generator.generateHtml(element.samples.first);
+      expect(html, contains('<div>HTML Bits</div>'));
+      expect(html, contains('<div>More HTML Bits</div>'));
+      expect(html, contains(r'  print(&#39;The actual $name.&#39;);'));
+      expect(
+          html,
+          contains(
+              '<div class="snippet-description">{@end-inject-html}A description of the snippet.\n\n'
+              'On several lines.{@inject-html}</div>\n'));
+      expect(html, contains('main() {'));
+    });
+
+    test('generates dartpad samples', () async {
+      final File inputFile = memoryFileSystem
+          .file(path.join(tmpDir.absolute.path, 'snippet_in.txt'))
+        ..createSync(recursive: true)
+        ..writeAsStringSync(r'''
+A description of the snippet.
+
+On several lines.
+
+** See code in examples/api/widgets/foo/foo_example.0.dart **
+''');
+      final String examplePath = path.join(configuration.flutterRoot.path, 'examples/api/widgets/foo/foo_example.0.dart');
+      memoryFileSystem.file(examplePath)
+        ..create(recursive: true)
+        ..writeAsStringSync('''
+// Copyright
+
+// Flutter code sample for [MyElement].
+
+void main() {
+  runApp(MaterialApp(title: 'foo'));
+}\n'''
+        );
+
+      final SnippetDartdocParser sampleParser =
+          SnippetDartdocParser(memoryFileSystem);
+      const String sourcePath = 'packages/flutter/lib/src/widgets/foo.dart';
+      const int sourceLine = 222;
+      final SourceElement element = sampleParser.parseFromDartdocToolFile(
+        inputFile,
+        element: 'MyElement',
+        startLine: sourceLine,
+        sourceFile: memoryFileSystem.file(sourcePath),
+        type: 'dartpad',
+      );
+      expect(element.samples, isNotEmpty);
+      element.samples.first.metadata.addAll(<String, Object>{
+        'channel': 'stable',
+      });
+      final String code = generator.generateCode(element.samples.first);
+      expect(code, contains("runApp(MaterialApp(title: 'foo'));"));
+      final String html = generator.generateHtml(element.samples.first);
+      expect(html, contains('<div>HTML Bits (DartPad-style)</div>'));
+      expect(html, contains('<div>More HTML Bits</div>'));
+      expect(
+          html,
+          contains(
+              '<iframe class="snippet-dartpad" src="https://dartpad.dev/embed-flutter.html?split=60&run=true&sample_id=MyElement.0&sample_channel=stable"></iframe>\n'));
+    });
+
+    test('generates sample metadata', () async {
+      final File inputFile = memoryFileSystem
+          .file(path.join(tmpDir.absolute.path, 'snippet_in.txt'))
+        ..createSync(recursive: true)
+        ..writeAsStringSync(r'''
+A description of the snippet.
+
+On several lines.
+
+```dart
+void main() {
+  print('The actual $name.');
+}
+```
+''');
+
+      final File outputFile = memoryFileSystem
+          .file(path.join(tmpDir.absolute.path, 'snippet_out.dart'));
+      final File expectedMetadataFile = memoryFileSystem
+          .file(path.join(tmpDir.absolute.path, 'snippet_out.json'));
+
+      final SnippetDartdocParser sampleParser =
+          SnippetDartdocParser(memoryFileSystem);
+      const String sourcePath = 'packages/flutter/lib/src/widgets/foo.dart';
+      const int sourceLine = 222;
+      final SourceElement element = sampleParser.parseFromDartdocToolFile(
+        inputFile,
+        element: 'MyElement',
+        startLine: sourceLine,
+        sourceFile: memoryFileSystem.file(sourcePath),
+        type: 'sample',
+      );
+      expect(element.samples, isNotEmpty);
+      element.samples.first.metadata
+          .addAll(<String, Object>{'channel': 'stable'});
+      generator.generateCode(element.samples.first, output: outputFile);
+      expect(expectedMetadataFile.existsSync(), isTrue);
+      final Map<String, dynamic> json =
+          jsonDecode(expectedMetadataFile.readAsStringSync())
+              as Map<String, dynamic>;
+      expect(json['id'], equals('MyElement.0'));
+      expect(json['channel'], equals('stable'));
+      expect(json['file'], equals('snippet_out.dart'));
+      expect(json['description'],
+          equals('A description of the snippet.\n\nOn several lines.'));
+      expect(json['sourcePath'],
+          equals('packages/flutter/lib/src/widgets/foo.dart'));
+    });
+  });
+
+  group('snippets command line argument test', () {
+    late MemoryFileSystem memoryFileSystem = MemoryFileSystem();
+    late Directory tmpDir;
+    late Directory flutterRoot;
+    late FakeProcessManager fakeProcessManager;
+
+    setUp(() {
+      fakeProcessManager = FakeProcessManager();
+      memoryFileSystem = MemoryFileSystem();
+      tmpDir = memoryFileSystem.systemTempDirectory
+          .createTempSync('flutter_snippets_test.');
+      flutterRoot = memoryFileSystem
+          .directory(path.join(tmpDir.absolute.path, 'flutter'))
+        ..createSync(recursive: true);
+    });
+
+    test('command line arguments are parsed and passed to generator', () {
+      final FakePlatform platform = FakePlatform(environment: <String, String>{
+        'PACKAGE_NAME': 'dart:ui',
+        'LIBRARY_NAME': 'library',
+        'ELEMENT_NAME': 'element',
+        'FLUTTER_ROOT': flutterRoot.absolute.path,
+        // The details here don't really matter other than the flutter root.
+        'FLUTTER_VERSION': '''
+      {
+        "frameworkVersion": "2.5.0-6.0.pre.55",
+        "channel": "use_snippets_pkg",
+        "repositoryUrl": "git@github.com:flutter/flutter.git",
+        "frameworkRevision": "fec4641e1c88923ecd6c969e2ff8a0dd12dc0875",
+        "frameworkCommitDate": "2021-08-11 15:19:48 -0700",
+        "engineRevision": "d8bbebed60a77b3d4fe9c840dc94dfbce159d951",
+        "dartSdkVersion": "2.14.0 (build 2.14.0-393.0.dev)",
+        "flutterRoot": "${flutterRoot.absolute.path}"
+      }''',
+      });
+      final FlutterInformation flutterInformation = FlutterInformation(
+        filesystem: memoryFileSystem,
+        processManager: fakeProcessManager,
+        platform: platform,
+      );
+      FlutterInformation.instance = flutterInformation;
+      MockSnippetGenerator mockSnippetGenerator = MockSnippetGenerator();
+      snippets_main.snippetGenerator = mockSnippetGenerator;
+      String errorMessage = '';
+      errorExit = (String message) {
+        errorMessage = message;
+      };
+
+      snippets_main.platform = platform;
+      snippets_main.filesystem = memoryFileSystem;
+      snippets_main.processManager = fakeProcessManager;
+      final File input = memoryFileSystem
+          .file(tmpDir.childFile('input.snippet'))
+        ..writeAsString('/// Test file');
+      snippets_main.main(
+          <String>['--input=${input.absolute.path}']);
+
+      final Map<String, dynamic> metadata =
+          mockSnippetGenerator.sample.metadata;
+      // Ignore the channel, because channel is really just the branch, and will be
+      // different on development workstations.
+      metadata.remove('channel');
+      expect(
+          metadata,
+          equals(<String, dynamic>{
+            'id': 'dart_ui.library.element',
+            'element': 'element',
+            'sourcePath': 'unknown.dart',
+            'sourceLine': 1,
+            'serial': '',
+            'package': 'dart:ui',
+            'library': 'library',
+          }));
+
+      snippets_main.main(<String>[]);
+      expect(
+          errorMessage,
+          equals(
+              'The --input option must be specified, either on the command line, or in the INPUT environment variable.'));
+      errorMessage = '';
+
+      snippets_main
+          .main(<String>['--input=${input.absolute.path}', '--type=snippet']);
+      expect(errorMessage, equals(''));
+      errorMessage = '';
+
+      mockSnippetGenerator = MockSnippetGenerator();
+      snippets_main.snippetGenerator = mockSnippetGenerator;
+      snippets_main.main(<String>[
+        '--input=${input.absolute.path}',
+        '--type=snippet',
+        '--no-format-output'
+      ]);
+      expect(mockSnippetGenerator.formatOutput, equals(false));
+      errorMessage = '';
+
+      input.deleteSync();
+      snippets_main.main(
+          <String>['--input=${input.absolute.path}']);
+      expect(errorMessage,
+          equals('The input file ${input.absolute.path} does not exist.'));
+      errorMessage = '';
+    });
+  });
+}
+
+class MockSnippetGenerator extends SnippetGenerator {
+  late CodeSample sample;
+  File? output;
+  String? copyright;
+  String? description;
+  late bool formatOutput;
+  late bool addSectionMarkers;
+  late bool includeAssumptions;
+
+  @override
+  String generateCode(
+    CodeSample sample, {
+    File? output,
+    String? copyright,
+    String? description,
+    bool formatOutput = true,
+    bool addSectionMarkers = false,
+    bool includeAssumptions = false,
+  }) {
+    this.sample = sample;
+    this.output = output;
+    this.copyright = copyright;
+    this.description = description;
+    this.formatOutput = formatOutput;
+    this.addSectionMarkers = addSectionMarkers;
+    this.includeAssumptions = includeAssumptions;
+
+    return '';
+  }
+
+  @override
+  String generateHtml(CodeSample sample) {
+    return '';
+  }
+}
diff --git a/dev/snippets/test/util_test.dart b/dev/snippets/test/util_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..cd27d47123a138b28c071c4d5ac0154733dcb3e6
--- /dev/null
+++ b/dev/snippets/test/util_test.dart
@@ -0,0 +1,87 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:file/memory.dart';
+import 'package:platform/platform.dart';
+import 'package:pub_semver/pub_semver.dart';
+import 'package:snippets/snippets.dart';
+import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
+
+import 'fake_process_manager.dart';
+
+const String testVersionInfo = r'''
+{
+  "frameworkVersion": "2.5.0-2.0.pre.63",
+  "channel": "master",
+  "repositoryUrl": "git@github.com:flutter/flutter.git",
+  "frameworkRevision": "9b2f6f7f9ab96bb3302f81b814a094f33023e79a",
+  "frameworkCommitDate": "2021-07-28 13:03:40 -0700",
+  "engineRevision": "0ed62a16f36348e97b2baadd8ccfec3825f80c5d",
+  "dartSdkVersion": "2.14.0 (build 2.14.0-360.0.dev)",
+  "flutterRoot": "/home/user/flutter"
+}
+''';
+
+void main() {
+  group('FlutterInformation', () {
+    late FakeProcessManager fakeProcessManager;
+    late FakePlatform fakePlatform;
+    late MemoryFileSystem memoryFileSystem;
+    late FlutterInformation flutterInformation;
+
+    setUp(() {
+      fakeProcessManager = FakeProcessManager();
+      memoryFileSystem = MemoryFileSystem();
+      fakePlatform = FakePlatform(environment: <String, String>{});
+      flutterInformation = FlutterInformation(
+        filesystem: memoryFileSystem,
+        processManager: fakeProcessManager,
+        platform: fakePlatform,
+      );
+    });
+
+    test('calls out to flutter if FLUTTER_VERSION is not set', () async {
+      fakeProcessManager.stdout = testVersionInfo;
+      final Map<String, dynamic> info =
+          flutterInformation.getFlutterInformation();
+      expect(fakeProcessManager.runs, equals(1));
+      expect(
+          info['frameworkVersion'], equals(Version.parse('2.5.0-2.0.pre.63')));
+    });
+    test("doesn't call out to flutter if FLUTTER_VERSION is set", () async {
+      fakePlatform.environment['FLUTTER_VERSION'] = testVersionInfo;
+      final Map<String, dynamic> info =
+          flutterInformation.getFlutterInformation();
+      expect(fakeProcessManager.runs, equals(0));
+      expect(
+          info['frameworkVersion'], equals(Version.parse('2.5.0-2.0.pre.63')));
+    });
+    test('getFlutterRoot calls out to flutter if FLUTTER_ROOT is not set',
+        () async {
+      fakeProcessManager.stdout = testVersionInfo;
+      final Directory root = flutterInformation.getFlutterRoot();
+      expect(fakeProcessManager.runs, equals(1));
+      expect(root.path, equals('/home/user/flutter'));
+    });
+    test("getFlutterRoot doesn't call out to flutter if FLUTTER_ROOT is set",
+        () async {
+      fakePlatform.environment['FLUTTER_ROOT'] = '/home/user/flutter';
+      final Directory root = flutterInformation.getFlutterRoot();
+      expect(fakeProcessManager.runs, equals(0));
+      expect(root.path, equals('/home/user/flutter'));
+    });
+    test('parses version properly', () async {
+      fakePlatform.environment['FLUTTER_VERSION'] = testVersionInfo;
+      final Map<String, dynamic> info =
+          flutterInformation.getFlutterInformation();
+      expect(info['frameworkVersion'], isNotNull);
+      expect(
+          info['frameworkVersion'], equals(Version.parse('2.5.0-2.0.pre.63')));
+      expect(info['dartSdkVersion'], isNotNull);
+      expect(info['dartSdkVersion'], equals(Version.parse('2.14.0-360.0.dev')));
+    });
+  });
+}
diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart
index 91a1b8f8439dc51ce3e4633750f756e32c10d726..9c7868712481764554001d3ab702bc81da45ee17 100644
--- a/dev/tools/create_api_docs.dart
+++ b/dev/tools/create_api_docs.dart
@@ -521,8 +521,8 @@ class DartdocGenerator {
 
     final Version version = FlutterInformation.instance.getFlutterVersion();
 
-    // Verify which version of snippets and dartdoc we're using.
-    final ProcessResult snippetsResult = processManager.runSync(
+    // Verify which version of the global activated packages we're using.
+    final ProcessResult versionResults = processManager.runSync(
       <String>[
         FlutterInformation.instance.getFlutterBinaryPath().path,
         'pub',
@@ -535,8 +535,8 @@ class DartdocGenerator {
     );
     print('');
     final Iterable<RegExpMatch> versionMatches =
-        RegExp(r'^(?<name>snippets|dartdoc) (?<version>[^\s]+)', multiLine: true)
-            .allMatches(snippetsResult.stdout as String);
+        RegExp(r'^(?<name>dartdoc) (?<version>[^\s]+)', multiLine: true)
+            .allMatches(versionResults.stdout as String);
     for (final RegExpMatch match in versionMatches) {
       print('${match.namedGroup('name')} version: ${match.namedGroup('version')}');
     }