diff --git a/pkgs/code_assets/doc/schema/shared/shared_definitions.generated.schema.json b/pkgs/code_assets/doc/schema/shared/shared_definitions.generated.schema.json index f3629226b..9bb0461d0 100644 --- a/pkgs/code_assets/doc/schema/shared/shared_definitions.generated.schema.json +++ b/pkgs/code_assets/doc/schema/shared/shared_definitions.generated.schema.json @@ -10,6 +10,19 @@ }, { "$ref": "../../../../hooks/doc/schema/shared/shared_definitions.schema.json#/definitions/BuildInput" + }, + { + "properties": { + "assets": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "shared_definitions.schema.json#/definitions/Asset" + } + } + } + } } ] }, @@ -32,6 +45,12 @@ } } }, + "assets_for_build": { + "type": "array", + "items": { + "$ref": "shared_definitions.schema.json#/definitions/Asset" + } + }, "assets_for_linking": { "type": "object", "additionalProperties": { diff --git a/pkgs/code_assets/doc/schema/shared/shared_definitions.schema.json b/pkgs/code_assets/doc/schema/shared/shared_definitions.schema.json index 8a19e9c56..3f6089f18 100644 --- a/pkgs/code_assets/doc/schema/shared/shared_definitions.schema.json +++ b/pkgs/code_assets/doc/schema/shared/shared_definitions.schema.json @@ -38,10 +38,10 @@ "type": "string", "anyOf": [ { - "const": "native_code" + "const": "code_assets/code" }, { - "const": "code_assets/code" + "const": "native_code" }, { "type": "string" @@ -54,7 +54,7 @@ "if": { "properties": { "type": { - "const": "native_code" + "const": "code_assets/code" } } }, @@ -63,20 +63,14 @@ "encoding": { "$ref": "#/definitions/NativeCodeAssetEncoding" } - }, - "allOf": [ - { - "$comment": "Also include the fields parent object for backwards compatibility.", - "$ref": "#/definitions/NativeCodeAssetEncoding" - } - ] + } } }, { "if": { "properties": { "type": { - "const": "code_assets/code" + "const": "native_code" } } }, @@ -85,7 +79,13 @@ "encoding": { "$ref": "#/definitions/NativeCodeAssetEncoding" } - } + }, + "allOf": [ + { + "$comment": "Also include the fields parent object for backwards compatibility.", + "$ref": "#/definitions/NativeCodeAssetEncoding" + } + ] } } ] diff --git a/pkgs/code_assets/test/data/build_input_macos.json b/pkgs/code_assets/test/data/build_input_macos.json index eec9ebd5b..2de3cec82 100644 --- a/pkgs/code_assets/test/data/build_input_macos.json +++ b/pkgs/code_assets/test/data/build_input_macos.json @@ -1,5 +1,28 @@ { "$schema": "../../doc/schema/sdk/build_input.generated.schema.json", + "assets": { + "some_package": [ + { + "architecture": "arm64", + "encoding": { + "architecture": "arm64", + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/iv6i0d/native_add/.dart_tool/native_assets_builder/native_add/c6b312c90c95d2d98ffb6760a738fb36/out/libnative_add.a", + "id": "package:native_add/src/native_add_bindings_generated.dart", + "link_mode": { + "type": "static" + }, + "os": "macos" + }, + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/iv6i0d/native_add/.dart_tool/native_assets_builder/native_add/c6b312c90c95d2d98ffb6760a738fb36/out/libnative_add.a", + "id": "package:native_add/src/native_add_bindings_generated.dart", + "link_mode": { + "type": "static" + }, + "os": "macos", + "type": "native_code" + } + ] + }, "config": { "build_asset_types": [ "native_code" diff --git a/pkgs/code_assets/test/data/build_output_macos.json b/pkgs/code_assets/test/data/build_output_macos.json index aa64cccb0..d76fa2ef2 100644 --- a/pkgs/code_assets/test/data/build_output_macos.json +++ b/pkgs/code_assets/test/data/build_output_macos.json @@ -116,6 +116,27 @@ } ] }, + "assets_for_build": [ + { + "architecture": "arm64", + "encoding": { + "architecture": "arm64", + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/iv6i0d/native_add/.dart_tool/native_assets_builder/native_add/c6b312c90c95d2d98ffb6760a738fb36/out/libnative_add.a", + "id": "package:native_add/src/native_add_bindings_generated.dart", + "link_mode": { + "type": "static" + }, + "os": "macos" + }, + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/iv6i0d/native_add/.dart_tool/native_assets_builder/native_add/c6b312c90c95d2d98ffb6760a738fb36/out/libnative_add.a", + "id": "package:native_add/src/native_add_bindings_generated.dart", + "link_mode": { + "type": "static" + }, + "os": "macos", + "type": "native_code" + } + ], "assets_for_linking": { "package_with_linker": [ { diff --git a/pkgs/code_assets/test/schema/schema_test.dart b/pkgs/code_assets/test/schema/schema_test.dart index fc779e91f..c879994dc 100644 --- a/pkgs/code_assets/test/schema/schema_test.dart +++ b/pkgs/code_assets/test/schema/schema_test.dart @@ -127,20 +127,12 @@ FieldsFunction _codeFields(AllTestData allTestData) { if (hook == Hook.build) ...[ for (final (field, expect) in codeAssetFields) for (final encoding in _encoding) - for (final assetsForLinking in [ - 'assetsForLinking', - 'assets_for_linking', + for (final path in [ + ['assets_for_build'], + ['assetsForLinking', 'package_with_linker'], + ['assets_for_linking', 'package_with_linker'], ]) - ( - [ - assetsForLinking, - 'package_with_linker', - 0, - ...encoding, - ...field, - ], - expect, - ), + ([...path, 0, ...encoding, ...field], expect), ], (['assets', staticIndex, 'file'], expectRequiredFieldMissing), ( diff --git a/pkgs/data_assets/doc/schema/shared/shared_definitions.generated.schema.json b/pkgs/data_assets/doc/schema/shared/shared_definitions.generated.schema.json index 9e5dc0fcd..46fc0ef6b 100644 --- a/pkgs/data_assets/doc/schema/shared/shared_definitions.generated.schema.json +++ b/pkgs/data_assets/doc/schema/shared/shared_definitions.generated.schema.json @@ -10,6 +10,19 @@ }, { "$ref": "../../../../hooks/doc/schema/shared/shared_definitions.schema.json#/definitions/BuildInput" + }, + { + "properties": { + "assets": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "shared_definitions.schema.json#/definitions/Asset" + } + } + } + } } ] }, @@ -32,6 +45,12 @@ } } }, + "assets_for_build": { + "type": "array", + "items": { + "$ref": "shared_definitions.schema.json#/definitions/Asset" + } + }, "assets_for_linking": { "type": "object", "additionalProperties": { diff --git a/pkgs/data_assets/test/data/build_input.json b/pkgs/data_assets/test/data/build_input.json index 884e7c155..2bc1f2c82 100644 --- a/pkgs/data_assets/test/data/build_input.json +++ b/pkgs/data_assets/test/data/build_input.json @@ -1,5 +1,31 @@ { "$schema": "../../doc/schema/sdk/build_input.generated.schema.json", + "assets": { + "some_package": [ + { + "encoding": { + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_0.json", + "name": "assets/data_0.json", + "package": "simple_link" + }, + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_0.json", + "name": "assets/data_0.json", + "package": "simple_link", + "type": "data" + }, + { + "encoding": { + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_1.json", + "name": "assets/data_1.json", + "package": "simple_link" + }, + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_1.json", + "name": "assets/data_1.json", + "package": "simple_link", + "type": "data" + } + ] + }, "config": { "build_asset_types": [ "data" diff --git a/pkgs/data_assets/test/data/build_output.json b/pkgs/data_assets/test/data/build_output.json index e7b62ceed..d2aaca2b3 100644 --- a/pkgs/data_assets/test/data/build_output.json +++ b/pkgs/data_assets/test/data/build_output.json @@ -50,6 +50,30 @@ } ] }, + "assets_for_build": [ + { + "encoding": { + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_0.json", + "name": "assets/data_0.json", + "package": "simple_link" + }, + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_0.json", + "name": "assets/data_0.json", + "package": "simple_link", + "type": "data" + }, + { + "encoding": { + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_1.json", + "name": "assets/data_1.json", + "package": "simple_link" + }, + "file": "/private/var/folders/2y/mngq9h194yzglt4kzttzfq6800klzg/T/0s5bKi/simple_link/assets/data_1.json", + "name": "assets/data_1.json", + "package": "simple_link", + "type": "data" + } + ], "assets_for_linking": { "package_with_linker": [ { diff --git a/pkgs/data_assets/test/schema/schema_test.dart b/pkgs/data_assets/test/schema/schema_test.dart index d3b83c723..c86d79b72 100644 --- a/pkgs/data_assets/test/schema/schema_test.dart +++ b/pkgs/data_assets/test/schema/schema_test.dart @@ -58,14 +58,12 @@ List<(List, void Function(ValidationResults result))> _dataFields({ if (hook == Hook.build) ...[ for (final field in _dataAssetFields) for (final encoding in _encoding) - for (final assetsForLinking in [ - 'assetsForLinking', - 'assets_for_linking', + for (final path in [ + ['assets_for_build'], + ['assetsForLinking', 'package_with_linker'], + ['assets_for_linking', 'package_with_linker'], ]) - ( - [assetsForLinking, 'package_with_linker', 0, ...encoding, field], - expectRequiredFieldMissing, - ), + ([...path, 0, ...encoding, field], expectRequiredFieldMissing), ], ], ]; diff --git a/pkgs/hooks/doc/schema/shared/shared_definitions.schema.json b/pkgs/hooks/doc/schema/shared/shared_definitions.schema.json index 962f983bd..b64ed7b59 100644 --- a/pkgs/hooks/doc/schema/shared/shared_definitions.schema.json +++ b/pkgs/hooks/doc/schema/shared/shared_definitions.schema.json @@ -6,7 +6,15 @@ "type": "object", "properties": { "type": { - "type": "string" + "type": "string", + "anyOf": [ + { + "const": "hooks/metadata" + }, + { + "type": "string" + } + ] }, "encoding": { "type": "object", @@ -15,6 +23,27 @@ }, "required": [ "type" + ], + "allOf": [ + { + "if": { + "properties": { + "type": { + "const": "hooks/metadata" + } + } + }, + "then": { + "properties": { + "encoding": { + "$ref": "#/definitions/MetadataAssetEncoding" + } + }, + "required": [ + "encoding" + ] + } + } ] }, "BuildConfig": { @@ -36,6 +65,15 @@ }, "BuildInput": { "properties": { + "assets": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/Asset" + } + } + }, "config": { "$ref": "#/definitions/BuildConfig" }, @@ -65,6 +103,12 @@ } } }, + "assets_for_build": { + "type": "array", + "items": { + "$ref": "#/definitions/Asset" + } + }, "assets_for_linking": { "type": "object", "additionalProperties": { @@ -196,6 +240,18 @@ } ] }, + "MetadataAssetEncoding": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": {} + }, + "required": [ + "key" + ] + }, "absolutePath": { "type": "string", "pattern": "^(\\/|[A-Za-z]:)" diff --git a/pkgs/hooks/test/data/build_input.json b/pkgs/hooks/test/data/build_input.json index 93f78e86a..8b7d189d0 100644 --- a/pkgs/hooks/test/data/build_input.json +++ b/pkgs/hooks/test/data/build_input.json @@ -1,5 +1,20 @@ { "$schema": "../../doc/schema/sdk/build_input.generated.schema.json", + "assets": { + "some_package": [ + { + "encoding": { + "key": "foo", + "value": "bar" + }, + "type": "hooks/metadata" + }, + { + "some_key": "some_value", + "type": "some_asset_type" + } + ] + }, "config": { "build_asset_types": [ "my_asset_type" diff --git a/pkgs/hooks/test/data/build_output.json b/pkgs/hooks/test/data/build_output.json index cffa92ce5..368ca06e5 100644 --- a/pkgs/hooks/test/data/build_output.json +++ b/pkgs/hooks/test/data/build_output.json @@ -20,35 +20,51 @@ "package_with_linker": [ { "encoding": { - "some_key": "some_value" + "a_key": "some_value" }, "some_key": "some_value", "type": "some_asset_type" }, { "encoding": { - "some_other_key": "some_value" + "key": "foo", + "value": "bar" }, - "some_other_key": "some_value", - "type": "some_other_asset_type" + "type": "hooks/metadata" } ] }, + "assets_for_build": [ + { + "encoding": { + "a_key": "some_value" + }, + "some_key": "some_value", + "type": "some_asset_type" + }, + { + "encoding": { + "key": "foo", + "value": "bar" + }, + "type": "hooks/metadata" + } + ], "assets_for_linking": { "package_with_linker": [ { "encoding": { - "some_key": "some_value" + "a_key": "some_value" }, "some_key": "some_value", "type": "some_asset_type" }, { "encoding": { - "some_other_key": "some_value" + "key": "foo", + "value": "bar" }, - "some_other_key": "some_value", - "type": "some_other_asset_type" + "type": "hooks/metadata" } ] }, diff --git a/pkgs/hooks/test/data/link_input.json b/pkgs/hooks/test/data/link_input.json index 351184a89..2e13e31db 100644 --- a/pkgs/hooks/test/data/link_input.json +++ b/pkgs/hooks/test/data/link_input.json @@ -2,12 +2,15 @@ "$schema": "../../doc/schema/sdk/link_input.generated.schema.json", "assets": [ { - "some_key": "some_value", + "a_key": "some_value", "type": "some_asset_type" }, { - "some_other_key": "some_value", - "type": "some_other_asset_type" + "encoding": { + "key": "foo", + "value": "bar" + }, + "type": "hooks/metadata" } ], "config": { diff --git a/pkgs/hooks/test/schema/helpers.dart b/pkgs/hooks/test/schema/helpers.dart index 862c5e83d..ad2c876fc 100644 --- a/pkgs/hooks/test/schema/helpers.dart +++ b/pkgs/hooks/test/schema/helpers.dart @@ -159,13 +159,14 @@ void testAllTestData(AllSchemas allSchemas, AllTestData allTestData) { /// [missingExpectations]. void testField({ required Uri schemaUri, + required Uri dataUri, required JsonSchema schema, required String data, required List field, required void Function(ValidationResults result) missingExpectations, }) { final fieldPath = field.join('.'); - test('$schemaUri $fieldPath missing', () { + test('$schemaUri $dataUri $fieldPath missing', () { final dataDecoded = jsonDecode(data); final dataToModify = _traverseJson( dataDecoded, @@ -254,6 +255,7 @@ void testFields({ field: field, schemaUri: schemaUri, schema: schema, + dataUri: dataUri, data: data, missingExpectations: missingExpectations, ); @@ -342,27 +344,34 @@ FieldsReturn _hookFields({ (['timestamp'], expectRequiredFieldMissing), (['dependencies'], expectOptionalFieldMissing), (['dependencies', 0], expectOptionalFieldMissing), - (['assets'], expectOptionalFieldMissing), - (['assets', 0], expectOptionalFieldMissing), - (['assets', 0, 'encoding'], expectOptionalFieldMissing), - (['assets', 0, 'type'], expectRequiredFieldMissing), - if (hook == Hook.build) - for (final assetsForLinking in [ - 'assetsForLinking', - 'assets_for_linking', + + if (hook == Hook.build) ...[ + (['metadata'], expectOptionalFieldMissing), + for (final path in [ + ['assets_for_build'], + ['assetsForLinking', 'package_with_linker'], + ['assets_for_linking', 'package_with_linker'], ]) ...[ - (['metadata'], expectOptionalFieldMissing), - ([assetsForLinking], expectOptionalFieldMissing), - ( - [assetsForLinking, 'package_with_linker', 0], - expectOptionalFieldMissing, - ), - ([assetsForLinking], expectOptionalFieldMissing), - ( - [assetsForLinking, 'package_with_linker', 0, 'type'], - expectRequiredFieldMissing, - ), + ([...path], expectOptionalFieldMissing), + ([...path, 0], expectOptionalFieldMissing), + ([...path, 0, 'type'], expectRequiredFieldMissing), + ([...path, 0, 'encoding'], expectOptionalFieldMissing), ], + ], + ], + for (final path in [ + if (inputOrOutput == InputOrOutput.output || hook == Hook.link) + ['assets'], + if (inputOrOutput == InputOrOutput.output && hook == Hook.build) ...[ + ['assets_for_build'], + ['assetsForLinking', 'package_with_linker'], + ['assets_for_linking', 'package_with_linker'], + ], + ]) ...[ + ([...path], expectOptionalFieldMissing), + ([...path, 0], expectOptionalFieldMissing), + ([...path, 0, 'type'], expectRequiredFieldMissing), + ([...path, 0, 'encoding'], expectOptionalFieldMissing), ], ]; } diff --git a/pkgs/hooks/test/schema/schema_test.dart b/pkgs/hooks/test/schema/schema_test.dart index c163281d7..51a0cf2a2 100644 --- a/pkgs/hooks/test/schema/schema_test.dart +++ b/pkgs/hooks/test/schema/schema_test.dart @@ -2,6 +2,8 @@ // 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 'package:json_schema/json_schema.dart'; + import 'helpers.dart'; void main() { @@ -19,6 +21,35 @@ void main() { allTestData: allTestData, packageUri: packageUri, ); + + testFields( + allSchemas: allSchemas, + allTestData: allTestData, + packageUri: packageUri, + fields: _metadataAssetFields, + ); } Uri packageUri = findPackageRoot('hooks'); + +List<(List, void Function(ValidationResults result))> +_metadataAssetFields({ + required InputOrOutput inputOrOutput, + required Hook hook, + required Party party, +}) => <(List, void Function(ValidationResults result))>[ + for (final path in [ + if (inputOrOutput == InputOrOutput.input && hook == Hook.link) ['assets'], + if (inputOrOutput == InputOrOutput.output && hook == Hook.build) ...[ + ['assets_for_build'], + ['assetsForLinking', 'package_with_linker'], + ['assets_for_linking', 'package_with_linker'], + ], + ]) ...[ + ([...path, 1], expectOptionalFieldMissing), + ([...path, 1, 'type'], expectRequiredFieldMissing), + ([...path, 1, 'encoding'], expectRequiredFieldMissing), + ([...path, 1, 'encoding', 'key'], expectRequiredFieldMissing), + // Skip `encoding.value`, it's optional and may have any type. + ], +]; diff --git a/pkgs/hooks/tool/generate_schemas.dart b/pkgs/hooks/tool/generate_schemas.dart index e13c9d77a..e00cea7ec 100644 --- a/pkgs/hooks/tool/generate_schemas.dart +++ b/pkgs/hooks/tool/generate_schemas.dart @@ -52,6 +52,23 @@ void generateSharedDefinitions() { }, }, }, + 'assets_for_build': { + 'type': 'array', + 'items': {r'$ref': 'shared_definitions.schema.json#/definitions/Asset'}, + }, + }, + }; + const buildInputAssetOverride = { + 'properties': { + 'assets': { + 'type': 'object', + 'additionalProperties': { + 'type': 'array', + 'items': { + r'$ref': 'shared_definitions.schema.json#/definitions/Asset', + }, + }, + }, }, }; const linkInputAssetOverride = { @@ -128,6 +145,10 @@ void generateSharedDefinitions() { hook == Hook.hook && inputOrOutput == InputOrOutput.output) hookOutputAssetOverride, + if (party == Party.shared && + hook == Hook.build && + inputOrOutput == InputOrOutput.input) + buildInputAssetOverride, if (party == Party.shared && hook == Hook.link && inputOrOutput == InputOrOutput.input) diff --git a/pkgs/json_syntax_generator/lib/src/parser/schema_analyzer.dart b/pkgs/json_syntax_generator/lib/src/parser/schema_analyzer.dart index 9df0eab7d..fe1f14e78 100644 --- a/pkgs/json_syntax_generator/lib/src/parser/schema_analyzer.dart +++ b/pkgs/json_syntax_generator/lib/src/parser/schema_analyzer.dart @@ -180,13 +180,18 @@ class SchemaAnalyzer { properties: properties, taggedUnionValue: taggedUnionValue, taggedUnionProperty: - schemas.generateSubClasses ? properties.single.name : null, + schemas.generateSubClasses ? schemas.generateSubClassesKey! : null, visibleTaggedUnion: visbleUnionTagValues.contains(typeName), extraValidation: extraValidation, ); _classes[typeName] = classInfo; if (schemas.generateSubClasses) { - _analyzeSubClasses(schemas, name: name, superclass: classInfo); + _analyzeSubClasses( + schemas, + schemas.generateSubClassesKey!, + name: name, + superclass: classInfo, + ); return; } } @@ -251,13 +256,13 @@ class SchemaAnalyzer { } void _analyzeSubClasses( - JsonSchemas schemas, { + JsonSchemas schemas, + String propertyKey, { String? name, NormalClassInfo? superclass, }) { final typeName = schemas.className; - final propertyKey = schemas.propertyKeys.single; final typeProperty = schemas.property(propertyKey); final subTypes = typeProperty.enumOrTaggedUnionValues; for (final subType in subTypes) { @@ -299,6 +304,8 @@ class SchemaAnalyzer { final type = schemas.type; final DartType dartType; switch (type) { + case null: + dartType = ObjectDartType(isNullable: !required); case SchemaType.boolean: dartType = BoolDartType(isNullable: !required); case SchemaType.integer: @@ -650,10 +657,21 @@ extension on JsonSchemas { (additionalPropertiesSchemas.isNotEmpty || additionalPropertiesBool == true); - bool get generateSubClasses => - type == SchemaType.object && - propertyKeys.length == 1 && - property(propertyKeys.single).anyOfs.isNotEmpty; + bool get generateSubClasses => generateSubClassesKey != null; + + 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) { + if (property(p).anyOfs.isNotEmpty) { + return p; + } + } + return null; + } bool get generateClass => type == SchemaType.object && !generateMapOf; diff --git a/pkgs/native_assets_cli/lib/src/config.dart b/pkgs/native_assets_cli/lib/src/config.dart index 7ff89a73a..d1e6e256d 100644 --- a/pkgs/native_assets_cli/lib/src/config.dart +++ b/pkgs/native_assets_cli/lib/src/config.dart @@ -183,6 +183,7 @@ final class BuildInputBuilder extends HookInputBuilder { dependencyMetadata: { for (final key in metadata.keys) key: metadata[key]!.toJson(), }, + assets: null, // TODO: Implement this. ); } diff --git a/pkgs/native_assets_cli/lib/src/hooks/syntax.g.dart b/pkgs/native_assets_cli/lib/src/hooks/syntax.g.dart index 92a209611..cb44527f2 100644 --- a/pkgs/native_assets_cli/lib/src/hooks/syntax.g.dart +++ b/pkgs/native_assets_cli/lib/src/hooks/syntax.g.dart @@ -11,7 +11,18 @@ import 'dart:io'; class Asset extends JsonObject { - Asset.fromJson(super.json, {super.path = const []}) : super.fromJson(); + factory Asset.fromJson( + Map json, { + List path = const [], + }) { + final result = Asset._fromJson(json, path: path); + if (result.isHooksMetadataAsset) { + return result.asHooksMetadataAsset; + } + return result; + } + + Asset._fromJson(super.json, {super.path = const []}) : super.fromJson(); Asset({required JsonObject? encoding, required String type}) : super() { _encoding = encoding; @@ -50,8 +61,25 @@ class Asset extends JsonObject { ...super.validate(), ..._validateEncoding(), ..._validateType(), + ..._validateExtraRules(), ]; + List _validateExtraRules() { + final result = []; + if (_reader.tryTraverse(['type']) == 'hooks/metadata') { + final objectErrors = _reader.validate?>('encoding'); + result.addAll(objectErrors); + if (objectErrors.isEmpty) { + final jsonValue = _reader.get?>('encoding'); + if (jsonValue != null) { + final reader = JsonReader(jsonValue, [...path, 'encoding']); + result.addAll(reader.validate('key')); + } + } + } + return result; + } + @override String toString() => 'Asset($json)'; } @@ -98,6 +126,7 @@ class BuildInput extends HookInput { BuildInput.fromJson(super.json, {super.path}) : super.fromJson(); BuildInput({ + required Map>? assets, required BuildConfig config, required Map>? dependencyMetadata, required super.outDir, @@ -107,17 +136,69 @@ class BuildInput extends HookInput { required super.packageRoot, required super.version, }) : super(config: config) { + _assets = assets; _dependencyMetadata = dependencyMetadata; json.sortOnKey(); } /// Setup all fields for [BuildInput] that are not in /// [HookInput]. - void setup({required Map>? dependencyMetadata}) { + void setup({ + required Map>? assets, + required Map>? dependencyMetadata, + }) { + _assets = assets; _dependencyMetadata = dependencyMetadata; json.sortOnKey(); } + Map>? get assets { + final jsonValue = _reader.optionalMap('assets'); + if (jsonValue == null) { + return null; + } + final result = >{}; + for (final MapEntry(:key, :value) in jsonValue.entries) { + result[key] = [ + for (final (index, item) in (value as List).indexed) + Asset.fromJson( + item as Map, + path: [...path, key, index], + ), + ]; + } + return result; + } + + set _assets(Map>? value) { + if (value == null) { + json.remove('assets'); + } else { + json['assets'] = { + for (final MapEntry(:key, :value) in value.entries) + key: [for (final item in value) item.json], + }; + } + } + + List _validateAssets() { + final mapErrors = _reader.validateOptionalMap('assets'); + if (mapErrors.isNotEmpty) { + return mapErrors; + } + final jsonValue = _reader.optionalMap('assets'); + if (jsonValue == null) { + return []; + } + final result = []; + for (final list in assets!.values) { + for (final element in list) { + result.addAll(element.validate()); + } + } + return result; + } + @override BuildConfig get config { final jsonValue = _reader.map$('config'); @@ -137,6 +218,7 @@ class BuildInput extends HookInput { @override List validate() => [ ...super.validate(), + ..._validateAssets(), ..._validateConfig(), ..._validateDependencyMetadata(), ]; @@ -150,6 +232,7 @@ class BuildOutput extends HookOutput { BuildOutput({ required super.assets, + required List? assetsForBuild, required Map>? assetsForLinking, required Map>? assetsForLinkingOld, required super.dependencies, @@ -158,6 +241,7 @@ class BuildOutput extends HookOutput { required super.version, }) : super() { this.assetsForLinkingOld = assetsForLinkingOld; + this.assetsForBuild = assetsForBuild; this.assetsForLinking = assetsForLinking; this.metadata = metadata; json.sortOnKey(); @@ -167,10 +251,12 @@ class BuildOutput extends HookOutput { /// [HookOutput]. void setup({ required Map>? assetsForLinkingOld, + required List? assetsForBuild, required Map>? assetsForLinking, required JsonObject? metadata, }) { this.assetsForLinkingOld = assetsForLinkingOld; + this.assetsForBuild = assetsForBuild; this.assetsForLinking = assetsForLinking; this.metadata = metadata; json.sortOnKey(); @@ -224,6 +310,41 @@ class BuildOutput extends HookOutput { return result; } + List? get assetsForBuild { + final jsonValue = _reader.optionalList('assets_for_build'); + if (jsonValue == null) return null; + return [ + for (final (index, element) in jsonValue.indexed) + Asset.fromJson( + element as Map, + path: [...path, 'assets_for_build', index], + ), + ]; + } + + set assetsForBuild(List? value) { + if (value == null) { + json.remove('assets_for_build'); + } else { + json['assets_for_build'] = [for (final item in value) item.json]; + } + json.sortOnKey(); + } + + List _validateAssetsForBuild() { + final listErrors = _reader.validateOptionalList>( + 'assets_for_build', + ); + if (listErrors.isNotEmpty) { + return listErrors; + } + final elements = assetsForBuild; + if (elements == null) { + return []; + } + return [for (final element in elements) ...element.validate()]; + } + Map>? get assetsForLinking { final jsonValue = _reader.optionalMap('assets_for_linking'); if (jsonValue == null) { @@ -295,6 +416,7 @@ class BuildOutput extends HookOutput { List validate() => [ ...super.validate(), ..._validateAssetsForLinkingOld(), + ..._validateAssetsForBuild(), ..._validateAssetsForLinking(), ..._validateMetadata(), ]; @@ -559,6 +681,41 @@ class HookOutput extends JsonObject { String toString() => 'HookOutput($json)'; } +class HooksMetadataAsset extends Asset { + static const typeValue = 'hooks/metadata'; + + HooksMetadataAsset.fromJson(super.json, {super.path}) : super._fromJson(); + + HooksMetadataAsset({required MetadataAssetEncoding encoding}) + : super(type: 'hooks/metadata', encoding: encoding); + + /// Setup all fields for [HooksMetadataAsset] that are not in + /// [Asset]. + void setup() {} + + @override + MetadataAssetEncoding get encoding { + final jsonValue = _reader.map$('encoding'); + return MetadataAssetEncoding.fromJson( + jsonValue, + path: [...path, 'encoding'], + ); + } + + @override + List validate() => [...super.validate(), ..._validateEncoding()]; + + @override + String toString() => 'HooksMetadataAsset($json)'; +} + +extension HooksMetadataAssetExtension on Asset { + bool get isHooksMetadataAsset => type == 'hooks/metadata'; + + HooksMetadataAsset get asHooksMetadataAsset => + HooksMetadataAsset.fromJson(json, path: path); +} + class LinkInput extends HookInput { LinkInput.fromJson(super.json, {super.path}) : super.fromJson(); @@ -660,6 +817,44 @@ class LinkOutput extends HookOutput { String toString() => 'LinkOutput($json)'; } +class MetadataAssetEncoding extends JsonObject { + MetadataAssetEncoding.fromJson(super.json, {super.path = const []}) + : super.fromJson(); + + MetadataAssetEncoding({required String key, required Object? value}) + : super() { + _key = key; + _value = value; + json.sortOnKey(); + } + + String get key => _reader.get('key'); + + set _key(String value) { + json.setOrRemove('key', value); + } + + List _validateKey() => _reader.validate('key'); + + Object? get value => _reader.get('value'); + + set _value(Object? value) { + json.setOrRemove('value', value); + } + + List _validateValue() => _reader.validate('value'); + + @override + List validate() => [ + ...super.validate(), + ..._validateKey(), + ..._validateValue(), + ]; + + @override + String toString() => 'MetadataAssetEncoding($json)'; +} + class JsonObject { final Map json;