Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions pkgs/hooks/tool/normalize.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void main(List<String> arguments) {
Directory.fromUri(packageUri.resolve('../code_assets/')),
Directory.fromUri(packageUri.resolve('../data_assets/')),
Directory.fromUri(packageUri.resolve('../pub_formats/')),
Directory.fromUri(packageUri.resolve('../record_use/')),
];
for (final directory in directories) {
final result = processDirectory(directory);
Expand Down Expand Up @@ -62,7 +63,12 @@ ProcessDirectoryResult processDirectory(Directory directory) {
for (final entity in entities) {
if (entity is File &&
p.extension(entity.path) == '.json' &&
!entity.path.contains('.dart_tool/')) {
// Don't sort non-source files.
!entity.uri.toFilePath(windows: false).contains('.dart_tool/') &&
// Don't sort recorded uses files, they have ordered arrays.
!entity.uri
.toFilePath(windows: false)
.contains('pkgs/record_use/test_data/json/')) {
processedCount++;
if (processFile(entity)) {
changedCount += 1;
Expand Down Expand Up @@ -212,15 +218,8 @@ dynamic sortJson(dynamic data, String filePath) {
return sortedMap;
}
if (data is List) {
return data.map((item) => sortJson(item, filePath)).toList()..sort((a, b) {
if (a is Map && b is Map) {
return compareMaps(a, b);
}
if (a is String && b is String) {
return a.compareTo(b);
}
throw UnimplementedError('Not implemented to compare $a and $b.');
});
return data.map((item) => sortJson(item, filePath)).toList()
..sort(_compareTwoItems);
}
return data;
}
Expand All @@ -229,15 +228,27 @@ int _compareTwoItems(dynamic a, dynamic b) {
if (a is Map && b is Map) {
return compareMaps(a, b);
}
if (a is String && b is String) {
return a.compareTo(b);
}
if (a is List && b is List) {
return compareLists(a, b);
}
if (a is String && b is String) {
return a.compareTo(b);
}
if (a is int && b is int) {
return a.compareTo(b);
}
if (a == b) {
return 0;
}
if (a is bool && b is bool) {
return a ? 1 : -1;
}
if (a == null && b != null) {
return -1;
}
if (b == null && a != null) {
return 1;
}
throw UnimplementedError('Not implemented to compare $a and $b.');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,17 @@ List<String> $validateName() => _reader.validateOptionalMap<${dartType.valueType
''');
}
} else {
throw UnimplementedError(valueType.toString());
buffer.writeln('''
$dartType get $fieldName => _reader.optionalMap<${dartType.valueType}>('$jsonKey', $keyPattern);
set $setterName($dartType value) {
_checkArgumentMapKeys(value, $keyPattern);
json.setOrRemove('$jsonKey', value);
$sortOnKey
}
List<String> $validateName() => _reader.validateMap<${dartType.valueType}>('$jsonKey', $keyPattern);
''');
}
default:
throw UnimplementedError(valueType.toString());
Expand Down Expand Up @@ -536,6 +546,25 @@ set $setterName($dartType value) {
List<String> $validateName() => _reader.$jsonValidate('$jsonKey');
''');

case 'Object':
case 'int':
final jsonRead = isNullable
? 'optionalList<$itemType>'
: 'list<$itemType>';
final jsonValidate = isNullable
? 'validateOptionalList<$itemType>'
: 'validateList<$itemType>';
final setter = setOrRemove(dartType, jsonKey);
buffer.writeln('''
$dartType get $fieldName => _reader.$jsonRead('$jsonKey');
set $setterName($dartType value) {
$setter
$sortOnKey
}
List<String> $validateName() => _reader.$jsonValidate('$jsonKey');
''');
default:
throw UnimplementedError(itemType.toString());
}
Expand Down
120 changes: 89 additions & 31 deletions pkgs/json_syntax_generator/lib/src/parser/schema_analyzer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -300,28 +300,33 @@ class SchemaAnalyzer {
bool required, {
bool allowEnum = true,
}) {
final type = schemas.type;
final (type, typeIsNullable) = schemas.typeAndNullable;
final isNullable = typeIsNullable || !required;

final DartType dartType;
switch (type) {
case null:
dartType = ObjectDartType(isNullable: !required);
dartType = ObjectDartType(isNullable: isNullable);
case SchemaType.boolean:
dartType = BoolDartType(isNullable: !required);
dartType = BoolDartType(isNullable: isNullable);
case SchemaType.integer:
dartType = IntDartType(isNullable: !required);
dartType = IntDartType(isNullable: isNullable);
case SchemaType.string:
if (schemas.generateUri) {
dartType = UriDartType(isNullable: !required);
dartType = UriDartType(isNullable: isNullable);
} else if (schemas.generateEnum && allowEnum) {
_analyzeEnumClass(schemas);
final classInfo = _classes[schemas.className]!;
dartType = ClassDartType(classInfo: classInfo, isNullable: !required);
dartType = ClassDartType(
classInfo: classInfo,
isNullable: isNullable,
);
} else {
if (schemas.patterns.length > 1) {
throw UnsupportedError('Only one pattern is supported.');
}
final pattern = schemas.patterns.firstOrNull;
dartType = StringDartType(isNullable: !required, pattern: pattern);
dartType = StringDartType(isNullable: isNullable, pattern: pattern);
}
case SchemaType.object:
final additionalPropertiesSchema =
Expand Down Expand Up @@ -352,7 +357,7 @@ class SchemaAnalyzer {
),
isNullable: false,
),
isNullable: !required,
isNullable: isNullable,
);
default:
throw UnimplementedError(itemType.toString());
Expand All @@ -366,7 +371,7 @@ class SchemaAnalyzer {
dartType = MapDartType(
keyType: keyDartType,
valueType: ClassDartType(classInfo: clazz, isNullable: false),
isNullable: !required,
isNullable: isNullable,
);
} else {
dartType = MapDartType(
Expand All @@ -375,17 +380,21 @@ class SchemaAnalyzer {
valueType: ObjectDartType(isNullable: true),
isNullable: false,
),
isNullable: !required,
isNullable: isNullable,
);
}
case null:
if (schemas.additionalPropertiesBool == true) {
dartType = ClassDartType(
classInfo: jsonObjectClassInfo,
isNullable: !required,
isNullable: isNullable,
);
} else {
final oneOfs = additionalPropertiesSchema.oneOfs;
if (oneOfs.isEmpty) {
// No type information.
return const ObjectDartType(isNullable: true);
}
if (oneOfs.length != 1) {
throw UnimplementedError();
}
Expand Down Expand Up @@ -413,7 +422,7 @@ class SchemaAnalyzer {
isNullable: true,
pattern: stringPattern,
),
isNullable: !required,
isNullable: isNullable,
);
} else {
throw UnimplementedError();
Expand All @@ -423,7 +432,13 @@ class SchemaAnalyzer {
dartType = MapDartType(
keyType: keyDartType,
valueType: const StringDartType(isNullable: false),
isNullable: !required,
isNullable: isNullable,
);
case SchemaType.integer:
dartType = MapDartType(
keyType: keyDartType,
valueType: const IntDartType(isNullable: false),
isNullable: isNullable,
);
default:
throw UnimplementedError(additionalPropertiesType.toString());
Expand All @@ -433,31 +448,60 @@ class SchemaAnalyzer {
typeName ??= _ucFirst(_snakeToCamelCase(propertyKey));
_analyzeClass(schemas, name: typeName);
final classInfo = _classes[typeName]!;
dartType = ClassDartType(classInfo: classInfo, isNullable: !required);
dartType = ClassDartType(
classInfo: classInfo,
isNullable: isNullable,
);
}
case SchemaType.array:
final items = schemas.items;
final itemType = items.type;
final (itemType, itemNullable) = items.typeAndNullable;
switch (itemType) {
case SchemaType.string:
if (items.generateUri) {
dartType = ListDartType(
itemType: const UriDartType(isNullable: false),
isNullable: !required,
itemType: UriDartType(isNullable: itemNullable),
isNullable: isNullable,
);
} else {
dartType = ListDartType(
itemType: const StringDartType(isNullable: false),
isNullable: !required,
itemType: StringDartType(isNullable: itemNullable),
isNullable: isNullable,
);
}
case SchemaType.object:
final typeName = items.className!;
_analyzeClass(items);
final classInfo = _classes[typeName]!;
case SchemaType.integer:
dartType = ListDartType(
itemType: ClassDartType(classInfo: classInfo, isNullable: false),
isNullable: !required,
itemType: IntDartType(isNullable: itemNullable),
isNullable: isNullable,
);
case SchemaType.object:
final typeName = items.className;
if (typeName != null) {
_analyzeClass(items);
final classInfo = _classes[typeName]!;
dartType = ListDartType(
itemType: ClassDartType(
classInfo: classInfo,
isNullable: itemNullable,
),
isNullable: isNullable,
);
} else if (items.generateMapOf) {
dartType = const ListDartType(
itemType: MapDartType(
valueType: ObjectDartType(isNullable: true),
isNullable: true,
),
isNullable: true,
);
} else {
throw UnimplementedError(itemType.toString());
}
case null:
// No type information.
dartType = const ListDartType(
itemType: ObjectDartType(isNullable: true),
isNullable: true,
);
default:
throw UnimplementedError(itemType.toString());
Expand Down Expand Up @@ -550,7 +594,7 @@ extension type JsonSchemas._(List<JsonSchema> _schemas) {
for (final schema in _schemas) ...schema.requiredProperties ?? [],
}.toList()..sort();

SchemaType? get type {
Set<SchemaType> get types {
final types = <SchemaType>{};
for (final schema in _schemas) {
final schemaTypes = schema.typeList;
Expand All @@ -560,12 +604,27 @@ extension type JsonSchemas._(List<JsonSchema> _schemas) {
}
}
}
return types;
}

SchemaType? get type {
if (types.length > 1) {
throw StateError('Multiple types found');
}
return types.singleOrNull;
}

(SchemaType?, bool) get typeAndNullable {
if (types.length <= 1) {
return (types.singleOrNull, false);
} else if (types.length == 2 && types.contains(SchemaType.nullValue)) {
final type = types.firstWhere((t) => t != SchemaType.nullValue);
return (type, true);
} else {
throw UnsupportedError('Multiple types: $types.');
}
}

List<RegExp> get patterns {
final patterns = <RegExp>{};
for (final schema in _schemas) {
Expand Down Expand Up @@ -745,10 +804,6 @@ extension on JsonSchemas {

String? get generateSubClassesKey {
if (type != SchemaType.object) return null;
// A tagged union either has only a key, or a key and an encoding.
// Classes with more than 2 properties have their a property that has
// predefined values generated as an enum class.
if (propertyKeys.length > 2) return null;
for (final p in propertyKeys) {
final propertySchemas = property(p);
if (propertySchemas.anyOfs.isNotEmpty) {
Expand Down Expand Up @@ -785,7 +840,10 @@ extension on JsonSchemas {
if (path.contains('#/definitions/')) {
final splits = path.split('/');
final indexOf = splits.indexOf('definitions');
final nameParts = splits.skip(indexOf + 1).where((e) => e.isNotEmpty);
final nameParts = splits
.skip(indexOf + 1)
.where((e) => e.isNotEmpty)
.toList();
if (nameParts.length == 1 && nameParts.single.startsWithUpperCase()) {
return nameParts.single;
}
Expand Down
1 change: 1 addition & 0 deletions pkgs/record_use/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Made locations optional to accomodate for dart2js compiler not providing
source locations for constant instances.
- Introduce a JSON schema for the json encoding.

## 0.4.2

Expand Down
Loading
Loading