encode method

Program encode({
  1. String? entryFile,
  2. String entryFunction = 'main',
})

Encode the whole package and return a ball Program.

entryFile is the relative path from packageDir to the Dart file that provides the package's void main() entry point (e.g. 'bin/main.dart'). When omitted, the encoder auto-detects the entry file.

entryFunction is the name of the entry function (default 'main').

scanDirs overrides the set of top-level directories that are scanned for .dart files. Defaults to ['lib', 'bin'] (plus ['test'] when includeTests is true).

Implementation

Program encode({String? entryFile, String entryFunction = 'main'}) {
  final String resolvedEntry =
      entryFile ?? _detectEntryFile() ?? 'bin/main.dart';
  final String entryModuleName =
      _fileToModule[resolvedEntry] ?? filePathToModuleName(resolvedEntry);

  final encoder = DartEncoder();
  // Accumulate all base functions across files; build std once at the end.

  final userModules = <Module>[];
  // External import stubs — deduplicated across all files.
  final externalStubs = <String, Module>{};
  // Internal module names already known (avoid duplicating in-package stubs).
  final inPackageModules = <String>{'std', ..._fileToModule.values};

  for (final MapEntry(key: relPath, value: moduleName)
      in _fileToModule.entries) {
    final file = File(
      '${packageDir.path}${Platform.pathSeparator}'
      '${relPath.replaceAll('/', Platform.pathSeparator)}',
    );
    if (!file.existsSync()) continue;

    // Prefer the type-RESOLVED unit when [prepareStaticTypes] supplied one
    // (issue #488): on it `expression.staticType` is non-null, which is the
    // only way the encoder can tell `Set.add` from `List.add`. Without it,
    // fall back to the syntax-only `parseString` unit — the historical
    // behavior, and still the behavior for every caller that never awaits
    // [prepareStaticTypes].
    final ast.CompilationUnit unit =
        _resolvedUnits[relPath] ??
        parseString(
          content: file.readAsStringSync(),
          throwIfDiagnostics: false,
          featureSet: FeatureSet.latestLanguageVersion(),
        ).unit;
    final uriOverrides = _computeUriOverridesFromUnit(relPath, unit);

    final (:module, :importStubs) = encoder.encodeModuleFromUnit(
      unit,
      moduleName: moduleName,
      uriToModuleOverrides: uriOverrides,
    );
    userModules.add(module);

    for (final stub in importStubs) {
      if (!inPackageModules.contains(stub.name) &&
          !externalStubs.containsKey(stub.name)) {
        externalStubs[stub.name] = stub;
      }
    }
  }

  final (:stdModule, :collectionsModule, :protoModule) = encoder
      .buildStdModules();

  // Sort user modules so the entry module is last (conventional positioning).
  userModules.sort((a, b) {
    if (a.name == entryModuleName) return 1;
    if (b.name == entryModuleName) return -1;
    return a.name.compareTo(b.name);
  });

  // Collect package manifest files (pubspec.yaml, pubspec.lock, etc.) and
  // any other non-Dart resources into a special __assets__ module.
  final resourceModule = _collectResources();

  return Program()
    ..name = packageName
    ..version = packageVersion
    ..entryModule = entryModuleName
    ..entryFunction = entryFunction
    ..modules.addAll([
      stdModule,
      // coverage:ignore-start
      // Empirically confirmed dart:coverage limitation: a null-aware
      // spread element (`?expr`) inside a list literal never gets a `DA:`
      // hit recorded even when the surrounding call executes and `expr`
      // evaluates to a non-null value — verified by running package-level
      // tests that reliably hit this line both with a null and a non-null
      // `collectionsModule`, and it stayed at 0 hits either way. Real
      // coverage (behavior) is proven by the module-presence assertions
      // in package_encoder_test.dart.
      ?collectionsModule,
      ?protoModule,
      // coverage:ignore-end
      ...externalStubs.values,
      ...userModules,
      ?resourceModule,
    ]);
}