[{"data":1,"prerenderedAt":3325},["ShallowReactive",2],{"page-\u002Fdart\u002F18-tooling-and-ecosystem":3},{"id":4,"title":5,"body":6,"description":3318,"extension":3319,"meta":3320,"navigation":63,"path":3321,"seo":3322,"stem":3323,"__hash__":3324},"content\u002Fdart\u002F18-tooling-and-ecosystem.md","Dart — Tooling, Code Generation & CI\u002FCD Pipeline",{"type":7,"value":8,"toc":3299},"minimark",[9,13,22,433,440,559,567,1174,1181,1810,1814,3295],[10,11,5],"h1",{"id":12},"dart-tooling-code-generation-cicd-pipeline",[14,15,17,21],"h2",{"id":16},"analysis_optionsyaml-strict-analysis-configuration",[18,19,20],"code",{},"analysis_options.yaml"," — Strict Analysis Configuration",[23,24,26],"code-wrapper",{"language":25},"yaml",[27,28,32],"pre",{"className":29,"code":30,"language":25,"meta":31,"style":31},"language-yaml shiki shiki-themes github-light github-dark","# Include a rule set: core (minimal), recommended (balanced), strict (aggressive).\ninclude: package:lints\u002Fstrict.yaml\n\nanalyzer:\n  # Exclude generated files from analysis (they may not pass strict rules).\n  exclude:\n    - 'build\u002F**'\n    - '**\u002F*.g.dart'        # json_serializable, etc.\n    - '**\u002F*.freezed.dart'  # freezed\n    - '**\u002F*.mocks.dart'    # mockito\n\n  # Language modes — enforce stricter type checking at analysis time.\n  language:\n    strict-casts: true      # no implicit casts (num → int requires explicit `as`)\n    strict-inference: true  # flags `var x;` (no initializer → infers dynamic)\n    strict-raw-types: true  # flags `List` without type args (requires List\u003CT>)\n\n  # Strong mode (legacy, mostly subsumed by `language:` above):\n  strong-mode:\n    implicit-casts: false    # no automatic downcasts (num → int)\n    implicit-dynamic: false # no implicit `dynamic` (var x; → error)\n\nlinter:\n  rules:\n    # ── Style ──\n    - prefer_const_constructors       # use const where possible\n    - prefer_const_constructors_in_immutables\n    - prefer_const_declarations\n    - prefer_final_locals             # use final for non-reassigned locals\n    - prefer_final_in_for_each         # use final in for-in loop variables\n    - require_trailing_commas         # trailing commas in multi-line collections\n    - avoid_print                     # no print() in production code\n\n    # ── Safety ──\n    - unawaited_futures               # flags `future();` without await\u002Funawaited()\n    - cancel_subscriptions             # flags StreamSubscription not cancelled\n    - close_sinks                      # flags StreamSink not closed\n    - avoid_dynamic_calls              # flags x.foo() on dynamic (NoSuchMethodError risk)\n\n    # ── Performance ──\n    - avoid_returning_null_for_future  # return Future.value(), not null\n    - prefer_is_empty                  # use isEmpty, not length == 0\n    - prefer_iterable_whereType        # use whereType\u003CT>(), not where((e) => e is T)\n","",[18,33,34,43,58,65,74,80,88,97,108,119,130,135,141,149,164,177,190,195,201,209,223,236,241,249,257,263,274,282,290,301,312,323,334,339,345,356,367,378,389,394,400,411,422],{"__ignoreMap":31},[35,36,39],"span",{"class":37,"line":38},"line",1,[35,40,42],{"class":41},"sdCPZ","# Include a rule set: core (minimal), recommended (balanced), strict (aggressive).\n",[35,44,46,50,54],{"class":37,"line":45},2,[35,47,49],{"class":48},"sk71V","include",[35,51,53],{"class":52},"ssxIu",": ",[35,55,57],{"class":56},"sJ6F3","package:lints\u002Fstrict.yaml\n",[35,59,61],{"class":37,"line":60},3,[35,62,64],{"emptyLinePlaceholder":63},true,"\n",[35,66,68,71],{"class":37,"line":67},4,[35,69,70],{"class":48},"analyzer",[35,72,73],{"class":52},":\n",[35,75,77],{"class":37,"line":76},5,[35,78,79],{"class":41},"  # Exclude generated files from analysis (they may not pass strict rules).\n",[35,81,83,86],{"class":37,"line":82},6,[35,84,85],{"class":48},"  exclude",[35,87,73],{"class":52},[35,89,91,94],{"class":37,"line":90},7,[35,92,93],{"class":52},"    - ",[35,95,96],{"class":56},"'build\u002F**'\n",[35,98,100,102,105],{"class":37,"line":99},8,[35,101,93],{"class":52},[35,103,104],{"class":56},"'**\u002F*.g.dart'",[35,106,107],{"class":41},"        # json_serializable, etc.\n",[35,109,111,113,116],{"class":37,"line":110},9,[35,112,93],{"class":52},[35,114,115],{"class":56},"'**\u002F*.freezed.dart'",[35,117,118],{"class":41},"  # freezed\n",[35,120,122,124,127],{"class":37,"line":121},10,[35,123,93],{"class":52},[35,125,126],{"class":56},"'**\u002F*.mocks.dart'",[35,128,129],{"class":41},"    # mockito\n",[35,131,133],{"class":37,"line":132},11,[35,134,64],{"emptyLinePlaceholder":63},[35,136,138],{"class":37,"line":137},12,[35,139,140],{"class":41},"  # Language modes — enforce stricter type checking at analysis time.\n",[35,142,144,147],{"class":37,"line":143},13,[35,145,146],{"class":48},"  language",[35,148,73],{"class":52},[35,150,152,155,157,161],{"class":37,"line":151},14,[35,153,154],{"class":48},"    strict-casts",[35,156,53],{"class":52},[35,158,160],{"class":159},"snvgF","true",[35,162,163],{"class":41},"      # no implicit casts (num → int requires explicit `as`)\n",[35,165,167,170,172,174],{"class":37,"line":166},15,[35,168,169],{"class":48},"    strict-inference",[35,171,53],{"class":52},[35,173,160],{"class":159},[35,175,176],{"class":41},"  # flags `var x;` (no initializer → infers dynamic)\n",[35,178,180,183,185,187],{"class":37,"line":179},16,[35,181,182],{"class":48},"    strict-raw-types",[35,184,53],{"class":52},[35,186,160],{"class":159},[35,188,189],{"class":41},"  # flags `List` without type args (requires List\u003CT>)\n",[35,191,193],{"class":37,"line":192},17,[35,194,64],{"emptyLinePlaceholder":63},[35,196,198],{"class":37,"line":197},18,[35,199,200],{"class":41},"  # Strong mode (legacy, mostly subsumed by `language:` above):\n",[35,202,204,207],{"class":37,"line":203},19,[35,205,206],{"class":48},"  strong-mode",[35,208,73],{"class":52},[35,210,212,215,217,220],{"class":37,"line":211},20,[35,213,214],{"class":48},"    implicit-casts",[35,216,53],{"class":52},[35,218,219],{"class":159},"false",[35,221,222],{"class":41},"    # no automatic downcasts (num → int)\n",[35,224,226,229,231,233],{"class":37,"line":225},21,[35,227,228],{"class":48},"    implicit-dynamic",[35,230,53],{"class":52},[35,232,219],{"class":159},[35,234,235],{"class":41}," # no implicit `dynamic` (var x; → error)\n",[35,237,239],{"class":37,"line":238},22,[35,240,64],{"emptyLinePlaceholder":63},[35,242,244,247],{"class":37,"line":243},23,[35,245,246],{"class":48},"linter",[35,248,73],{"class":52},[35,250,252,255],{"class":37,"line":251},24,[35,253,254],{"class":48},"  rules",[35,256,73],{"class":52},[35,258,260],{"class":37,"line":259},25,[35,261,262],{"class":41},"    # ── Style ──\n",[35,264,266,268,271],{"class":37,"line":265},26,[35,267,93],{"class":52},[35,269,270],{"class":56},"prefer_const_constructors",[35,272,273],{"class":41},"       # use const where possible\n",[35,275,277,279],{"class":37,"line":276},27,[35,278,93],{"class":52},[35,280,281],{"class":56},"prefer_const_constructors_in_immutables\n",[35,283,285,287],{"class":37,"line":284},28,[35,286,93],{"class":52},[35,288,289],{"class":56},"prefer_const_declarations\n",[35,291,293,295,298],{"class":37,"line":292},29,[35,294,93],{"class":52},[35,296,297],{"class":56},"prefer_final_locals",[35,299,300],{"class":41},"             # use final for non-reassigned locals\n",[35,302,304,306,309],{"class":37,"line":303},30,[35,305,93],{"class":52},[35,307,308],{"class":56},"prefer_final_in_for_each",[35,310,311],{"class":41},"         # use final in for-in loop variables\n",[35,313,315,317,320],{"class":37,"line":314},31,[35,316,93],{"class":52},[35,318,319],{"class":56},"require_trailing_commas",[35,321,322],{"class":41},"         # trailing commas in multi-line collections\n",[35,324,326,328,331],{"class":37,"line":325},32,[35,327,93],{"class":52},[35,329,330],{"class":56},"avoid_print",[35,332,333],{"class":41},"                     # no print() in production code\n",[35,335,337],{"class":37,"line":336},33,[35,338,64],{"emptyLinePlaceholder":63},[35,340,342],{"class":37,"line":341},34,[35,343,344],{"class":41},"    # ── Safety ──\n",[35,346,348,350,353],{"class":37,"line":347},35,[35,349,93],{"class":52},[35,351,352],{"class":56},"unawaited_futures",[35,354,355],{"class":41},"               # flags `future();` without await\u002Funawaited()\n",[35,357,359,361,364],{"class":37,"line":358},36,[35,360,93],{"class":52},[35,362,363],{"class":56},"cancel_subscriptions",[35,365,366],{"class":41},"             # flags StreamSubscription not cancelled\n",[35,368,370,372,375],{"class":37,"line":369},37,[35,371,93],{"class":52},[35,373,374],{"class":56},"close_sinks",[35,376,377],{"class":41},"                      # flags StreamSink not closed\n",[35,379,381,383,386],{"class":37,"line":380},38,[35,382,93],{"class":52},[35,384,385],{"class":56},"avoid_dynamic_calls",[35,387,388],{"class":41},"              # flags x.foo() on dynamic (NoSuchMethodError risk)\n",[35,390,392],{"class":37,"line":391},39,[35,393,64],{"emptyLinePlaceholder":63},[35,395,397],{"class":37,"line":396},40,[35,398,399],{"class":41},"    # ── Performance ──\n",[35,401,403,405,408],{"class":37,"line":402},41,[35,404,93],{"class":52},[35,406,407],{"class":56},"avoid_returning_null_for_future",[35,409,410],{"class":41},"  # return Future.value(), not null\n",[35,412,414,416,419],{"class":37,"line":413},42,[35,415,93],{"class":52},[35,417,418],{"class":56},"prefer_is_empty",[35,420,421],{"class":41},"                  # use isEmpty, not length == 0\n",[35,423,425,427,430],{"class":37,"line":424},43,[35,426,93],{"class":52},[35,428,429],{"class":56},"prefer_iterable_whereType",[35,431,432],{"class":41},"        # use whereType\u003CT>(), not where((e) => e is T)\n",[14,434,436,437],{"id":435},"code-generation-build_runner","Code Generation — ",[18,438,439],{},"build_runner",[23,441,443],{"language":442},"bash",[27,444,447],{"className":445,"code":446,"language":442,"meta":31,"style":31},"language-bash shiki shiki-themes github-light github-dark","# ── build_runner: runs code generators from annotations ──\n# Generators: json_serializable, freezed, mockito, drift, riverpod_generator.\n\n# Install as a dev dependency:\n# dart pub add dev:build_runner\n\n# One-shot generation (CI, before commit):\ndart run build_runner build\n\n# Watch mode (dev — regenerates on file save):\ndart run build_runner watch\n\n# Force (delete conflicting outputs — use when generated files are stale):\ndart run build_runner build --delete-conflicting-outputs\n\n# ── Performance ──\n# build_runner can be slow on large projects (minutes). Use `watch` for\n# incremental dev. Or use no-codegen alternatives (mocktail instead of mockito).\n",[18,448,449,454,459,463,468,473,477,482,497,501,506,517,521,526,540,544,549,554],{"__ignoreMap":31},[35,450,451],{"class":37,"line":38},[35,452,453],{"class":41},"# ── build_runner: runs code generators from annotations ──\n",[35,455,456],{"class":37,"line":45},[35,457,458],{"class":41},"# Generators: json_serializable, freezed, mockito, drift, riverpod_generator.\n",[35,460,461],{"class":37,"line":60},[35,462,64],{"emptyLinePlaceholder":63},[35,464,465],{"class":37,"line":67},[35,466,467],{"class":41},"# Install as a dev dependency:\n",[35,469,470],{"class":37,"line":76},[35,471,472],{"class":41},"# dart pub add dev:build_runner\n",[35,474,475],{"class":37,"line":82},[35,476,64],{"emptyLinePlaceholder":63},[35,478,479],{"class":37,"line":90},[35,480,481],{"class":41},"# One-shot generation (CI, before commit):\n",[35,483,484,488,491,494],{"class":37,"line":99},[35,485,487],{"class":486},"sIsaT","dart",[35,489,490],{"class":56}," run",[35,492,493],{"class":56}," build_runner",[35,495,496],{"class":56}," build\n",[35,498,499],{"class":37,"line":110},[35,500,64],{"emptyLinePlaceholder":63},[35,502,503],{"class":37,"line":121},[35,504,505],{"class":41},"# Watch mode (dev — regenerates on file save):\n",[35,507,508,510,512,514],{"class":37,"line":132},[35,509,487],{"class":486},[35,511,490],{"class":56},[35,513,493],{"class":56},[35,515,516],{"class":56}," watch\n",[35,518,519],{"class":37,"line":137},[35,520,64],{"emptyLinePlaceholder":63},[35,522,523],{"class":37,"line":143},[35,524,525],{"class":41},"# Force (delete conflicting outputs — use when generated files are stale):\n",[35,527,528,530,532,534,537],{"class":37,"line":151},[35,529,487],{"class":486},[35,531,490],{"class":56},[35,533,493],{"class":56},[35,535,536],{"class":56}," build",[35,538,539],{"class":159}," --delete-conflicting-outputs\n",[35,541,542],{"class":37,"line":166},[35,543,64],{"emptyLinePlaceholder":63},[35,545,546],{"class":37,"line":179},[35,547,548],{"class":41},"# ── Performance ──\n",[35,550,551],{"class":37,"line":192},[35,552,553],{"class":41},"# build_runner can be slow on large projects (minutes). Use `watch` for\n",[35,555,556],{"class":37,"line":197},[35,557,558],{"class":41},"# incremental dev. Or use no-codegen alternatives (mocktail instead of mockito).\n",[560,561,563,566],"h3",{"id":562},"json_serializable-typed-json-serialization",[18,564,565],{},"json_serializable"," — Typed JSON Serialization",[23,568,569],{"language":487},[27,570,573],{"className":571,"code":572,"language":487,"meta":31,"style":31},"language-dart shiki shiki-themes github-light github-dark","import 'package:json_annotation\u002Fjson_annotation.dart';\n\n\u002F\u002F The `part` directive includes the generated file (user.g.dart).\n\u002F\u002F After `dart run build_runner build`, this file contains:\n\u002F\u002F   _$UserFromJson(Map\u003CString, dynamic>) → User\n\u002F\u002F   _$UserToJson(User) → Map\u003CString, dynamic>\npart 'user.g.dart';\n\n@JsonSerializable()\nclass User {\n  final int id;\n  final String name;\n  final String? email;  \u002F\u002F nullable — optional in JSON\n  @JsonKey(name: 'created_at')  \u002F\u002F JSON key differs from Dart field name\n  final DateTime createdAt;\n\n  User({required this.id, required this.name, this.email, required this.createdAt});\n\n  \u002F\u002F Generated factory + method — type-safe JSON serialization.\n  factory User.fromJson(Map\u003CString, dynamic> json) => _$UserFromJson(json);\n  Map\u003CString, dynamic> toJson() => _$UserToJson(this);\n}\n\n\u002F\u002F Usage:\nfinal user = User(id: 1, name: 'Alice', createdAt: DateTime.now());\nfinal json = user.toJson();  \u002F\u002F {'id': 1, 'name': 'Alice', 'created_at': '...'}\nfinal parsed = User.fromJson(json);  \u002F\u002F type-safe, validated at runtime\n\n\u002F\u002F ── Custom converters (for non-standard types) ──\nclass DateTimeMillisConverter implements JsonConverter\u003CDateTime, int> {\n  const DateTimeMillisConverter();\n  @override\n  DateTime fromJson(int json) => DateTime.fromMillisecondsSinceEpoch(json);\n  @override\n  int toJson(DateTime object) => object.millisecondsSinceEpoch;\n}\n\n@JsonSerializable()\nclass Event {\n  final String id;\n  @DateTimeMillisConverter()  \u002F\u002F ← custom converter for this field\n  final DateTime timestamp;\n  Event({required this.id, required this.timestamp});\n  factory Event.fromJson(Map\u003CString, dynamic> json) => _$EventFromJson(json);\n  Map\u003CString, dynamic> toJson() => _$EventToJson(this);\n}\n",[18,574,575,587,591,596,601,606,611,621,625,633,644,655,665,680,700,710,714,751,755,760,803,837,842,846,851,895,915,936,940,945,971,981,986,1012,1016,1036,1040,1044,1050,1059,1067,1078,1087,1107,1139,1169],{"__ignoreMap":31},[35,576,577,581,584],{"class":37,"line":38},[35,578,580],{"class":579},"svdQ7","import",[35,582,583],{"class":56}," 'package:json_annotation\u002Fjson_annotation.dart'",[35,585,586],{"class":52},";\n",[35,588,589],{"class":37,"line":45},[35,590,64],{"emptyLinePlaceholder":63},[35,592,593],{"class":37,"line":60},[35,594,595],{"class":41},"\u002F\u002F The `part` directive includes the generated file (user.g.dart).\n",[35,597,598],{"class":37,"line":67},[35,599,600],{"class":41},"\u002F\u002F After `dart run build_runner build`, this file contains:\n",[35,602,603],{"class":37,"line":76},[35,604,605],{"class":41},"\u002F\u002F   _$UserFromJson(Map\u003CString, dynamic>) → User\n",[35,607,608],{"class":37,"line":82},[35,609,610],{"class":41},"\u002F\u002F   _$UserToJson(User) → Map\u003CString, dynamic>\n",[35,612,613,616,619],{"class":37,"line":90},[35,614,615],{"class":579},"part",[35,617,618],{"class":56}," 'user.g.dart'",[35,620,586],{"class":52},[35,622,623],{"class":37,"line":99},[35,624,64],{"emptyLinePlaceholder":63},[35,626,627,630],{"class":37,"line":110},[35,628,629],{"class":579},"@JsonSerializable",[35,631,632],{"class":52},"()\n",[35,634,635,638,641],{"class":37,"line":121},[35,636,637],{"class":579},"class",[35,639,640],{"class":159}," User",[35,642,643],{"class":52}," {\n",[35,645,646,649,652],{"class":37,"line":132},[35,647,648],{"class":579},"  final",[35,650,651],{"class":159}," int",[35,653,654],{"class":52}," id;\n",[35,656,657,659,662],{"class":37,"line":137},[35,658,648],{"class":579},[35,660,661],{"class":159}," String",[35,663,664],{"class":52}," name;\n",[35,666,667,669,671,674,677],{"class":37,"line":143},[35,668,648],{"class":579},[35,670,661],{"class":159},[35,672,673],{"class":579},"?",[35,675,676],{"class":52}," email;  ",[35,678,679],{"class":41},"\u002F\u002F nullable — optional in JSON\n",[35,681,682,685,688,691,694,697],{"class":37,"line":151},[35,683,684],{"class":579},"  @JsonKey",[35,686,687],{"class":52},"(name",[35,689,690],{"class":579},":",[35,692,693],{"class":56}," 'created_at'",[35,695,696],{"class":52},")  ",[35,698,699],{"class":41},"\u002F\u002F JSON key differs from Dart field name\n",[35,701,702,704,707],{"class":37,"line":166},[35,703,648],{"class":579},[35,705,706],{"class":159}," DateTime",[35,708,709],{"class":52}," createdAt;\n",[35,711,712],{"class":37,"line":179},[35,713,64],{"emptyLinePlaceholder":63},[35,715,716,719,722,725,728,731,733,735,738,741,744,746,748],{"class":37,"line":192},[35,717,718],{"class":159},"  User",[35,720,721],{"class":52},"({",[35,723,724],{"class":579},"required",[35,726,727],{"class":159}," this",[35,729,730],{"class":52},".id, ",[35,732,724],{"class":579},[35,734,727],{"class":159},[35,736,737],{"class":52},".name, ",[35,739,740],{"class":159},"this",[35,742,743],{"class":52},".email, ",[35,745,724],{"class":579},[35,747,727],{"class":159},[35,749,750],{"class":52},".createdAt});\n",[35,752,753],{"class":37,"line":197},[35,754,64],{"emptyLinePlaceholder":63},[35,756,757],{"class":37,"line":203},[35,758,759],{"class":41},"  \u002F\u002F Generated factory + method — type-safe JSON serialization.\n",[35,761,762,765,767,770,773,776,779,782,785,788,791,794,797,800],{"class":37,"line":211},[35,763,764],{"class":579},"  factory",[35,766,640],{"class":159},[35,768,769],{"class":52},".",[35,771,772],{"class":486},"fromJson",[35,774,775],{"class":52},"(",[35,777,778],{"class":159},"Map",[35,780,781],{"class":52},"\u003C",[35,783,784],{"class":159},"String",[35,786,787],{"class":52},", ",[35,789,790],{"class":159},"dynamic",[35,792,793],{"class":52},"> json) ",[35,795,796],{"class":579},"=>",[35,798,799],{"class":159}," _$UserFromJson",[35,801,802],{"class":52},"(json);\n",[35,804,805,808,810,812,814,816,819,822,825,827,830,832,834],{"class":37,"line":225},[35,806,807],{"class":159},"  Map",[35,809,781],{"class":52},[35,811,784],{"class":159},[35,813,787],{"class":52},[35,815,790],{"class":159},[35,817,818],{"class":52},"> ",[35,820,821],{"class":486},"toJson",[35,823,824],{"class":52},"() ",[35,826,796],{"class":579},[35,828,829],{"class":159}," _$UserToJson",[35,831,775],{"class":52},[35,833,740],{"class":159},[35,835,836],{"class":52},");\n",[35,838,839],{"class":37,"line":238},[35,840,841],{"class":52},"}\n",[35,843,844],{"class":37,"line":243},[35,845,64],{"emptyLinePlaceholder":63},[35,847,848],{"class":37,"line":251},[35,849,850],{"class":41},"\u002F\u002F Usage:\n",[35,852,853,856,859,862,864,867,869,872,875,877,880,883,885,887,889,892],{"class":37,"line":259},[35,854,855],{"class":579},"final",[35,857,858],{"class":52}," user ",[35,860,861],{"class":579},"=",[35,863,640],{"class":159},[35,865,866],{"class":52},"(id",[35,868,690],{"class":579},[35,870,871],{"class":159}," 1",[35,873,874],{"class":52},", name",[35,876,690],{"class":579},[35,878,879],{"class":56}," 'Alice'",[35,881,882],{"class":52},", createdAt",[35,884,690],{"class":579},[35,886,706],{"class":159},[35,888,769],{"class":52},[35,890,891],{"class":486},"now",[35,893,894],{"class":52},"());\n",[35,896,897,899,902,904,907,909,912],{"class":37,"line":265},[35,898,855],{"class":579},[35,900,901],{"class":52}," json ",[35,903,861],{"class":579},[35,905,906],{"class":52}," user.",[35,908,821],{"class":486},[35,910,911],{"class":52},"();  ",[35,913,914],{"class":41},"\u002F\u002F {'id': 1, 'name': 'Alice', 'created_at': '...'}\n",[35,916,917,919,922,924,926,928,930,933],{"class":37,"line":276},[35,918,855],{"class":579},[35,920,921],{"class":52}," parsed ",[35,923,861],{"class":579},[35,925,640],{"class":159},[35,927,769],{"class":52},[35,929,772],{"class":486},[35,931,932],{"class":52},"(json);  ",[35,934,935],{"class":41},"\u002F\u002F type-safe, validated at runtime\n",[35,937,938],{"class":37,"line":284},[35,939,64],{"emptyLinePlaceholder":63},[35,941,942],{"class":37,"line":292},[35,943,944],{"class":41},"\u002F\u002F ── Custom converters (for non-standard types) ──\n",[35,946,947,949,952,955,958,960,963,965,968],{"class":37,"line":303},[35,948,637],{"class":579},[35,950,951],{"class":159}," DateTimeMillisConverter",[35,953,954],{"class":579}," implements",[35,956,957],{"class":159}," JsonConverter",[35,959,781],{"class":52},[35,961,962],{"class":159},"DateTime",[35,964,787],{"class":52},[35,966,967],{"class":159},"int",[35,969,970],{"class":52},"> {\n",[35,972,973,976,978],{"class":37,"line":314},[35,974,975],{"class":579},"  const",[35,977,951],{"class":159},[35,979,980],{"class":52},"();\n",[35,982,983],{"class":37,"line":325},[35,984,985],{"class":579},"  @override\n",[35,987,988,991,994,996,998,1001,1003,1005,1007,1010],{"class":37,"line":336},[35,989,990],{"class":159},"  DateTime",[35,992,993],{"class":486}," fromJson",[35,995,775],{"class":52},[35,997,967],{"class":159},[35,999,1000],{"class":52}," json) ",[35,1002,796],{"class":579},[35,1004,706],{"class":159},[35,1006,769],{"class":52},[35,1008,1009],{"class":486},"fromMillisecondsSinceEpoch",[35,1011,802],{"class":52},[35,1013,1014],{"class":37,"line":341},[35,1015,985],{"class":579},[35,1017,1018,1021,1024,1026,1028,1031,1033],{"class":37,"line":347},[35,1019,1020],{"class":159},"  int",[35,1022,1023],{"class":486}," toJson",[35,1025,775],{"class":52},[35,1027,962],{"class":159},[35,1029,1030],{"class":52}," object) ",[35,1032,796],{"class":579},[35,1034,1035],{"class":52}," object.millisecondsSinceEpoch;\n",[35,1037,1038],{"class":37,"line":358},[35,1039,841],{"class":52},[35,1041,1042],{"class":37,"line":369},[35,1043,64],{"emptyLinePlaceholder":63},[35,1045,1046,1048],{"class":37,"line":380},[35,1047,629],{"class":579},[35,1049,632],{"class":52},[35,1051,1052,1054,1057],{"class":37,"line":391},[35,1053,637],{"class":579},[35,1055,1056],{"class":159}," Event",[35,1058,643],{"class":52},[35,1060,1061,1063,1065],{"class":37,"line":396},[35,1062,648],{"class":579},[35,1064,661],{"class":159},[35,1066,654],{"class":52},[35,1068,1069,1072,1075],{"class":37,"line":402},[35,1070,1071],{"class":579},"  @DateTimeMillisConverter",[35,1073,1074],{"class":52},"()  ",[35,1076,1077],{"class":41},"\u002F\u002F ← custom converter for this field\n",[35,1079,1080,1082,1084],{"class":37,"line":413},[35,1081,648],{"class":579},[35,1083,706],{"class":159},[35,1085,1086],{"class":52}," timestamp;\n",[35,1088,1089,1092,1094,1096,1098,1100,1102,1104],{"class":37,"line":424},[35,1090,1091],{"class":159},"  Event",[35,1093,721],{"class":52},[35,1095,724],{"class":579},[35,1097,727],{"class":159},[35,1099,730],{"class":52},[35,1101,724],{"class":579},[35,1103,727],{"class":159},[35,1105,1106],{"class":52},".timestamp});\n",[35,1108,1110,1112,1114,1116,1118,1120,1122,1124,1126,1128,1130,1132,1134,1137],{"class":37,"line":1109},44,[35,1111,764],{"class":579},[35,1113,1056],{"class":159},[35,1115,769],{"class":52},[35,1117,772],{"class":486},[35,1119,775],{"class":52},[35,1121,778],{"class":159},[35,1123,781],{"class":52},[35,1125,784],{"class":159},[35,1127,787],{"class":52},[35,1129,790],{"class":159},[35,1131,793],{"class":52},[35,1133,796],{"class":579},[35,1135,1136],{"class":159}," _$EventFromJson",[35,1138,802],{"class":52},[35,1140,1142,1144,1146,1148,1150,1152,1154,1156,1158,1160,1163,1165,1167],{"class":37,"line":1141},45,[35,1143,807],{"class":159},[35,1145,781],{"class":52},[35,1147,784],{"class":159},[35,1149,787],{"class":52},[35,1151,790],{"class":159},[35,1153,818],{"class":52},[35,1155,821],{"class":486},[35,1157,824],{"class":52},[35,1159,796],{"class":579},[35,1161,1162],{"class":159}," _$EventToJson",[35,1164,775],{"class":52},[35,1166,740],{"class":159},[35,1168,836],{"class":52},[35,1170,1172],{"class":37,"line":1171},46,[35,1173,841],{"class":52},[560,1175,1177,1180],{"id":1176},"freezed-immutable-data-classes-sealed-unions",[18,1178,1179],{},"freezed"," — Immutable Data Classes & Sealed Unions",[23,1182,1183],{"language":487},[27,1184,1186],{"className":571,"code":1185,"language":487,"meta":31,"style":31},"import 'package:freezed_annotation\u002Ffreezed_annotation.dart';\n\n\u002F\u002F freezed generates: immutable class, ==\u002FhashCode, copyWith, toString,\n\u002F\u002F sealed union types, and JSON serialization — all from one annotation.\n\npart 'result.freezed.dart';\npart 'result.g.dart';  \u002F\u002F for JSON (if using @Freezed(toJson: true))\n\n\u002F\u002F ── Sealed union (like a sealed class with data) ──\n@freezed\nsealed class Result\u003CT> with _$Result\u003CT> {\n  const factory Result.success(T value) = Success\u003CT>;\n  const factory Result.failure(String error) = Failure\u003CT>;\n  const factory Result.loading() = Loading\u003CT>;\n\n  \u002F\u002F JSON (optional — requires part 'result.g.dart'):\n  factory Result.fromJson(Map\u003CString, dynamic> json) => _$ResultFromJson(json);\n}\n\n\u002F\u002F Usage with exhaustive switch:\nString describe\u003CT>(Result\u003CT> r) => switch (r) {\n  Success(:final value) => 'OK: $value',\n  Failure(:final error) => 'ERR: $error',\n  Loading() => 'Loading...',\n};\n\n\u002F\u002F ── Immutable data class with copyWith ──\n@freezed\nclass User with _$User {\n  const factory User({\n    required int id,\n    required String name,\n    required String email,\n    @Default([]) List\u003CString> tags,  \u002F\u002F default value\n  }) = _User;\n\n  factory User.fromJson(Map\u003CString, dynamic> json) => _$UserFromJson(json);\n}\n\n\u002F\u002F copyWith creates a new instance with modified fields (original unchanged):\nfinal user = User(id: 1, name: 'Alice', email: 'alice@ex.com');\nfinal updated = user.copyWith(name: 'Bob');  \u002F\u002F new instance, name changed\n\u002F\u002F user.name is still 'Alice' — immutability preserved.\n\n\u002F\u002F Value equality is automatic:\nprint(User(id: 1, name: 'A', email: 'a@x') == User(id: 1, name: 'A', email: 'a@x'));  \u002F\u002F true\n",[18,1187,1188,1197,1201,1206,1211,1215,1224,1237,1241,1246,1251,1281,1314,1345,1371,1375,1380,1411,1415,1419,1424,1456,1485,1510,1524,1529,1533,1538,1542,1556,1567,1577,1586,1595,1616,1628,1632,1662,1666,1670,1675,1707,1734,1739,1743,1748],{"__ignoreMap":31},[35,1189,1190,1192,1195],{"class":37,"line":38},[35,1191,580],{"class":579},[35,1193,1194],{"class":56}," 'package:freezed_annotation\u002Ffreezed_annotation.dart'",[35,1196,586],{"class":52},[35,1198,1199],{"class":37,"line":45},[35,1200,64],{"emptyLinePlaceholder":63},[35,1202,1203],{"class":37,"line":60},[35,1204,1205],{"class":41},"\u002F\u002F freezed generates: immutable class, ==\u002FhashCode, copyWith, toString,\n",[35,1207,1208],{"class":37,"line":67},[35,1209,1210],{"class":41},"\u002F\u002F sealed union types, and JSON serialization — all from one annotation.\n",[35,1212,1213],{"class":37,"line":76},[35,1214,64],{"emptyLinePlaceholder":63},[35,1216,1217,1219,1222],{"class":37,"line":82},[35,1218,615],{"class":579},[35,1220,1221],{"class":56}," 'result.freezed.dart'",[35,1223,586],{"class":52},[35,1225,1226,1228,1231,1234],{"class":37,"line":90},[35,1227,615],{"class":579},[35,1229,1230],{"class":56}," 'result.g.dart'",[35,1232,1233],{"class":52},";  ",[35,1235,1236],{"class":41},"\u002F\u002F for JSON (if using @Freezed(toJson: true))\n",[35,1238,1239],{"class":37,"line":99},[35,1240,64],{"emptyLinePlaceholder":63},[35,1242,1243],{"class":37,"line":110},[35,1244,1245],{"class":41},"\u002F\u002F ── Sealed union (like a sealed class with data) ──\n",[35,1247,1248],{"class":37,"line":121},[35,1249,1250],{"class":579},"@freezed\n",[35,1252,1253,1256,1259,1262,1264,1267,1269,1272,1275,1277,1279],{"class":37,"line":132},[35,1254,1255],{"class":579},"sealed",[35,1257,1258],{"class":579}," class",[35,1260,1261],{"class":159}," Result",[35,1263,781],{"class":52},[35,1265,1266],{"class":159},"T",[35,1268,818],{"class":52},[35,1270,1271],{"class":579},"with",[35,1273,1274],{"class":159}," _$Result",[35,1276,781],{"class":52},[35,1278,1266],{"class":159},[35,1280,970],{"class":52},[35,1282,1283,1285,1288,1290,1292,1295,1297,1299,1302,1304,1307,1309,1311],{"class":37,"line":137},[35,1284,975],{"class":579},[35,1286,1287],{"class":579}," factory",[35,1289,1261],{"class":159},[35,1291,769],{"class":52},[35,1293,1294],{"class":486},"success",[35,1296,775],{"class":52},[35,1298,1266],{"class":159},[35,1300,1301],{"class":52}," value) ",[35,1303,861],{"class":579},[35,1305,1306],{"class":159}," Success",[35,1308,781],{"class":52},[35,1310,1266],{"class":159},[35,1312,1313],{"class":52},">;\n",[35,1315,1316,1318,1320,1322,1324,1327,1329,1331,1334,1336,1339,1341,1343],{"class":37,"line":143},[35,1317,975],{"class":579},[35,1319,1287],{"class":579},[35,1321,1261],{"class":159},[35,1323,769],{"class":52},[35,1325,1326],{"class":486},"failure",[35,1328,775],{"class":52},[35,1330,784],{"class":159},[35,1332,1333],{"class":52}," error) ",[35,1335,861],{"class":579},[35,1337,1338],{"class":159}," Failure",[35,1340,781],{"class":52},[35,1342,1266],{"class":159},[35,1344,1313],{"class":52},[35,1346,1347,1349,1351,1353,1355,1358,1360,1362,1365,1367,1369],{"class":37,"line":151},[35,1348,975],{"class":579},[35,1350,1287],{"class":579},[35,1352,1261],{"class":159},[35,1354,769],{"class":52},[35,1356,1357],{"class":486},"loading",[35,1359,824],{"class":52},[35,1361,861],{"class":579},[35,1363,1364],{"class":159}," Loading",[35,1366,781],{"class":52},[35,1368,1266],{"class":159},[35,1370,1313],{"class":52},[35,1372,1373],{"class":37,"line":166},[35,1374,64],{"emptyLinePlaceholder":63},[35,1376,1377],{"class":37,"line":179},[35,1378,1379],{"class":41},"  \u002F\u002F JSON (optional — requires part 'result.g.dart'):\n",[35,1381,1382,1384,1386,1388,1390,1392,1394,1396,1398,1400,1402,1404,1406,1409],{"class":37,"line":192},[35,1383,764],{"class":579},[35,1385,1261],{"class":159},[35,1387,769],{"class":52},[35,1389,772],{"class":486},[35,1391,775],{"class":52},[35,1393,778],{"class":159},[35,1395,781],{"class":52},[35,1397,784],{"class":159},[35,1399,787],{"class":52},[35,1401,790],{"class":159},[35,1403,793],{"class":52},[35,1405,796],{"class":579},[35,1407,1408],{"class":159}," _$ResultFromJson",[35,1410,802],{"class":52},[35,1412,1413],{"class":37,"line":197},[35,1414,841],{"class":52},[35,1416,1417],{"class":37,"line":203},[35,1418,64],{"emptyLinePlaceholder":63},[35,1420,1421],{"class":37,"line":211},[35,1422,1423],{"class":41},"\u002F\u002F Usage with exhaustive switch:\n",[35,1425,1426,1428,1431,1433,1435,1438,1441,1443,1445,1448,1450,1453],{"class":37,"line":225},[35,1427,784],{"class":159},[35,1429,1430],{"class":486}," describe",[35,1432,781],{"class":52},[35,1434,1266],{"class":159},[35,1436,1437],{"class":52},">(",[35,1439,1440],{"class":159},"Result",[35,1442,781],{"class":52},[35,1444,1266],{"class":159},[35,1446,1447],{"class":52},"> r) ",[35,1449,796],{"class":579},[35,1451,1452],{"class":579}," switch",[35,1454,1455],{"class":52}," (r) {\n",[35,1457,1458,1461,1463,1466,1468,1470,1473,1476,1479,1482],{"class":37,"line":238},[35,1459,1460],{"class":159},"  Success",[35,1462,775],{"class":52},[35,1464,1465],{"class":579},":final",[35,1467,1301],{"class":52},[35,1469,796],{"class":579},[35,1471,1472],{"class":56}," 'OK: ",[35,1474,1475],{"class":56},"$",[35,1477,1478],{"class":159},"value",[35,1480,1481],{"class":56},"'",[35,1483,1484],{"class":52},",\n",[35,1486,1487,1490,1492,1494,1496,1498,1501,1503,1506,1508],{"class":37,"line":243},[35,1488,1489],{"class":159},"  Failure",[35,1491,775],{"class":52},[35,1493,1465],{"class":579},[35,1495,1333],{"class":52},[35,1497,796],{"class":579},[35,1499,1500],{"class":56}," 'ERR: ",[35,1502,1475],{"class":56},[35,1504,1505],{"class":159},"error",[35,1507,1481],{"class":56},[35,1509,1484],{"class":52},[35,1511,1512,1515,1517,1519,1522],{"class":37,"line":251},[35,1513,1514],{"class":159},"  Loading",[35,1516,824],{"class":52},[35,1518,796],{"class":579},[35,1520,1521],{"class":56}," 'Loading...'",[35,1523,1484],{"class":52},[35,1525,1526],{"class":37,"line":259},[35,1527,1528],{"class":52},"};\n",[35,1530,1531],{"class":37,"line":265},[35,1532,64],{"emptyLinePlaceholder":63},[35,1534,1535],{"class":37,"line":276},[35,1536,1537],{"class":41},"\u002F\u002F ── Immutable data class with copyWith ──\n",[35,1539,1540],{"class":37,"line":284},[35,1541,1250],{"class":579},[35,1543,1544,1546,1548,1551,1554],{"class":37,"line":292},[35,1545,637],{"class":579},[35,1547,640],{"class":159},[35,1549,1550],{"class":579}," with",[35,1552,1553],{"class":159}," _$User",[35,1555,643],{"class":52},[35,1557,1558,1560,1562,1564],{"class":37,"line":303},[35,1559,975],{"class":579},[35,1561,1287],{"class":579},[35,1563,640],{"class":159},[35,1565,1566],{"class":52},"({\n",[35,1568,1569,1572,1574],{"class":37,"line":314},[35,1570,1571],{"class":579},"    required",[35,1573,651],{"class":159},[35,1575,1576],{"class":52}," id,\n",[35,1578,1579,1581,1583],{"class":37,"line":325},[35,1580,1571],{"class":579},[35,1582,661],{"class":159},[35,1584,1585],{"class":52}," name,\n",[35,1587,1588,1590,1592],{"class":37,"line":336},[35,1589,1571],{"class":579},[35,1591,661],{"class":159},[35,1593,1594],{"class":52}," email,\n",[35,1596,1597,1600,1603,1606,1608,1610,1613],{"class":37,"line":341},[35,1598,1599],{"class":579},"    @Default",[35,1601,1602],{"class":52},"([]) ",[35,1604,1605],{"class":159},"List",[35,1607,781],{"class":52},[35,1609,784],{"class":159},[35,1611,1612],{"class":52},"> tags,  ",[35,1614,1615],{"class":41},"\u002F\u002F default value\n",[35,1617,1618,1621,1623,1626],{"class":37,"line":347},[35,1619,1620],{"class":52},"  }) ",[35,1622,861],{"class":579},[35,1624,1625],{"class":159}," _User",[35,1627,586],{"class":52},[35,1629,1630],{"class":37,"line":358},[35,1631,64],{"emptyLinePlaceholder":63},[35,1633,1634,1636,1638,1640,1642,1644,1646,1648,1650,1652,1654,1656,1658,1660],{"class":37,"line":369},[35,1635,764],{"class":579},[35,1637,640],{"class":159},[35,1639,769],{"class":52},[35,1641,772],{"class":486},[35,1643,775],{"class":52},[35,1645,778],{"class":159},[35,1647,781],{"class":52},[35,1649,784],{"class":159},[35,1651,787],{"class":52},[35,1653,790],{"class":159},[35,1655,793],{"class":52},[35,1657,796],{"class":579},[35,1659,799],{"class":159},[35,1661,802],{"class":52},[35,1663,1664],{"class":37,"line":380},[35,1665,841],{"class":52},[35,1667,1668],{"class":37,"line":391},[35,1669,64],{"emptyLinePlaceholder":63},[35,1671,1672],{"class":37,"line":396},[35,1673,1674],{"class":41},"\u002F\u002F copyWith creates a new instance with modified fields (original unchanged):\n",[35,1676,1677,1679,1681,1683,1685,1687,1689,1691,1693,1695,1697,1700,1702,1705],{"class":37,"line":402},[35,1678,855],{"class":579},[35,1680,858],{"class":52},[35,1682,861],{"class":579},[35,1684,640],{"class":159},[35,1686,866],{"class":52},[35,1688,690],{"class":579},[35,1690,871],{"class":159},[35,1692,874],{"class":52},[35,1694,690],{"class":579},[35,1696,879],{"class":56},[35,1698,1699],{"class":52},", email",[35,1701,690],{"class":579},[35,1703,1704],{"class":56}," 'alice@ex.com'",[35,1706,836],{"class":52},[35,1708,1709,1711,1714,1716,1718,1721,1723,1725,1728,1731],{"class":37,"line":413},[35,1710,855],{"class":579},[35,1712,1713],{"class":52}," updated ",[35,1715,861],{"class":579},[35,1717,906],{"class":52},[35,1719,1720],{"class":486},"copyWith",[35,1722,687],{"class":52},[35,1724,690],{"class":579},[35,1726,1727],{"class":56}," 'Bob'",[35,1729,1730],{"class":52},");  ",[35,1732,1733],{"class":41},"\u002F\u002F new instance, name changed\n",[35,1735,1736],{"class":37,"line":424},[35,1737,1738],{"class":41},"\u002F\u002F user.name is still 'Alice' — immutability preserved.\n",[35,1740,1741],{"class":37,"line":1109},[35,1742,64],{"emptyLinePlaceholder":63},[35,1744,1745],{"class":37,"line":1141},[35,1746,1747],{"class":41},"\u002F\u002F Value equality is automatic:\n",[35,1749,1750,1753,1755,1758,1760,1762,1764,1766,1768,1771,1773,1775,1778,1781,1784,1786,1788,1790,1792,1794,1796,1798,1800,1802,1804,1807],{"class":37,"line":1171},[35,1751,1752],{"class":486},"print",[35,1754,775],{"class":52},[35,1756,1757],{"class":159},"User",[35,1759,866],{"class":52},[35,1761,690],{"class":579},[35,1763,871],{"class":159},[35,1765,874],{"class":52},[35,1767,690],{"class":579},[35,1769,1770],{"class":56}," 'A'",[35,1772,1699],{"class":52},[35,1774,690],{"class":579},[35,1776,1777],{"class":56}," 'a@x'",[35,1779,1780],{"class":52},") ",[35,1782,1783],{"class":579},"==",[35,1785,640],{"class":159},[35,1787,866],{"class":52},[35,1789,690],{"class":579},[35,1791,871],{"class":159},[35,1793,874],{"class":52},[35,1795,690],{"class":579},[35,1797,1770],{"class":56},[35,1799,1699],{"class":52},[35,1801,690],{"class":579},[35,1803,1777],{"class":56},[35,1805,1806],{"class":52},"));  ",[35,1808,1809],{"class":41},"\u002F\u002F true\n",[14,1811,1813],{"id":1812},"cicd-github-actions","CI\u002FCD — GitHub Actions",[23,1815,1816,2101,2108,2229,2233,2353,2357,2682,2686,2792,2796,2962,2966,2970,3069,3084],{"language":25},[27,1817,1819],{"className":29,"code":1818,"language":25,"meta":31,"style":31},"# .github\u002Fworkflows\u002Fdart.yml\nname: Dart CI\non: [push, pull_request]\n\njobs:\n  analyze-and-test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: dart-lang\u002Fsetup-dart@v1\n        with:\n          sdk: stable\n\n      # Install dependencies\n      - run: dart pub get\n\n      # ── Format check (fails if files aren't formatted) ──\n      - run: dart format --set-exit-if-changed .\n\n      # ── Static analysis (treat infos\u002Fwarnings as errors) ──\n      - run: dart analyze --fatal-infos\n\n      # ── Code generation (if using build_runner) ──\n      - run: dart run build_runner build --delete-conflicting-outputs\n\n      # ── Tests ──\n      - run: dart test\n\n      # ── Coverage (optional) ──\n      - run: dart test --coverage=coverage\n      - run: dart pub global activate coverage\n      - run: dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage\u002Flcov.info --packages=.packages --report-on=lib\n      - uses: codecov\u002Fcodecov-action@v3\n        with:\n          file: coverage\u002Flcov.info\n",[18,1820,1821,1826,1836,1855,1859,1866,1873,1883,1890,1903,1914,1921,1931,1935,1940,1952,1956,1961,1972,1976,1981,1992,1996,2001,2012,2016,2021,2032,2036,2041,2052,2063,2074,2085,2091],{"__ignoreMap":31},[35,1822,1823],{"class":37,"line":38},[35,1824,1825],{"class":41},"# .github\u002Fworkflows\u002Fdart.yml\n",[35,1827,1828,1831,1833],{"class":37,"line":45},[35,1829,1830],{"class":48},"name",[35,1832,53],{"class":52},[35,1834,1835],{"class":56},"Dart CI\n",[35,1837,1838,1841,1844,1847,1849,1852],{"class":37,"line":60},[35,1839,1840],{"class":159},"on",[35,1842,1843],{"class":52},": [",[35,1845,1846],{"class":56},"push",[35,1848,787],{"class":52},[35,1850,1851],{"class":56},"pull_request",[35,1853,1854],{"class":52},"]\n",[35,1856,1857],{"class":37,"line":67},[35,1858,64],{"emptyLinePlaceholder":63},[35,1860,1861,1864],{"class":37,"line":76},[35,1862,1863],{"class":48},"jobs",[35,1865,73],{"class":52},[35,1867,1868,1871],{"class":37,"line":82},[35,1869,1870],{"class":48},"  analyze-and-test",[35,1872,73],{"class":52},[35,1874,1875,1878,1880],{"class":37,"line":90},[35,1876,1877],{"class":48},"    runs-on",[35,1879,53],{"class":52},[35,1881,1882],{"class":56},"ubuntu-latest\n",[35,1884,1885,1888],{"class":37,"line":99},[35,1886,1887],{"class":48},"    steps",[35,1889,73],{"class":52},[35,1891,1892,1895,1898,1900],{"class":37,"line":110},[35,1893,1894],{"class":52},"      - ",[35,1896,1897],{"class":48},"uses",[35,1899,53],{"class":52},[35,1901,1902],{"class":56},"actions\u002Fcheckout@v4\n",[35,1904,1905,1907,1909,1911],{"class":37,"line":121},[35,1906,1894],{"class":52},[35,1908,1897],{"class":48},[35,1910,53],{"class":52},[35,1912,1913],{"class":56},"dart-lang\u002Fsetup-dart@v1\n",[35,1915,1916,1919],{"class":37,"line":132},[35,1917,1918],{"class":48},"        with",[35,1920,73],{"class":52},[35,1922,1923,1926,1928],{"class":37,"line":137},[35,1924,1925],{"class":48},"          sdk",[35,1927,53],{"class":52},[35,1929,1930],{"class":56},"stable\n",[35,1932,1933],{"class":37,"line":143},[35,1934,64],{"emptyLinePlaceholder":63},[35,1936,1937],{"class":37,"line":151},[35,1938,1939],{"class":41},"      # Install dependencies\n",[35,1941,1942,1944,1947,1949],{"class":37,"line":166},[35,1943,1894],{"class":52},[35,1945,1946],{"class":48},"run",[35,1948,53],{"class":52},[35,1950,1951],{"class":56},"dart pub get\n",[35,1953,1954],{"class":37,"line":179},[35,1955,64],{"emptyLinePlaceholder":63},[35,1957,1958],{"class":37,"line":192},[35,1959,1960],{"class":41},"      # ── Format check (fails if files aren't formatted) ──\n",[35,1962,1963,1965,1967,1969],{"class":37,"line":197},[35,1964,1894],{"class":52},[35,1966,1946],{"class":48},[35,1968,53],{"class":52},[35,1970,1971],{"class":56},"dart format --set-exit-if-changed .\n",[35,1973,1974],{"class":37,"line":203},[35,1975,64],{"emptyLinePlaceholder":63},[35,1977,1978],{"class":37,"line":211},[35,1979,1980],{"class":41},"      # ── Static analysis (treat infos\u002Fwarnings as errors) ──\n",[35,1982,1983,1985,1987,1989],{"class":37,"line":225},[35,1984,1894],{"class":52},[35,1986,1946],{"class":48},[35,1988,53],{"class":52},[35,1990,1991],{"class":56},"dart analyze --fatal-infos\n",[35,1993,1994],{"class":37,"line":238},[35,1995,64],{"emptyLinePlaceholder":63},[35,1997,1998],{"class":37,"line":243},[35,1999,2000],{"class":41},"      # ── Code generation (if using build_runner) ──\n",[35,2002,2003,2005,2007,2009],{"class":37,"line":251},[35,2004,1894],{"class":52},[35,2006,1946],{"class":48},[35,2008,53],{"class":52},[35,2010,2011],{"class":56},"dart run build_runner build --delete-conflicting-outputs\n",[35,2013,2014],{"class":37,"line":259},[35,2015,64],{"emptyLinePlaceholder":63},[35,2017,2018],{"class":37,"line":265},[35,2019,2020],{"class":41},"      # ── Tests ──\n",[35,2022,2023,2025,2027,2029],{"class":37,"line":276},[35,2024,1894],{"class":52},[35,2026,1946],{"class":48},[35,2028,53],{"class":52},[35,2030,2031],{"class":56},"dart test\n",[35,2033,2034],{"class":37,"line":284},[35,2035,64],{"emptyLinePlaceholder":63},[35,2037,2038],{"class":37,"line":292},[35,2039,2040],{"class":41},"      # ── Coverage (optional) ──\n",[35,2042,2043,2045,2047,2049],{"class":37,"line":303},[35,2044,1894],{"class":52},[35,2046,1946],{"class":48},[35,2048,53],{"class":52},[35,2050,2051],{"class":56},"dart test --coverage=coverage\n",[35,2053,2054,2056,2058,2060],{"class":37,"line":314},[35,2055,1894],{"class":52},[35,2057,1946],{"class":48},[35,2059,53],{"class":52},[35,2061,2062],{"class":56},"dart pub global activate coverage\n",[35,2064,2065,2067,2069,2071],{"class":37,"line":325},[35,2066,1894],{"class":52},[35,2068,1946],{"class":48},[35,2070,53],{"class":52},[35,2072,2073],{"class":56},"dart pub global run coverage:format_coverage --lcov --in=coverage --out=coverage\u002Flcov.info --packages=.packages --report-on=lib\n",[35,2075,2076,2078,2080,2082],{"class":37,"line":336},[35,2077,1894],{"class":52},[35,2079,1897],{"class":48},[35,2081,53],{"class":52},[35,2083,2084],{"class":56},"codecov\u002Fcodecov-action@v3\n",[35,2086,2087,2089],{"class":37,"line":341},[35,2088,1918],{"class":48},[35,2090,73],{"class":52},[35,2092,2093,2096,2098],{"class":37,"line":347},[35,2094,2095],{"class":48},"          file",[35,2097,53],{"class":52},[35,2099,2100],{"class":56},"coverage\u002Flcov.info\n",[14,2102,2104,2105],{"id":2103},"the-formatter-dart-format","The Formatter — ",[18,2106,2107],{},"dart format",[23,2109,2110],{"language":442},[27,2111,2113],{"className":445,"code":2112,"language":442,"meta":31,"style":31},"# dart format is opinionated (like gofmt) — it decides the style. Don't argue.\n# Configure your editor to format on save.\n\n# Format all files:\ndart format .\n\n# Custom line length (default is 80):\ndart format --line-length 100 .\n\n# CI check (fails if files aren't formatted — no auto-fix):\ndart format --set-exit-if-changed .\n\n# Format a single file:\ndart format lib\u002Fmain.dart\n\n# ── The formatter resolves all style debates ──\n# It handles: indentation, line wrapping, trailing commas, spacing.\n# There's no .editorconfig or .prettierrc — `dart format` IS the config.\n# For custom line length, set it in analysis_options.yaml or the CLI flag.\n",[18,2114,2115,2120,2125,2129,2134,2144,2148,2153,2167,2171,2176,2187,2191,2196,2205,2209,2214,2219,2224],{"__ignoreMap":31},[35,2116,2117],{"class":37,"line":38},[35,2118,2119],{"class":41},"# dart format is opinionated (like gofmt) — it decides the style. Don't argue.\n",[35,2121,2122],{"class":37,"line":45},[35,2123,2124],{"class":41},"# Configure your editor to format on save.\n",[35,2126,2127],{"class":37,"line":60},[35,2128,64],{"emptyLinePlaceholder":63},[35,2130,2131],{"class":37,"line":67},[35,2132,2133],{"class":41},"# Format all files:\n",[35,2135,2136,2138,2141],{"class":37,"line":76},[35,2137,487],{"class":486},[35,2139,2140],{"class":56}," format",[35,2142,2143],{"class":56}," .\n",[35,2145,2146],{"class":37,"line":82},[35,2147,64],{"emptyLinePlaceholder":63},[35,2149,2150],{"class":37,"line":90},[35,2151,2152],{"class":41},"# Custom line length (default is 80):\n",[35,2154,2155,2157,2159,2162,2165],{"class":37,"line":99},[35,2156,487],{"class":486},[35,2158,2140],{"class":56},[35,2160,2161],{"class":159}," --line-length",[35,2163,2164],{"class":159}," 100",[35,2166,2143],{"class":56},[35,2168,2169],{"class":37,"line":110},[35,2170,64],{"emptyLinePlaceholder":63},[35,2172,2173],{"class":37,"line":121},[35,2174,2175],{"class":41},"# CI check (fails if files aren't formatted — no auto-fix):\n",[35,2177,2178,2180,2182,2185],{"class":37,"line":132},[35,2179,487],{"class":486},[35,2181,2140],{"class":56},[35,2183,2184],{"class":159}," --set-exit-if-changed",[35,2186,2143],{"class":56},[35,2188,2189],{"class":37,"line":137},[35,2190,64],{"emptyLinePlaceholder":63},[35,2192,2193],{"class":37,"line":143},[35,2194,2195],{"class":41},"# Format a single file:\n",[35,2197,2198,2200,2202],{"class":37,"line":151},[35,2199,487],{"class":486},[35,2201,2140],{"class":56},[35,2203,2204],{"class":56}," lib\u002Fmain.dart\n",[35,2206,2207],{"class":37,"line":166},[35,2208,64],{"emptyLinePlaceholder":63},[35,2210,2211],{"class":37,"line":179},[35,2212,2213],{"class":41},"# ── The formatter resolves all style debates ──\n",[35,2215,2216],{"class":37,"line":192},[35,2217,2218],{"class":41},"# It handles: indentation, line wrapping, trailing commas, spacing.\n",[35,2220,2221],{"class":37,"line":197},[35,2222,2223],{"class":41},"# There's no .editorconfig or .prettierrc — `dart format` IS the config.\n",[35,2225,2226],{"class":37,"line":203},[35,2227,2228],{"class":41},"# For custom line length, set it in analysis_options.yaml or the CLI flag.\n",[14,2230,2232],{"id":2231},"devtools-profiling-debugging","DevTools — Profiling & Debugging",[23,2234,2235],{"language":442},[27,2236,2238],{"className":445,"code":2237,"language":442,"meta":31,"style":31},"# ── Launch DevTools (browser-based debugger\u002Fprofiler) ──\ndart devtools\n# Opens a browser with: Inspector, Performance, Memory, Network, Logging, Debugger.\n\n# ── For Flutter ──\nflutter run  # then press 'D' in the terminal to open DevTools\n\n# ── VM Service (remote debugging) ──\ndart run --observe bin\u002Fserver.dart       # starts VM service on default port\ndart run --observe=8181 bin\u002Fserver.dart  # pin the port\n\n# ── DevTools features ──\n# Inspector: widget tree (Flutter), properties, rendering\n# Performance: frame rendering timeline, CPU flame chart, jank detection\n# Memory: heap snapshots, allocation tracking, leak detection\n# Network: HTTP requests (Flutter), timing, payloads\n# Logging: structured logs, filtering\n# Debugger: breakpoints, step, variables, watch expressions\n",[18,2239,2240,2245,2252,2257,2261,2266,2276,2280,2285,2300,2314,2318,2323,2328,2333,2338,2343,2348],{"__ignoreMap":31},[35,2241,2242],{"class":37,"line":38},[35,2243,2244],{"class":41},"# ── Launch DevTools (browser-based debugger\u002Fprofiler) ──\n",[35,2246,2247,2249],{"class":37,"line":45},[35,2248,487],{"class":486},[35,2250,2251],{"class":56}," devtools\n",[35,2253,2254],{"class":37,"line":60},[35,2255,2256],{"class":41},"# Opens a browser with: Inspector, Performance, Memory, Network, Logging, Debugger.\n",[35,2258,2259],{"class":37,"line":67},[35,2260,64],{"emptyLinePlaceholder":63},[35,2262,2263],{"class":37,"line":76},[35,2264,2265],{"class":41},"# ── For Flutter ──\n",[35,2267,2268,2271,2273],{"class":37,"line":82},[35,2269,2270],{"class":486},"flutter",[35,2272,490],{"class":56},[35,2274,2275],{"class":41},"  # then press 'D' in the terminal to open DevTools\n",[35,2277,2278],{"class":37,"line":90},[35,2279,64],{"emptyLinePlaceholder":63},[35,2281,2282],{"class":37,"line":99},[35,2283,2284],{"class":41},"# ── VM Service (remote debugging) ──\n",[35,2286,2287,2289,2291,2294,2297],{"class":37,"line":110},[35,2288,487],{"class":486},[35,2290,490],{"class":56},[35,2292,2293],{"class":159}," --observe",[35,2295,2296],{"class":56}," bin\u002Fserver.dart",[35,2298,2299],{"class":41},"       # starts VM service on default port\n",[35,2301,2302,2304,2306,2309,2311],{"class":37,"line":121},[35,2303,487],{"class":486},[35,2305,490],{"class":56},[35,2307,2308],{"class":159}," --observe=8181",[35,2310,2296],{"class":56},[35,2312,2313],{"class":41},"  # pin the port\n",[35,2315,2316],{"class":37,"line":132},[35,2317,64],{"emptyLinePlaceholder":63},[35,2319,2320],{"class":37,"line":137},[35,2321,2322],{"class":41},"# ── DevTools features ──\n",[35,2324,2325],{"class":37,"line":143},[35,2326,2327],{"class":41},"# Inspector: widget tree (Flutter), properties, rendering\n",[35,2329,2330],{"class":37,"line":151},[35,2331,2332],{"class":41},"# Performance: frame rendering timeline, CPU flame chart, jank detection\n",[35,2334,2335],{"class":37,"line":166},[35,2336,2337],{"class":41},"# Memory: heap snapshots, allocation tracking, leak detection\n",[35,2339,2340],{"class":37,"line":179},[35,2341,2342],{"class":41},"# Network: HTTP requests (Flutter), timing, payloads\n",[35,2344,2345],{"class":37,"line":192},[35,2346,2347],{"class":41},"# Logging: structured logs, filtering\n",[35,2349,2350],{"class":37,"line":197},[35,2351,2352],{"class":41},"# Debugger: breakpoints, step, variables, watch expressions\n",[14,2354,2356],{"id":2355},"popular-packages-ecosystem-reference","Popular Packages — Ecosystem Reference",[23,2358,2359],{"language":25},[27,2360,2362],{"className":29,"code":2361,"language":25,"meta":31,"style":31},"# ── HTTP ──\ndependencies:\n  http: ^1.2.0          # basic HTTP client (cross-platform)\n  dio: ^5.0.0           # advanced (interceptors, cancellation, FormData)\n\n  # ── Server ──\n  shelf: ^1.4.0         # middleware framework\n  shelf_router: ^1.1.0  # routing for shelf\n  dart_frog: ^1.0.0     # file-based web framework\n\n  # ── Database ──\n  postgres: ^3.0.0     # PostgreSQL driver\n  sqlite3: ^2.0.0      # SQLite (sync, native)\n  drift: ^2.0.0         # reactive ORM (SQLite, code generation)\n\n  # ── State Management (Flutter) ──\n  flutter_riverpod: ^2.0.0  # modern, compile-safe\n  provider: ^6.0.0          # simple, official\n  flutter_bloc: ^8.0.0      # event-driven, scalable\n\n  # ── Utilities ──\n  intl: ^0.19.0        # i18n, date\u002Fnumber formatting\n  path: ^1.8.0         # path manipulation (cross-platform)\n  args: ^2.4.0         # CLI argument parsing\n\n  # ── Code Generation ──\ndev_dependencies:\n  build_runner: ^2.4.0     # runs generators\n  json_serializable: ^6.0.0 # JSON codegen\n  freezed: ^2.0.0           # immutable data classes\n  mocktail: ^1.0.0          # mocking (no codegen)\n  test: ^1.25.0             # testing framework\n  lints: ^4.0.0            # lint rule sets\n",[18,2363,2364,2369,2376,2389,2402,2406,2411,2424,2437,2450,2454,2459,2472,2485,2497,2501,2506,2518,2531,2544,2548,2553,2566,2579,2592,2596,2601,2608,2620,2632,2644,2656,2669],{"__ignoreMap":31},[35,2365,2366],{"class":37,"line":38},[35,2367,2368],{"class":41},"# ── HTTP ──\n",[35,2370,2371,2374],{"class":37,"line":45},[35,2372,2373],{"class":48},"dependencies",[35,2375,73],{"class":52},[35,2377,2378,2381,2383,2386],{"class":37,"line":60},[35,2379,2380],{"class":48},"  http",[35,2382,53],{"class":52},[35,2384,2385],{"class":56},"^1.2.0",[35,2387,2388],{"class":41},"          # basic HTTP client (cross-platform)\n",[35,2390,2391,2394,2396,2399],{"class":37,"line":67},[35,2392,2393],{"class":48},"  dio",[35,2395,53],{"class":52},[35,2397,2398],{"class":56},"^5.0.0",[35,2400,2401],{"class":41},"           # advanced (interceptors, cancellation, FormData)\n",[35,2403,2404],{"class":37,"line":76},[35,2405,64],{"emptyLinePlaceholder":63},[35,2407,2408],{"class":37,"line":82},[35,2409,2410],{"class":41},"  # ── Server ──\n",[35,2412,2413,2416,2418,2421],{"class":37,"line":90},[35,2414,2415],{"class":48},"  shelf",[35,2417,53],{"class":52},[35,2419,2420],{"class":56},"^1.4.0",[35,2422,2423],{"class":41},"         # middleware framework\n",[35,2425,2426,2429,2431,2434],{"class":37,"line":99},[35,2427,2428],{"class":48},"  shelf_router",[35,2430,53],{"class":52},[35,2432,2433],{"class":56},"^1.1.0",[35,2435,2436],{"class":41},"  # routing for shelf\n",[35,2438,2439,2442,2444,2447],{"class":37,"line":110},[35,2440,2441],{"class":48},"  dart_frog",[35,2443,53],{"class":52},[35,2445,2446],{"class":56},"^1.0.0",[35,2448,2449],{"class":41},"     # file-based web framework\n",[35,2451,2452],{"class":37,"line":121},[35,2453,64],{"emptyLinePlaceholder":63},[35,2455,2456],{"class":37,"line":132},[35,2457,2458],{"class":41},"  # ── Database ──\n",[35,2460,2461,2464,2466,2469],{"class":37,"line":137},[35,2462,2463],{"class":48},"  postgres",[35,2465,53],{"class":52},[35,2467,2468],{"class":56},"^3.0.0",[35,2470,2471],{"class":41},"     # PostgreSQL driver\n",[35,2473,2474,2477,2479,2482],{"class":37,"line":143},[35,2475,2476],{"class":48},"  sqlite3",[35,2478,53],{"class":52},[35,2480,2481],{"class":56},"^2.0.0",[35,2483,2484],{"class":41},"      # SQLite (sync, native)\n",[35,2486,2487,2490,2492,2494],{"class":37,"line":151},[35,2488,2489],{"class":48},"  drift",[35,2491,53],{"class":52},[35,2493,2481],{"class":56},[35,2495,2496],{"class":41},"         # reactive ORM (SQLite, code generation)\n",[35,2498,2499],{"class":37,"line":166},[35,2500,64],{"emptyLinePlaceholder":63},[35,2502,2503],{"class":37,"line":179},[35,2504,2505],{"class":41},"  # ── State Management (Flutter) ──\n",[35,2507,2508,2511,2513,2515],{"class":37,"line":192},[35,2509,2510],{"class":48},"  flutter_riverpod",[35,2512,53],{"class":52},[35,2514,2481],{"class":56},[35,2516,2517],{"class":41},"  # modern, compile-safe\n",[35,2519,2520,2523,2525,2528],{"class":37,"line":197},[35,2521,2522],{"class":48},"  provider",[35,2524,53],{"class":52},[35,2526,2527],{"class":56},"^6.0.0",[35,2529,2530],{"class":41},"          # simple, official\n",[35,2532,2533,2536,2538,2541],{"class":37,"line":203},[35,2534,2535],{"class":48},"  flutter_bloc",[35,2537,53],{"class":52},[35,2539,2540],{"class":56},"^8.0.0",[35,2542,2543],{"class":41},"      # event-driven, scalable\n",[35,2545,2546],{"class":37,"line":211},[35,2547,64],{"emptyLinePlaceholder":63},[35,2549,2550],{"class":37,"line":225},[35,2551,2552],{"class":41},"  # ── Utilities ──\n",[35,2554,2555,2558,2560,2563],{"class":37,"line":238},[35,2556,2557],{"class":48},"  intl",[35,2559,53],{"class":52},[35,2561,2562],{"class":56},"^0.19.0",[35,2564,2565],{"class":41},"        # i18n, date\u002Fnumber formatting\n",[35,2567,2568,2571,2573,2576],{"class":37,"line":243},[35,2569,2570],{"class":48},"  path",[35,2572,53],{"class":52},[35,2574,2575],{"class":56},"^1.8.0",[35,2577,2578],{"class":41},"         # path manipulation (cross-platform)\n",[35,2580,2581,2584,2586,2589],{"class":37,"line":251},[35,2582,2583],{"class":48},"  args",[35,2585,53],{"class":52},[35,2587,2588],{"class":56},"^2.4.0",[35,2590,2591],{"class":41},"         # CLI argument parsing\n",[35,2593,2594],{"class":37,"line":259},[35,2595,64],{"emptyLinePlaceholder":63},[35,2597,2598],{"class":37,"line":265},[35,2599,2600],{"class":41},"  # ── Code Generation ──\n",[35,2602,2603,2606],{"class":37,"line":276},[35,2604,2605],{"class":48},"dev_dependencies",[35,2607,73],{"class":52},[35,2609,2610,2613,2615,2617],{"class":37,"line":284},[35,2611,2612],{"class":48},"  build_runner",[35,2614,53],{"class":52},[35,2616,2588],{"class":56},[35,2618,2619],{"class":41},"     # runs generators\n",[35,2621,2622,2625,2627,2629],{"class":37,"line":292},[35,2623,2624],{"class":48},"  json_serializable",[35,2626,53],{"class":52},[35,2628,2527],{"class":56},[35,2630,2631],{"class":41}," # JSON codegen\n",[35,2633,2634,2637,2639,2641],{"class":37,"line":303},[35,2635,2636],{"class":48},"  freezed",[35,2638,53],{"class":52},[35,2640,2481],{"class":56},[35,2642,2643],{"class":41},"           # immutable data classes\n",[35,2645,2646,2649,2651,2653],{"class":37,"line":314},[35,2647,2648],{"class":48},"  mocktail",[35,2650,53],{"class":52},[35,2652,2446],{"class":56},[35,2654,2655],{"class":41},"          # mocking (no codegen)\n",[35,2657,2658,2661,2663,2666],{"class":37,"line":325},[35,2659,2660],{"class":48},"  test",[35,2662,53],{"class":52},[35,2664,2665],{"class":56},"^1.25.0",[35,2667,2668],{"class":41},"             # testing framework\n",[35,2670,2671,2674,2676,2679],{"class":37,"line":336},[35,2672,2673],{"class":48},"  lints",[35,2675,53],{"class":52},[35,2677,2678],{"class":56},"^4.0.0",[35,2680,2681],{"class":41},"            # lint rule sets\n",[14,2683,2685],{"id":2684},"tips-tricks","💡 Tips & Tricks",[2687,2688,2689,2708,2727,2752,2779],"ul",{},[2690,2691,2692,2696,2697,2699,2700,2703,2704,2707],"li",{},[2693,2694,2695],"strong",{},"Idiom",": run ",[18,2698,2107],{}," on save and in CI — Dart has an opinionated formatter (like ",[18,2701,2702],{},"gofmt","), so code style is automatic and consistent. Configure your editor to format on save; enforce with ",[18,2705,2706],{},"dart format --set-exit-if-changed"," in CI.",[2690,2709,2710,2696,2712,2715,2716,2719,2720,2722,2723,2726],{},[2693,2711,2695],{},[18,2713,2714],{},"dart analyze"," in CI with ",[18,2717,2718],{},"--fatal-infos"," — catches type errors, lints, unused code. Configure rules in ",[18,2721,20],{}," (start with ",[18,2724,2725],{},"package:lints\u002Frecommended.yaml","). Treat warnings as errors in production.",[2690,2728,2729,2731,2732,2735,2736,2739,2740,2743,2744,2747,2748,2751],{},[2693,2730,2695],{},": use ",[18,2733,2734],{},"build_runner watch"," during development for code generation — it regenerates ",[18,2737,2738],{},".g.dart","\u002F",[18,2741,2742],{},".freezed.dart"," files on save. Use ",[18,2745,2746],{},"build"," for CI (one-shot). Run ",[18,2749,2750],{},"--delete-conflicting-outputs"," if stale files cause issues.",[2690,2753,2754,2731,2756,2758,2759,2761,2762,2764,2765,2739,2767,787,2770,2772,2773,2775,2776,2778],{},[2693,2755,2695],{},[18,2757,565],{}," + ",[18,2760,1179],{}," for data models — ",[18,2763,1179],{}," for immutable classes, ",[18,2766,1783],{},[18,2768,2769],{},"hashCode",[18,2771,1720],{},", sealed unions; ",[18,2774,565],{}," for JSON. Both use code generation (run ",[18,2777,439],{},").",[2690,2780,2781,2783,2784,2787,2788,2791],{},[2693,2782,2695],{},": use DevTools for debugging and profiling — Inspector (widget tree), Performance (frame\u002FCPU), Memory (heap). For Flutter, press ",[18,2785,2786],{},"D"," in ",[18,2789,2790],{},"flutter run"," to open DevTools. Invaluable for performance issues.",[14,2793,2795],{"id":2794},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2687,2797,2798,2816,2839,2853,2868,2885,2898,2913,2927,2948],{},[2690,2799,2800,2808,2809,2811,2812,2815],{},[2693,2801,2802,2803,787,2805,2807],{},"Generated files (",[18,2804,2738],{},[18,2806,2742],{},") shouldn't be edited",": they're regenerated by ",[18,2810,439],{},", overwriting your changes. Add them to ",[18,2813,2814],{},".gitignore"," (or commit them — a project choice; committing avoids a build step for consumers).",[2690,2817,2818,2823,2824,2827,2828,2831,2832,2835,2836,2778],{},[2693,2819,2820,2822],{},[18,2821,439],{}," can be slow",": for large projects, ",[18,2825,2826],{},"build_runner build"," can take minutes. Use ",[18,2829,2830],{},"watch"," (incremental) in dev. Or use packages without codegen (",[18,2833,2834],{},"mocktail"," instead of ",[18,2837,2838],{},"mockito",[2690,2840,2841,2846,2847,2850,2851,2778],{},[2693,2842,2843,2845],{},[18,2844,2107],{}," line length (default 80)",": configure with ",[18,2848,2849],{},"--line-length 100"," if 80 is too narrow. Be consistent across the project (configure in ",[18,2852,20],{},[2690,2854,2855,53,2860,2863,2864,2867],{},[2693,2856,2857,2859],{},[18,2858,2714],{}," rules can be strict",[18,2861,2862],{},"strict.yaml"," may flag style preferences as errors. Start with ",[18,2865,2866],{},"recommended.yaml"," and add rules as needed. Don't enable all rules blindly.",[2690,2869,2870,2876,2877,2880,2881,2884],{},[2693,2871,2872,2875],{},[18,2873,2874],{},"dart test --coverage"," needs post-processing",": the raw coverage data isn't a report. Use ",[18,2878,2879],{},"dart pub global run coverage:format_coverage"," to generate LCOV, then ",[18,2882,2883],{},"genhtml"," for HTML.",[2690,2886,2887,2893,2894,2897],{},[2693,2888,2889,2892],{},[18,2890,2891],{},"dart pub publish"," requires a pub.dev account",": first publish prompts for a confirmation. Once published, a version is permanent (can't be republished; must bump version). Use ",[18,2895,2896],{},"--dry-run"," to check.",[2690,2899,2900,2906,2907,2909,2910,2912],{},[2693,2901,2902,2903,2905],{},"Generated mocks (",[18,2904,2838],{},") need rebuild",": if you change the class, run ",[18,2908,2826],{}," to regenerate mocks. Stale mocks cause test failures. ",[18,2911,2834],{}," avoids this (no codegen).",[2690,2914,2915,53,2921,2924,2925,769],{},[2693,2916,2917,2920],{},[18,2918,2919],{},"part 'x.g.dart'"," must match the file",[18,2922,2923],{},"part 'user.g.dart';"," must point to the generated file. A mismatch (typo, wrong path) causes a compile error after ",[18,2926,439],{},[2690,2928,2929,2938,2939,2941,2942,2944,2945,2778],{},[2693,2930,2931,2933,2934,2937],{},[18,2932,70],{}," ",[18,2935,2936],{},"exclude"," for generated files",": generated files (",[18,2940,2738],{},") may not pass strict analysis. Exclude them in ",[18,2943,20],{}," (",[18,2946,2947],{},"exclude: ['**\u002F*.g.dart']",[2690,2949,2950,2953,2954,2957,2958,2961],{},[2693,2951,2952],{},"DevTools version",": use the DevTools matching your Dart\u002FFlutter version. ",[18,2955,2956],{},"dart devtools"," launches the bundled version; ",[18,2959,2960],{},"dart pub global activate devtools"," gets the latest.",[14,2963,2965],{"id":2964},"spot-the-bug","🧠 Spot the Bug",[2967,2968,2969],"p",{},"A developer edits a generated file to fix a JSON parsing issue, but the fix disappears after the next build:",[23,2971,2972],{"language":487},[27,2973,2975],{"className":571,"code":2974,"language":487,"meta":31,"style":31},"\u002F\u002F user.g.dart (generated by json_serializable)\nUser _$UserFromJson(Map\u003CString, dynamic> json) {\n  return User(\n    id: json['id'] as int,        \u002F\u002F ← throws if 'id' is null\n    name: json['name'] as String,\n  );\n}\n",[18,2976,2977,2982,3003,3013,3040,3060,3065],{"__ignoreMap":31},[35,2978,2979],{"class":37,"line":38},[35,2980,2981],{"class":41},"\u002F\u002F user.g.dart (generated by json_serializable)\n",[35,2983,2984,2986,2988,2990,2992,2994,2996,2998,3000],{"class":37,"line":45},[35,2985,1757],{"class":159},[35,2987,799],{"class":159},[35,2989,775],{"class":52},[35,2991,778],{"class":159},[35,2993,781],{"class":52},[35,2995,784],{"class":159},[35,2997,787],{"class":52},[35,2999,790],{"class":159},[35,3001,3002],{"class":52},"> json) {\n",[35,3004,3005,3008,3010],{"class":37,"line":60},[35,3006,3007],{"class":579},"  return",[35,3009,640],{"class":159},[35,3011,3012],{"class":52},"(\n",[35,3014,3015,3018,3020,3023,3026,3029,3032,3034,3037],{"class":37,"line":67},[35,3016,3017],{"class":52},"    id",[35,3019,690],{"class":579},[35,3021,3022],{"class":52}," json[",[35,3024,3025],{"class":56},"'id'",[35,3027,3028],{"class":52},"] ",[35,3030,3031],{"class":579},"as",[35,3033,651],{"class":159},[35,3035,3036],{"class":52},",        ",[35,3038,3039],{"class":41},"\u002F\u002F ← throws if 'id' is null\n",[35,3041,3042,3045,3047,3049,3052,3054,3056,3058],{"class":37,"line":76},[35,3043,3044],{"class":52},"    name",[35,3046,690],{"class":579},[35,3048,3022],{"class":52},[35,3050,3051],{"class":56},"'name'",[35,3053,3028],{"class":52},[35,3055,3031],{"class":579},[35,3057,661],{"class":159},[35,3059,1484],{"class":52},[35,3061,3062],{"class":37,"line":82},[35,3063,3064],{"class":52},"  );\n",[35,3066,3067],{"class":37,"line":90},[35,3068,841],{"class":52},[2967,3070,3071,3072,3075,3076,3079,3080,3083],{},"The developer changes ",[18,3073,3074],{},"json['id'] as int"," to ",[18,3077,3078],{},"json['id'] as int? ?? 0",", but after running ",[18,3081,3082],{},"dart run build_runner build",", the change is gone. Why?",[3085,3086,3087,3091,3120,3126,3268,3281],"details",{},[3088,3089,3090],"summary",{},"Answer",[2967,3092,3093,3096,3097,3100,3101,3103,3104,3107,3108,2787,3110,3113,3114,3116,3117,3119],{},[18,3094,3095],{},"user.g.dart"," is a ",[2693,3098,3099],{},"generated file"," — ",[18,3102,439],{}," regenerates it from the ",[18,3105,3106],{},"@JsonSerializable()"," annotation on ",[18,3109,1757],{},[18,3111,3112],{},"user.dart",". Any manual edits to ",[18,3115,3095],{}," are overwritten on the next ",[18,3118,2826],{},". The generated file is derived from the source annotation, not editable.",[2967,3121,3122,3123,3125],{},"The fix — change the source (",[18,3124,3112],{},"), not the generated file:",[27,3127,3129],{"className":571,"code":3128,"language":487,"meta":31,"style":31},"\u002F\u002F user.dart\n@JsonSerializable()\nclass User {\n  final int id;  \u002F\u002F ← change to int? for nullable, or use @JsonKey(defaultValue: 0)\n  final String name;\n\n  User({this.id = 0, required this.name});  \u002F\u002F default value for missing id\n\n  factory User.fromJson(Map\u003CString, dynamic> json) => _$UserFromJson(json);\n  Map\u003CString, dynamic> toJson() => _$UserToJson(this);\n}\n",[18,3130,3131,3136,3142,3150,3162,3170,3174,3202,3206,3236,3264],{"__ignoreMap":31},[35,3132,3133],{"class":37,"line":38},[35,3134,3135],{"class":41},"\u002F\u002F user.dart\n",[35,3137,3138,3140],{"class":37,"line":45},[35,3139,629],{"class":579},[35,3141,632],{"class":52},[35,3143,3144,3146,3148],{"class":37,"line":60},[35,3145,637],{"class":579},[35,3147,640],{"class":159},[35,3149,643],{"class":52},[35,3151,3152,3154,3156,3159],{"class":37,"line":67},[35,3153,648],{"class":579},[35,3155,651],{"class":159},[35,3157,3158],{"class":52}," id;  ",[35,3160,3161],{"class":41},"\u002F\u002F ← change to int? for nullable, or use @JsonKey(defaultValue: 0)\n",[35,3163,3164,3166,3168],{"class":37,"line":76},[35,3165,648],{"class":579},[35,3167,661],{"class":159},[35,3169,664],{"class":52},[35,3171,3172],{"class":37,"line":82},[35,3173,64],{"emptyLinePlaceholder":63},[35,3175,3176,3178,3180,3182,3185,3187,3190,3192,3194,3196,3199],{"class":37,"line":90},[35,3177,718],{"class":159},[35,3179,721],{"class":52},[35,3181,740],{"class":159},[35,3183,3184],{"class":52},".id ",[35,3186,861],{"class":579},[35,3188,3189],{"class":159}," 0",[35,3191,787],{"class":52},[35,3193,724],{"class":579},[35,3195,727],{"class":159},[35,3197,3198],{"class":52},".name});  ",[35,3200,3201],{"class":41},"\u002F\u002F default value for missing id\n",[35,3203,3204],{"class":37,"line":99},[35,3205,64],{"emptyLinePlaceholder":63},[35,3207,3208,3210,3212,3214,3216,3218,3220,3222,3224,3226,3228,3230,3232,3234],{"class":37,"line":110},[35,3209,764],{"class":579},[35,3211,640],{"class":159},[35,3213,769],{"class":52},[35,3215,772],{"class":486},[35,3217,775],{"class":52},[35,3219,778],{"class":159},[35,3221,781],{"class":52},[35,3223,784],{"class":159},[35,3225,787],{"class":52},[35,3227,790],{"class":159},[35,3229,793],{"class":52},[35,3231,796],{"class":579},[35,3233,799],{"class":159},[35,3235,802],{"class":52},[35,3237,3238,3240,3242,3244,3246,3248,3250,3252,3254,3256,3258,3260,3262],{"class":37,"line":121},[35,3239,807],{"class":159},[35,3241,781],{"class":52},[35,3243,784],{"class":159},[35,3245,787],{"class":52},[35,3247,790],{"class":159},[35,3249,818],{"class":52},[35,3251,821],{"class":486},[35,3253,824],{"class":52},[35,3255,796],{"class":579},[35,3257,829],{"class":159},[35,3259,775],{"class":52},[35,3261,740],{"class":159},[35,3263,836],{"class":52},[35,3265,3266],{"class":37,"line":132},[35,3267,841],{"class":52},[2967,3269,3270,3271,3273,3274,3276,3277,3280],{},"Then run ",[18,3272,3082],{}," — the regenerated ",[18,3275,3095],{}," will handle ",[18,3278,3279],{},"id"," as nullable or with a default (from the annotation).",[2967,3282,3283,3284,787,3286,787,3288,3291,3292,3294],{},"Never edit generated files (",[18,3285,2738],{},[18,3287,2742],{},[18,3289,3290],{},".mocks.dart","). They're derived from annotations\u002Fsource. Change the source, regenerate. Add them to ",[18,3293,2814],{}," (and regenerate in CI) or commit them (avoiding a build step for consumers) — but never edit them.",[3296,3297,3298],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .sk71V, html code.shiki .sk71V{--shiki-default:#22863A;--shiki-github-dark:#85E89D}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}",{"title":31,"searchDepth":45,"depth":45,"links":3300},[3301,3303,3310,3311,3313,3314,3315,3316,3317],{"id":16,"depth":45,"text":3302},"analysis_options.yaml — Strict Analysis Configuration",{"id":435,"depth":45,"text":3304,"children":3305},"Code Generation — build_runner",[3306,3308],{"id":562,"depth":60,"text":3307},"json_serializable — Typed JSON Serialization",{"id":1176,"depth":60,"text":3309},"freezed — Immutable Data Classes & Sealed Unions",{"id":1812,"depth":45,"text":1813},{"id":2103,"depth":45,"text":3312},"The Formatter — dart format",{"id":2231,"depth":45,"text":2232},{"id":2355,"depth":45,"text":2356},{"id":2684,"depth":45,"text":2685},{"id":2794,"depth":45,"text":2795},{"id":2964,"depth":45,"text":2965},"Deep-dive into Dart's analyzer configuration, build_runner code generation, freezed\u002Fjson_serializable patterns, CI pipeline setup, and strict analysis rules. Code-first engineering reference.","md",{},"\u002Fdart\u002F18-tooling-and-ecosystem",{"title":5,"description":3318},"dart\u002F18-tooling-and-ecosystem","fJfn_d00Dewq9nsHWkW1xVP_ufdsx9qIbPiJoLydh1k",1789924647999]