// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file // for details. 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:async'; import 'package:build/build.dart'; import 'package:path/path.dart' as p; import 'package:source_gen/source_gen.dart'; final _copyrightContent = '''// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. '''; final copyrightHeader = '$_copyrightContent\n$defaultFileHeader'; Builder nonNull([_]) => LibraryBuilder(_NonNullableGenerator(), generatedExtension: '.non_nullable.dart', header: copyrightHeader); Builder wrapped([_]) => LibraryBuilder(_WrappedGenerator(), generatedExtension: '.wrapped.dart', header: copyrightHeader); Builder checked([_]) => LibraryBuilder(_CheckedGenerator(), generatedExtension: '.checked.dart', header: copyrightHeader); class _NonNullableGenerator extends Generator { @override FutureOr generate(LibraryReader library, BuildStep buildStep) async { final path = buildStep.inputId.path; final baseName = p.basenameWithoutExtension(path); final content = await buildStep.readAsString(buildStep.inputId); final replacements = [ _Replacement(_copyrightContent, ''), _Replacement( "part '$baseName.g.dart", "part '$baseName.non_nullable.g.dart", ), _Replacement('@JsonSerializable(', '@JsonSerializable(nullable: false,'), ]; if (baseName == 'kitchen_sink') { replacements.addAll([ _Replacement('List _defaultList() => null;', 'List _defaultList() => [];'), _Replacement('Set _defaultSet() => null;', 'Set _defaultSet() => Set();'), _Replacement('Map _defaultMap() => null;', 'Map _defaultMap() => {};'), _Replacement('SimpleObject _defaultSimpleObject() => null;', 'SimpleObject _defaultSimpleObject() => SimpleObject(42);'), _Replacement( 'StrictKeysObject _defaultStrictKeysObject() => null;', 'StrictKeysObject _defaultStrictKeysObject() => ' "StrictKeysObject(10, 'cool');"), _Replacement( 'DateTime dateTime;', 'DateTime dateTime = DateTime(1981, 6, 5);') ]); } return _Replacement.generate(content, replacements); } } class _CheckedGenerator extends Generator { @override FutureOr generate(LibraryReader library, BuildStep buildStep) async { final path = buildStep.inputId.path; final baseName = p.basenameWithoutExtension(path); final content = await buildStep.readAsString(buildStep.inputId); final replacements = [ _Replacement('@JsonSerializable(', '@JsonSerializable(checked: true,'), _Replacement(_copyrightContent, ''), _Replacement( "part '$baseName.g.dart", "part '$baseName.checked.g.dart", ), ]; if (baseName == 'default_value') { replacements.add( _Replacement('@JsonSerializable(', '@JsonSerializable(anyMap: true,'), ); } return _Replacement.generate(content, replacements); } } class _WrappedGenerator extends Generator { @override FutureOr generate(LibraryReader library, BuildStep buildStep) async { final path = buildStep.inputId.path; final baseName = p.basenameWithoutExtension(path); final content = await buildStep.readAsString(buildStep.inputId); final replacements = [ _Replacement(_copyrightContent, ''), _Replacement( "part '$baseName.g.dart", "part '$baseName.wrapped.g.dart", ), _Replacement( '@JsonSerializable(', '@JsonSerializable(useWrappers: true,'), ]; return _Replacement.generate(content, replacements); } } class _Replacement { final Pattern existing; final String replacement; _Replacement(this.existing, this.replacement); static String generate( String inputContent, Iterable<_Replacement> replacements) { var outputContent = inputContent; for (final r in replacements) { if (!outputContent.contains(r.existing)) { throw StateError( 'Input string did not contain `${r.existing}` as expected.'); } outputContent = outputContent.replaceAll(r.existing, r.replacement); } return outputContent; } }