toZip method

List<int> toZip()

Serializes this bundle as a ZIP archive.

The archive follows the .ast bundle specification:

  • manifest.json — plain JSON with metadata and file-to-URI mapping
  • N.ast.json — gzip-compressed JSON for each module
  • N.src.dart — plain-text source code (only when sources is non-null)

Module entries are pre-compressed with gzip and stored without additional ZIP-level compression, allowing individual modules to be extracted and used standalone.

Implementation

List<int> toZip() {
  final archive = Archive();

  // Assign sequential file names to each module
  final fileToUri = <String, String>{};
  final uriToFileName = <String, String>{};
  var index = 0;
  for (final uri in modules.keys) {
    final fileName = '$index${AstBundleFormat.astJsonSuffix}';
    fileToUri[fileName] = uri;
    uriToFileName[uri] = fileName;
    index++;
  }

  // Build optional source file mapping
  Map<String, String>? sourceFileToUri;
  if (sources != null && sources!.isNotEmpty) {
    sourceFileToUri = <String, String>{};
    var srcIndex = 0;
    for (final uri in sources!.keys) {
      final srcFileName = '$srcIndex${AstBundleFormat.sourceDartSuffix}';
      sourceFileToUri[srcFileName] = uri;
      srcIndex++;
    }
  }

  // Write manifest (uncompressed, human-readable)
  final manifest = AstBundleManifest(
    version: AstBundleFormat.version,
    entryPoint: entryPointUri,
    files: fileToUri,
    sourceFiles: sourceFileToUri,
  );
  final manifestJson = const JsonEncoder.withIndent(
    '  ',
  ).convert(manifest.toJson());
  archive.addFile(
    ArchiveFile.string(AstBundleFormat.manifestFileName, manifestJson),
  );

  // Write each module as gzip-compressed JSON
  for (final entry in modules.entries) {
    final fileName = uriToFileName[entry.key]!;
    final moduleJson = jsonEncode(entry.value.toJson());
    final compressed = gzip.encode(utf8.encode(moduleJson));
    // Use noCompress: content is already gzip-compressed
    archive.addFile(
      ArchiveFile.noCompress(fileName, compressed.length, compressed),
    );
  }

  // Write source files (plain text, uncompressed for readability)
  if (sources != null && sourceFileToUri != null) {
    final uriToSrcFileName = <String, String>{};
    for (final entry in sourceFileToUri.entries) {
      uriToSrcFileName[entry.value] = entry.key;
    }
    for (final entry in sources!.entries) {
      final srcFileName = uriToSrcFileName[entry.key];
      if (srcFileName != null) {
        archive.addFile(ArchiveFile.string(srcFileName, entry.value));
      }
    }
  }

  return ZipEncoder().encode(archive);
}