From e22584dad88b50e4e119faf6fd197737a241f8b5 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sat, 3 Jun 2023 18:25:53 +0530 Subject: [PATCH 01/23] Add ffigen schema and refer them in example config yaml using modeline --- example/c_json/config.yaml | 2 + example/ffinative/config.yaml | 2 + example/libclang-example/config.yaml | 2 + example/objective_c/config.yaml | 2 + example/shared_bindings/ffigen_configs/a.yaml | 2 + .../ffigen_configs/a_shared_base.yaml | 2 + .../shared_bindings/ffigen_configs/base.yaml | 2 + example/simple/config.yaml | 2 + example/swift/config.yaml | 2 + ffigen.schema.json | 404 ++++++++++++++++++ tool/libclang_config.yaml | 2 + 11 files changed, 424 insertions(+) create mode 100644 ffigen.schema.json diff --git a/example/c_json/config.yaml b/example/c_json/config.yaml index 08c5891a..3d61cbd2 100644 --- a/example/c_json/config.yaml +++ b/example/c_json/config.yaml @@ -1,3 +1,5 @@ +# yaml-language-server: $schema=../../ffigen.schema.json + output: 'cjson_generated_bindings.dart' name: 'CJson' description: 'Holds bindings to cJSON.' diff --git a/example/ffinative/config.yaml b/example/ffinative/config.yaml index 18aeb3f6..449275f4 100644 --- a/example/ffinative/config.yaml +++ b/example/ffinative/config.yaml @@ -1,3 +1,5 @@ +# yaml-language-server: $schema=../../ffigen.schema.json + name: NativeLibrary ffi-native: # asset: 'assetname' # (optional) diff --git a/example/libclang-example/config.yaml b/example/libclang-example/config.yaml index f6517c08..69c111e7 100644 --- a/example/libclang-example/config.yaml +++ b/example/libclang-example/config.yaml @@ -1,3 +1,5 @@ +# yaml-language-server: $schema=../../ffigen.schema.json + output: 'generated_bindings.dart' # This will sort the bindings alphabetically. diff --git a/example/objective_c/config.yaml b/example/objective_c/config.yaml index 94764ca4..b44cc690 100644 --- a/example/objective_c/config.yaml +++ b/example/objective_c/config.yaml @@ -1,3 +1,5 @@ +# yaml-language-server: $schema=../../ffigen.schema.json + name: AVFAudio description: Bindings for AVFAudio. language: objc diff --git a/example/shared_bindings/ffigen_configs/a.yaml b/example/shared_bindings/ffigen_configs/a.yaml index 55a720e0..a23faa18 100644 --- a/example/shared_bindings/ffigen_configs/a.yaml +++ b/example/shared_bindings/ffigen_configs/a.yaml @@ -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. +# yaml-language-server: $schema=../../../ffigen.schema.json + name: NativeLibraryA description: Bindings to `headers/a.h`. output: '../lib/generated/a_gen.dart' diff --git a/example/shared_bindings/ffigen_configs/a_shared_base.yaml b/example/shared_bindings/ffigen_configs/a_shared_base.yaml index 0adcc204..aa4f1b10 100644 --- a/example/shared_bindings/ffigen_configs/a_shared_base.yaml +++ b/example/shared_bindings/ffigen_configs/a_shared_base.yaml @@ -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. +# yaml-language-server: $schema=../../../ffigen.schema.json + name: NativeLibraryASharedB description: Bindings to `headers/a.h` with shared definitions from `headers/base.h`. output: '../lib/generated/a_shared_b_gen.dart' diff --git a/example/shared_bindings/ffigen_configs/base.yaml b/example/shared_bindings/ffigen_configs/base.yaml index 474d0f9f..da03542d 100644 --- a/example/shared_bindings/ffigen_configs/base.yaml +++ b/example/shared_bindings/ffigen_configs/base.yaml @@ -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. +# yaml-language-server: $schema=../../../ffigen.schema.json + name: NativeLibraryBase description: Bindings to `headers/base.h`. output: diff --git a/example/simple/config.yaml b/example/simple/config.yaml index 82ed9251..f12c3493 100644 --- a/example/simple/config.yaml +++ b/example/simple/config.yaml @@ -1,3 +1,5 @@ +# yaml-language-server: $schema=../../ffigen.schema.json + name: NativeLibrary description: Bindings to `headers/example.h`. output: 'generated_bindings.dart' diff --git a/example/swift/config.yaml b/example/swift/config.yaml index e1a83225..6082e978 100644 --- a/example/swift/config.yaml +++ b/example/swift/config.yaml @@ -1,3 +1,5 @@ +# yaml-language-server: $schema=../../ffigen.schema.json + name: SwiftLibrary description: Bindings for swift_api. language: objc diff --git a/ffigen.schema.json b/ffigen.schema.json new file mode 100644 index 00000000..b1770474 --- /dev/null +++ b/ffigen.schema.json @@ -0,0 +1,404 @@ +{ + "$id": "https://json.schemastore.org/ffigen", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Configuration for generating dart ffi bindings via ffigen", + "type": "object", + "properties": { + "output": { + "oneOf": [ + { + "$ref": "#/$defs/outputBindings" + }, + { + "type": "object", + "properties": { + "bindings": { + "$ref": "#/$defs/outputBindings" + }, + "symbol-file": { + "$ref": "#/$defs/outputSymbolFile" + } + }, + "required": [ + "bindings" + ] + } + ] + }, + "llvm-path": { + "description": "Path to llvm folder or the libclang dynamic library.", + "type": "array", + "items": { + "type": "string" + } + }, + "headers": { + "description": "Input header files", + "type": "object", + "properties": { + "entry-points": { + "description": "Header entry-points to start parsing C files. Supports Glob syntax.", + "type": "array", + "items": { + "type": "string" + } + }, + "include-directives": { + "description": "Header include-directives from which declarations to generate. Supports Glob syntax.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "entry-points" + ] + }, + "name": { + "description": "Name of generated class.", + "type": "string" + }, + "description": { + "description": "Dart Doc for generated class.", + "type": "string" + }, + "compilerOpts": { + "description": "Pass compiler options to clang.", + "type": "array", + "items": { + "type": "string" + } + }, + "compilerOptsAutomatic": { + "description": "Tries to automatically find and add C standard library path to compiler-opts on macos", + "type": "object", + "properties": { + "macos": { + "type": "object", + "properties": { + "include-c-standard-library": { + "type": "boolean" + } + } + } + } + }, + "functions": { + "allOf": [ + { + "$ref": "#/$defs/includeExcludeRenameProperties" + } + ], + "type": "object", + "properties": { + "symbol-address": { + "$ref": "#/$defs/includeExcludeProperties" + }, + "expose-typedefs": { + "$ref": "#/$defs/includeExcludeProperties" + }, + "leaf": { + "$ref": "#/$defs/includeExcludeProperties" + } + } + }, + "typedefs": { + "$ref": "#/$defs/includeExcludeRenameProperties" + }, + "unnamed-enums": { + "$ref": "#/$defs/includeExcludeRenameProperties" + }, + "macros": { + "$ref": "#/$defs/includeExcludeRenameProperties" + }, + "globals": { + "allOf": [ + { + "$ref": "#/$defs/includeExcludeRenameProperties" + } + ], + "type": "object", + "properties": { + "symbol-address": { + "$ref": "#/$defs/includeExcludeProperties" + } + } + }, + "enums": { + "$ref": "#/$defs/includeExcludeRenameMemberProperties" + }, + "structs": { + "allOf": [ + { + "$ref": "#/$defs/compound" + } + ], + "type": "object", + "properties": { + "pack": { + "type": "object", + "patternProperties": { + ".*": { + "enum": [ + null, + 1, + 2, + 4, + 8, + 16 + ] + } + } + } + } + }, + "unions": { + "$ref": "#/$defs/compound" + }, + "comments": { + "description": "Extract documentation comments for declarations.", + "anyOf": [ + { + "type": "object", + "properties": { + "style": { + "enum": [ + "doxygen", + "any" + ] + }, + "length": { + "enum": [ + "brief", + "full" + ] + } + } + }, + { + "type": "boolean" + } + ] + }, + "sort": { + "description": "Sort the bindings according to name.", + "type": "boolean" + }, + "use-supported-typedefs": { + "description": "Should automatically map typedefs, E.g uint8_t => Uint8, int16_t => Int16, size_t => Size etc", + "type": "boolean" + }, + "use-dart-handle": { + "description": "Should map `Dart_Handle` to `Handle`.", + "type": "boolean" + }, + "exclude-all-by-default": { + "description": "When a declaration filter (eg `functions:` or `structs:`) is empty or unset, it defaults to including everything. If this flag is enabled, the default behavior is to exclude everything instead.", + "type": "boolean" + }, + "preamble": { + "description": "Raw header of the file, pasted as-it-is.", + "type": "string" + }, + "library-imports": { + "description": "Specify library imports for use in type-map.", + "type": "object" + }, + "type-map": { + "description": "Map types like integers, typedefs, structs, unions to any other type.", + "type": "object", + "properties": { + "native-types": { + "$ref": "#/$defs/mappedTypes" + }, + "typedefs": { + "$ref": "#/$defs/mappedTypes" + }, + "structs": { + "$ref": "#/$defs/mappedTypes" + }, + "unions": { + "$ref": "#/$defs/mappedTypes" + } + } + }, + "ffi-native": { + "properties": { + "assets": { + "asset": "string" + } + } + }, + "language": { + "enum": [ + "c", + "objc" + ] + }, + "import": { + "description": "Import symbols from a symbol file.", + "type": "object", + "properties": { + "symbol-files": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "objc-interfaces": { + "allOf": [ + { + "$ref": "#/$defs/includeExcludeRenameProperties" + } + ], + "type": "object", + "properties": { + "module": { + "description": "Adds a module prefix to the class name when loading the class from the dylib. This is only relevent for ObjC headers that are generated wrappers for a Swift library.", + "type": "object", + "patternProperties": { + ".*": { + "type": "string" + } + } + } + } + } + }, + "required": [ + "output", + "headers" + ], + "$defs": { + "outputBindings": { + "description": "Output path of the generated bindings.", + "type": "string" + }, + "outputSymbolFile": { + "description": "Generates a symbol file yaml containing all types defined in the generated output.", + "type": "object", + "properties": { + "output": { + "description": "Output path of the generated symbol file.", + "type": "string" + }, + "import-path": { + "description": "Import path for the dart bindings symbols.", + "type": "string" + } + } + }, + "includeExcludeProperties": { + "type": "object", + "properties": { + "include": { + "description": "Match declarations to include. Supports Regexps.", + "type": "array", + "items": { + "type": "string", + "format": "regex" + } + }, + "exclude": { + "description": "Match declarations to exclude (overrides include). Supports Regexps.", + "type": "array", + "items": { + "type": "string", + "format": "regex" + } + } + } + }, + "renameProperties": { + "type": "object", + "properties": { + "rename": { + "description": "Match and rename declarations. Supports Regexps group based replacement.", + "type": "object", + "patternProperties": { + ".+": { + "type": "string", + "format": "regex" + } + } + } + } + }, + "memberRenameProperties": { + "type": "object", + "properties": { + "member-rename": { + "description": "Match and rename declaration members. Supports Regexps group based replacement.", + "type": "object", + "patternProperties": { + ".+": { + "type": "string", + "format": "regex" + } + } + } + } + }, + "includeExcludeRenameProperties": { + "allOf": [ + { + "$ref": "#/$defs/includeExcludeProperties" + }, + { + "$ref": "#/$defs/renameProperties" + } + ] + }, + "includeExcludeRenameMemberProperties": { + "allOf": [ + { + "$ref": "#/$defs/includeExcludeProperties" + }, + { + "$ref": "#/$defs/renameProperties" + }, + { + "$ref": "#/$defs/memberRenameProperties" + } + ] + }, + "compound": { + "allOf": [ + { + "$ref": "#/$defs/includeExcludeRenameMemberProperties" + } + ], + "type": "object", + "properties": { + "dependency-only": { + "enum": [ + "full", + "opaque" + ] + } + } + }, + "mappedTypes": { + "type": "object", + "patternProperties": { + ".*": { + "type": "object", + "properties": { + "lib": { + "type": "string" + }, + "c-type": { + "type": "string" + }, + "dart-type": { + "type": "string" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tool/libclang_config.yaml b/tool/libclang_config.yaml index 6ac924f7..f0f9b3be 100644 --- a/tool/libclang_config.yaml +++ b/tool/libclang_config.yaml @@ -9,6 +9,8 @@ # dart run ffigen --config tool/libclang_config.yaml # =============================================================== +# yaml-language-server: $schema=../ffigen.schema.json + name: Clang description: Holds bindings to LibClang. output: '../lib/src/header_parser/clang_bindings/clang_bindings.dart' From 04c137b5065dd09a115569acf1ca18d938b5ad7d Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sat, 17 Jun 2023 15:34:43 +0530 Subject: [PATCH 02/23] Add basic Schema Design API --- lib/src/config_provider/schema.dart | 360 ++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 lib/src/config_provider/schema.dart diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart new file mode 100644 index 00000000..432231e5 --- /dev/null +++ b/lib/src/config_provider/schema.dart @@ -0,0 +1,360 @@ +import 'package:ffigen/src/config_provider/config_types.dart'; +import 'package:logging/logging.dart'; +import 'package:yaml/yaml.dart'; + +final _logger = Logger('ffigen.config_provider.config'); + +class SchemaNode { + final List path; + final E value; + + SchemaNode({required this.path, required this.value}); + SchemaNode withValue(T value) { + return SchemaNode(path: path, value: value); + } + + String get pathString => path.join(" -> "); + bool checkType({bool log = true}) { + if (value is! T) { + if (log) { + _logger.severe( + "Expected value of key '$pathString' to be of type '$T' (Got ${value.runtimeType})."); + } + return false; + } + return true; + } +} + +SchemaNode extractOrRaw( + dynamic Function(SchemaNode value)? extractor, SchemaNode rawValue) { + if (extractor != null) { + return rawValue.withValue(extractor.call(rawValue)); + } + return rawValue; +} + +class SchemaExtractionError extends Error { + SchemaNode? item; + String message; + SchemaExtractionError(this.item, [this.message = "Invalid Schema"]); + + @override + String toString() { + if (item != null) { + return "$runtimeType: $message @ ${item!.pathString}"; + } + return "$runtimeType: $message"; + } +} + +abstract class Schema { + dynamic Function(SchemaNode node)? extractor; + Schema({required this.extractor}); + + bool validateSchema(SchemaNode o, {bool log = true}); + + SchemaNode extract(SchemaNode o); +} + +class FixedMapSchema extends Schema> { + final Map keys; + final List requiredKeys; + + FixedMapSchema({ + required this.keys, + this.requiredKeys = const [], + super.extractor, + }) { + final unknownKeys = + requiredKeys.where((element) => !keys.containsKey(element)).toList(); + if (unknownKeys.isNotEmpty) { + throw ArgumentError( + "Invalid requiredKeys: $unknownKeys, requiredKeys must be a subset of keys"); + } + } + + @override + bool validateSchema(SchemaNode o, {bool log = true}) { + if (!o.checkType(log: log)) { + return false; + } + + var result = true; + final inputMap = (o.value as YamlMap).cast(); + + for (final MapEntry(key: key, value: value) in keys.entries) { + final path = [...o.path, key]; + if (!inputMap.containsKey(key)) { + if (log) { + _logger.severe("Unknown key - '${[...o.path, key].join(' -> ')}'."); + } + continue; + } + final schemaNode = SchemaNode(path: path, value: inputMap[key]); + if (!value.validateSchema(schemaNode, log: log)) { + result = false; + continue; + } + } + + for (final requiredKey in requiredKeys) { + if (!inputMap.containsKey(requiredKey)) { + _logger.severe( + "Key '${[...o.path, requiredKey].join(' -> ')}' is required."); + result = false; + } + } + + return result; + } + + @override + SchemaNode extract(SchemaNode o) { + if (!o.checkType(log: false)) { + throw SchemaExtractionError(o); + } + + final inputMap = (o.value as YamlMap).cast(); + final childExtracts = {}; + + for (final MapEntry(key: key, value: value) in keys.entries) { + final path = [...o.path, key]; + if (!inputMap.containsKey(key)) { + continue; + } + final schemaNode = SchemaNode(path: path, value: inputMap[key]); + if (!value.validateSchema(schemaNode, log: false)) { + throw SchemaExtractionError(schemaNode); + } + childExtracts[key] = value.extract(schemaNode).value as CE; + } + for (final requiredKey in requiredKeys) { + if (!inputMap.containsKey(requiredKey)) { + throw SchemaExtractionError( + null, "Invalid schema, missing required key - $requiredKey."); + } + } + + return extractOrRaw>(extractor, o.withValue(childExtracts)); + } +} + +class DynamicMapSchema extends Schema> { + final Schema valueSchema; + + DynamicMapSchema({ + required this.valueSchema, + super.extractor, + }); + + @override + bool validateSchema(SchemaNode o, {bool log = true}) { + if (!o.checkType(log: log)) { + return false; + } + + var result = true; + final inputMap = (o.value as YamlMap).cast(); + + for (final MapEntry(key: key, value: value) in inputMap.entries) { + final schemaNode = SchemaNode(path: [...o.path, key], value: value); + if (!valueSchema.validateSchema(schemaNode, log: log)) { + result = false; + continue; + } + } + + return result; + } + + @override + SchemaNode extract(SchemaNode o) { + if (!o.checkType(log: false)) { + throw SchemaExtractionError(o); + } + + final inputMap = (o.value as YamlMap).cast(); + final childExtracts = {}; + for (final MapEntry(key: key, value: value) in inputMap.entries) { + final schemaNode = SchemaNode(path: [...o.path, key], value: value); + if (!valueSchema.validateSchema(schemaNode, log: false)) { + throw SchemaExtractionError(schemaNode); + } + childExtracts[key] = valueSchema.extract(schemaNode) as CE; + } + + return extractOrRaw(extractor, o.withValue(childExtracts)); + } +} + +class ListSchema extends Schema> { + final Schema childSchema; + + ListSchema({ + required this.childSchema, + super.extractor, + }); + + @override + bool validateSchema(SchemaNode o, {bool log = true}) { + if (!o.checkType(log: log)) { + return false; + } + final inputList = (o.value as YamlList).cast(); + var result = true; + for (final (i, input) in inputList.indexed) { + final schemaNode = SchemaNode(path: [...o.path, "[$i]"], value: input); + if (!childSchema.validateSchema(schemaNode, log: log)) { + result = false; + continue; + } + } + + return result; + } + + @override + SchemaNode extract(SchemaNode o) { + if (!o.checkType(log: false)) { + throw SchemaExtractionError(o); + } + final inputList = (o.value as YamlList).cast(); + final childExtracts = []; + for (final (i, input) in inputList.indexed) { + final schemaNode = + SchemaNode(path: [...o.path, i.toString()], value: input); + if (!childSchema.validateSchema(schemaNode, log: false)) { + throw SchemaExtractionError(schemaNode); + } + childExtracts.add(childSchema.extract(schemaNode).value as CE); + } + return extractOrRaw(extractor, o.withValue(childExtracts)); + } +} + +class StringSchema extends Schema { + StringSchema({ + super.extractor, + }); + + @override + bool validateSchema(SchemaNode o, {bool log = true}) { + if (!o.checkType(log: log)) { + return false; + } + return true; + } + + @override + SchemaNode extract(SchemaNode o) { + if (!o.checkType(log: false)) { + throw SchemaExtractionError(o); + } + return extractOrRaw(extractor, o.withValue(o.value as String)); + } +} + +class BooleanSchema extends Schema { + BooleanSchema({ + super.extractor, + }); + + @override + bool validateSchema(SchemaNode o, {bool log = true}) { + if (!o.checkType(log: log)) { + return false; + } + return true; + } + + @override + SchemaNode extract(SchemaNode o) { + if (!o.checkType(log: false)) { + throw SchemaExtractionError(o); + } + return extractOrRaw(extractor, o.withValue(o.value as bool)); + } +} + +class OneOfSchema extends Schema { + final List children; + + OneOfSchema({ + required this.children, + super.extractor, + }); + + @override + bool validateSchema(SchemaNode o, {bool log = true}) { + for (final schema in children) { + if (schema.validateSchema(o, log: log)) { + return true; + } + } + return false; + } + + @override + SchemaNode extract(SchemaNode o) { + for (final schema in children) { + if (schema.validateSchema(o, log: false)) { + return extractOrRaw(extractor, o.withValue(schema.extract(o) as E)); + } + } + throw SchemaExtractionError(o); + } +} + +void main() { + final extractMap = {}; + final testSchema = FixedMapSchema( + keys: { + "name": StringSchema( + extractor: (node) => extractMap[node.pathString] = node.value, + ), + "description": StringSchema( + extractor: (node) => extractMap[node.pathString] = node.value, + ), + "output": OneOfSchema( + children: [ + StringSchema( + extractor: (node) => extractMap[node.pathString] = node.value, + ), + FixedMapSchema( + keys: { + "bindings": StringSchema(), + "symbol-file": FixedMapSchema(keys: { + "output": StringSchema(), + "import-path": StringSchema(), + }) + }, + requiredKeys: ["bindings"], + extractor: (node) => + OutputConfig(node.value["bindings"] as String, null), + ) + ], + ), + "headers": FixedMapSchema>( + keys: { + "entry-points": ListSchema(childSchema: StringSchema()), + "include-directives": ListSchema(childSchema: StringSchema()), + }, + extractor: (node) => extractMap[node.pathString] = node.value, + ), + }, + ); + _logger.onRecord.listen((event) => print(event)); + final yaml = loadYaml(""" +name: NativeLibrary +description: Bindings to `headers/example.h`. +output: 'generated_bindings.dart' +headers: + entry-points: + - 'headers/example.h' +"""); + + print(testSchema.validateSchema(SchemaNode(path: [], value: yaml))); + print(testSchema.extract(SchemaNode(path: [], value: yaml)).value); + print(extractMap); +} From a3d5af555d42c55419bcb54b6fe0b46064a94277 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sat, 17 Jun 2023 15:47:55 +0530 Subject: [PATCH 03/23] rename --- lib/src/config_provider/schema.dart | 91 ++++++++++++++++------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index 432231e5..ca973ca6 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -9,10 +9,18 @@ class SchemaNode { final E value; SchemaNode({required this.path, required this.value}); + SchemaNode withValue(T value) { return SchemaNode(path: path, value: value); } + SchemaNode extractOrRaw(dynamic Function(SchemaNode value)? extractor) { + if (extractor != null) { + return this.withValue(extractor.call(this)); + } + return this; + } + String get pathString => path.join(" -> "); bool checkType({bool log = true}) { if (value is! T) { @@ -26,14 +34,6 @@ class SchemaNode { } } -SchemaNode extractOrRaw( - dynamic Function(SchemaNode value)? extractor, SchemaNode rawValue) { - if (extractor != null) { - return rawValue.withValue(extractor.call(rawValue)); - } - return rawValue; -} - class SchemaExtractionError extends Error { SchemaNode? item; String message; @@ -52,9 +52,17 @@ abstract class Schema { dynamic Function(SchemaNode node)? extractor; Schema({required this.extractor}); - bool validateSchema(SchemaNode o, {bool log = true}); + bool validateNode(SchemaNode o, {bool log = true}); + + SchemaNode extractNode(SchemaNode o); + + bool validate(dynamic value) { + return validateNode(SchemaNode(path: [], value: value)); + } - SchemaNode extract(SchemaNode o); + SchemaNode extract(dynamic value) { + return extractNode(SchemaNode(path: [], value: value)); + } } class FixedMapSchema extends Schema> { @@ -75,7 +83,7 @@ class FixedMapSchema extends Schema> { } @override - bool validateSchema(SchemaNode o, {bool log = true}) { + bool validateNode(SchemaNode o, {bool log = true}) { if (!o.checkType(log: log)) { return false; } @@ -92,7 +100,7 @@ class FixedMapSchema extends Schema> { continue; } final schemaNode = SchemaNode(path: path, value: inputMap[key]); - if (!value.validateSchema(schemaNode, log: log)) { + if (!value.validateNode(schemaNode, log: log)) { result = false; continue; } @@ -110,7 +118,7 @@ class FixedMapSchema extends Schema> { } @override - SchemaNode extract(SchemaNode o) { + SchemaNode extractNode(SchemaNode o) { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } @@ -124,10 +132,10 @@ class FixedMapSchema extends Schema> { continue; } final schemaNode = SchemaNode(path: path, value: inputMap[key]); - if (!value.validateSchema(schemaNode, log: false)) { + if (!value.validateNode(schemaNode, log: false)) { throw SchemaExtractionError(schemaNode); } - childExtracts[key] = value.extract(schemaNode).value as CE; + childExtracts[key] = value.extractNode(schemaNode).value as CE; } for (final requiredKey in requiredKeys) { if (!inputMap.containsKey(requiredKey)) { @@ -135,8 +143,7 @@ class FixedMapSchema extends Schema> { null, "Invalid schema, missing required key - $requiredKey."); } } - - return extractOrRaw>(extractor, o.withValue(childExtracts)); + return o.withValue(childExtracts).extractOrRaw(extractor); } } @@ -149,7 +156,7 @@ class DynamicMapSchema extends Schema> { }); @override - bool validateSchema(SchemaNode o, {bool log = true}) { + bool validateNode(SchemaNode o, {bool log = true}) { if (!o.checkType(log: log)) { return false; } @@ -159,7 +166,7 @@ class DynamicMapSchema extends Schema> { for (final MapEntry(key: key, value: value) in inputMap.entries) { final schemaNode = SchemaNode(path: [...o.path, key], value: value); - if (!valueSchema.validateSchema(schemaNode, log: log)) { + if (!valueSchema.validateNode(schemaNode, log: log)) { result = false; continue; } @@ -169,7 +176,7 @@ class DynamicMapSchema extends Schema> { } @override - SchemaNode extract(SchemaNode o) { + SchemaNode extractNode(SchemaNode o) { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } @@ -178,13 +185,13 @@ class DynamicMapSchema extends Schema> { final childExtracts = {}; for (final MapEntry(key: key, value: value) in inputMap.entries) { final schemaNode = SchemaNode(path: [...o.path, key], value: value); - if (!valueSchema.validateSchema(schemaNode, log: false)) { + if (!valueSchema.validateNode(schemaNode, log: false)) { throw SchemaExtractionError(schemaNode); } - childExtracts[key] = valueSchema.extract(schemaNode) as CE; + childExtracts[key] = valueSchema.extractNode(schemaNode) as CE; } - return extractOrRaw(extractor, o.withValue(childExtracts)); + return o.withValue(childExtracts).extractOrRaw(extractor); } } @@ -197,7 +204,7 @@ class ListSchema extends Schema> { }); @override - bool validateSchema(SchemaNode o, {bool log = true}) { + bool validateNode(SchemaNode o, {bool log = true}) { if (!o.checkType(log: log)) { return false; } @@ -205,7 +212,7 @@ class ListSchema extends Schema> { var result = true; for (final (i, input) in inputList.indexed) { final schemaNode = SchemaNode(path: [...o.path, "[$i]"], value: input); - if (!childSchema.validateSchema(schemaNode, log: log)) { + if (!childSchema.validateNode(schemaNode, log: log)) { result = false; continue; } @@ -215,7 +222,7 @@ class ListSchema extends Schema> { } @override - SchemaNode extract(SchemaNode o) { + SchemaNode extractNode(SchemaNode o) { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } @@ -224,12 +231,12 @@ class ListSchema extends Schema> { for (final (i, input) in inputList.indexed) { final schemaNode = SchemaNode(path: [...o.path, i.toString()], value: input); - if (!childSchema.validateSchema(schemaNode, log: false)) { + if (!childSchema.validateNode(schemaNode, log: false)) { throw SchemaExtractionError(schemaNode); } - childExtracts.add(childSchema.extract(schemaNode).value as CE); + childExtracts.add(childSchema.extractNode(schemaNode).value as CE); } - return extractOrRaw(extractor, o.withValue(childExtracts)); + return o.withValue(childExtracts).extractOrRaw(extractor); } } @@ -239,7 +246,7 @@ class StringSchema extends Schema { }); @override - bool validateSchema(SchemaNode o, {bool log = true}) { + bool validateNode(SchemaNode o, {bool log = true}) { if (!o.checkType(log: log)) { return false; } @@ -247,11 +254,11 @@ class StringSchema extends Schema { } @override - SchemaNode extract(SchemaNode o) { + SchemaNode extractNode(SchemaNode o) { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return extractOrRaw(extractor, o.withValue(o.value as String)); + return o.withValue(o.value as String).extractOrRaw(extractor); } } @@ -261,7 +268,7 @@ class BooleanSchema extends Schema { }); @override - bool validateSchema(SchemaNode o, {bool log = true}) { + bool validateNode(SchemaNode o, {bool log = true}) { if (!o.checkType(log: log)) { return false; } @@ -269,11 +276,11 @@ class BooleanSchema extends Schema { } @override - SchemaNode extract(SchemaNode o) { + SchemaNode extractNode(SchemaNode o) { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return extractOrRaw(extractor, o.withValue(o.value as bool)); + return o.withValue(o.value as bool).extractOrRaw(extractor); } } @@ -286,9 +293,9 @@ class OneOfSchema extends Schema { }); @override - bool validateSchema(SchemaNode o, {bool log = true}) { + bool validateNode(SchemaNode o, {bool log = true}) { for (final schema in children) { - if (schema.validateSchema(o, log: log)) { + if (schema.validateNode(o, log: log)) { return true; } } @@ -296,10 +303,10 @@ class OneOfSchema extends Schema { } @override - SchemaNode extract(SchemaNode o) { + SchemaNode extractNode(SchemaNode o) { for (final schema in children) { - if (schema.validateSchema(o, log: false)) { - return extractOrRaw(extractor, o.withValue(schema.extract(o) as E)); + if (schema.validateNode(o, log: false)) { + return o.withValue(schema.extractNode(o) as E).extractOrRaw(extractor); } } throw SchemaExtractionError(o); @@ -354,7 +361,7 @@ headers: - 'headers/example.h' """); - print(testSchema.validateSchema(SchemaNode(path: [], value: yaml))); - print(testSchema.extract(SchemaNode(path: [], value: yaml)).value); + print(testSchema.validate(yaml)); + print(testSchema.extract(yaml).value); print(extractMap); } From 3828ef625191520c1ab446a140ec1be09c306698 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 01:26:35 +0530 Subject: [PATCH 04/23] Complete basic sample --- lib/src/config_provider/schema.dart | 99 +++++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 12 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index ca973ca6..451e446d 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:ffigen/src/config_provider/config_types.dart'; import 'package:logging/logging.dart'; import 'package:yaml/yaml.dart'; @@ -35,8 +37,8 @@ class SchemaNode { } class SchemaExtractionError extends Error { - SchemaNode? item; - String message; + final SchemaNode? item; + final String message; SchemaExtractionError(this.item, [this.message = "Invalid Schema"]); @override @@ -49,13 +51,24 @@ class SchemaExtractionError extends Error { } abstract class Schema { + String? defName; dynamic Function(SchemaNode node)? extractor; - Schema({required this.extractor}); + Schema({required this.extractor, this.defName}); bool validateNode(SchemaNode o, {bool log = true}); SchemaNode extractNode(SchemaNode o); + Map getRefOrSchema(Map defs) { + if (defName == null) { + return generateJsonSchema(defs); + } + defs.putIfAbsent(defName!, () => generateJsonSchema(defs)); + return {r"$ref": "#/\$defs/$defName"}; + } + + Map generateJsonSchema(Map defs); + bool validate(dynamic value) { return validateNode(SchemaNode(path: [], value: value)); } @@ -73,6 +86,7 @@ class FixedMapSchema extends Schema> { required this.keys, this.requiredKeys = const [], super.extractor, + super.defName, }) { final unknownKeys = requiredKeys.where((element) => !keys.containsKey(element)).toList(); @@ -145,6 +159,17 @@ class FixedMapSchema extends Schema> { } return o.withValue(childExtracts).extractOrRaw(extractor); } + + @override + Map generateJsonSchema(Map defs) { + return { + "type": "object", + if (keys.isNotEmpty) + "properties": + keys.map((key, value) => MapEntry(key, value.getRefOrSchema(defs))), + if (requiredKeys.isNotEmpty) "required": requiredKeys + }; + } } class DynamicMapSchema extends Schema> { @@ -153,6 +178,7 @@ class DynamicMapSchema extends Schema> { DynamicMapSchema({ required this.valueSchema, super.extractor, + super.defName, }); @override @@ -193,6 +219,14 @@ class DynamicMapSchema extends Schema> { return o.withValue(childExtracts).extractOrRaw(extractor); } + + @override + Map generateJsonSchema(Map defs) { + return { + "type": "object", + "patternProperties": {".*": valueSchema.getRefOrSchema(defs)} + }; + } } class ListSchema extends Schema> { @@ -201,6 +235,7 @@ class ListSchema extends Schema> { ListSchema({ required this.childSchema, super.extractor, + super.defName, }); @override @@ -238,11 +273,17 @@ class ListSchema extends Schema> { } return o.withValue(childExtracts).extractOrRaw(extractor); } + + @override + Map generateJsonSchema(Map defs) { + return {"type": "array", "items": childSchema.getRefOrSchema(defs)}; + } } class StringSchema extends Schema { StringSchema({ super.extractor, + super.defName, }); @override @@ -260,11 +301,17 @@ class StringSchema extends Schema { } return o.withValue(o.value as String).extractOrRaw(extractor); } + + @override + Map generateJsonSchema(Map defs) { + return {"type": "string"}; + } } class BooleanSchema extends Schema { BooleanSchema({ super.extractor, + super.defName, }); @override @@ -282,19 +329,25 @@ class BooleanSchema extends Schema { } return o.withValue(o.value as bool).extractOrRaw(extractor); } + + @override + Map generateJsonSchema(Map defs) { + return {"type": "boolean"}; + } } class OneOfSchema extends Schema { - final List children; + final List childSchemas; OneOfSchema({ - required this.children, + required this.childSchemas, super.extractor, + super.defName, }); @override bool validateNode(SchemaNode o, {bool log = true}) { - for (final schema in children) { + for (final schema in childSchemas) { if (schema.validateNode(o, log: log)) { return true; } @@ -304,13 +357,21 @@ class OneOfSchema extends Schema { @override SchemaNode extractNode(SchemaNode o) { - for (final schema in children) { + for (final schema in childSchemas) { if (schema.validateNode(o, log: false)) { return o.withValue(schema.extractNode(o) as E).extractOrRaw(extractor); } } throw SchemaExtractionError(o); } + + @override + Map generateJsonSchema(Map defs) { + return { + r"$oneOf": + childSchemas.map((child) => child.getRefOrSchema(defs)).toList() + }; + } } void main() { @@ -324,13 +385,16 @@ void main() { extractor: (node) => extractMap[node.pathString] = node.value, ), "output": OneOfSchema( - children: [ + childSchemas: [ StringSchema( + defName: "outputBindings", extractor: (node) => extractMap[node.pathString] = node.value, ), FixedMapSchema( keys: { - "bindings": StringSchema(), + "bindings": StringSchema( + defName: "outputBindings", + ), "symbol-file": FixedMapSchema(keys: { "output": StringSchema(), "import-path": StringSchema(), @@ -361,7 +425,18 @@ headers: - 'headers/example.h' """); - print(testSchema.validate(yaml)); - print(testSchema.extract(yaml).value); - print(extractMap); + print("validate: ${testSchema.validate(yaml)}"); + print("extract: ${testSchema.extract(yaml).value}"); + print("extractMap: $extractMap"); + final defs = {}; + final jsonSchema = testSchema.generateJsonSchema(defs); + print("jsonschema object: $jsonSchema"); + print("defs: $defs"); + final jsonSchemaJson = jsonEncode({ + r"$id": "test", + r"$schema": "https://json-schema.org/draft/2020-12/schema", + ...jsonSchema, + r"$defs": defs, + }); + print("jsonschema file: $jsonSchemaJson"); } From 0067874f2399980f65f21a6a9d14b579492d3cd0 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 02:24:50 +0530 Subject: [PATCH 05/23] Fix DynamicMapSceham , add IntegerSchema --- lib/src/config_provider/schema.dart | 116 ++++++++++++++++++++++------ 1 file changed, 93 insertions(+), 23 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index 451e446d..928f02c8 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -78,8 +78,8 @@ abstract class Schema { } } -class FixedMapSchema extends Schema> { - final Map keys; +class FixedMapSchema extends Schema> { + final Map keys; final List requiredKeys; FixedMapSchema({ @@ -103,10 +103,10 @@ class FixedMapSchema extends Schema> { } var result = true; - final inputMap = (o.value as YamlMap).cast(); + final inputMap = (o.value as YamlMap); for (final MapEntry(key: key, value: value) in keys.entries) { - final path = [...o.path, key]; + final path = [...o.path, key.toString()]; if (!inputMap.containsKey(key)) { if (log) { _logger.severe("Unknown key - '${[...o.path, key].join(' -> ')}'."); @@ -137,11 +137,11 @@ class FixedMapSchema extends Schema> { throw SchemaExtractionError(o); } - final inputMap = (o.value as YamlMap).cast(); - final childExtracts = {}; + final inputMap = (o.value as YamlMap); + final childExtracts = {}; for (final MapEntry(key: key, value: value) in keys.entries) { - final path = [...o.path, key]; + final path = [...o.path, key.toString()]; if (!inputMap.containsKey(key)) { continue; } @@ -165,18 +165,19 @@ class FixedMapSchema extends Schema> { return { "type": "object", if (keys.isNotEmpty) - "properties": - keys.map((key, value) => MapEntry(key, value.getRefOrSchema(defs))), - if (requiredKeys.isNotEmpty) "required": requiredKeys + "properties": { + for (final kv in keys.entries) kv.key: kv.value.getRefOrSchema(defs) + }, + if (requiredKeys.isNotEmpty) "required": requiredKeys, }; } } -class DynamicMapSchema extends Schema> { - final Schema valueSchema; +class DynamicMapSchema extends Schema> { + final List<({String keyRegexp, Schema valueSchema})> keyValueSchemas; DynamicMapSchema({ - required this.valueSchema, + required this.keyValueSchemas, super.extractor, super.defName, }); @@ -188,11 +189,21 @@ class DynamicMapSchema extends Schema> { } var result = true; - final inputMap = (o.value as YamlMap).cast(); + final inputMap = (o.value as YamlMap); for (final MapEntry(key: key, value: value) in inputMap.entries) { - final schemaNode = SchemaNode(path: [...o.path, key], value: value); - if (!valueSchema.validateNode(schemaNode, log: log)) { + final schemaNode = + SchemaNode(path: [...o.path, key.toString()], value: value); + var keyValueMatch = false; + for (final (keyRegexp: keyRegexp, valueSchema: valueSchema) + in keyValueSchemas) { + if (RegExp(keyRegexp).hasMatch(key.toString()) && + valueSchema.validateNode(schemaNode, log: log)) { + keyValueMatch = true; + break; + } + } + if (!keyValueMatch) { result = false; continue; } @@ -207,14 +218,24 @@ class DynamicMapSchema extends Schema> { throw SchemaExtractionError(o); } - final inputMap = (o.value as YamlMap).cast(); - final childExtracts = {}; + final inputMap = (o.value as YamlMap); + final childExtracts = {}; for (final MapEntry(key: key, value: value) in inputMap.entries) { - final schemaNode = SchemaNode(path: [...o.path, key], value: value); - if (!valueSchema.validateNode(schemaNode, log: false)) { + final schemaNode = + SchemaNode(path: [...o.path, key.toString()], value: value); + var keyValueMatch = false; + for (final (keyRegexp: keyRegexp, valueSchema: valueSchema) + in keyValueSchemas) { + if (RegExp(keyRegexp).hasMatch(key.toString()) && + valueSchema.validateNode(schemaNode, log: false)) { + childExtracts[key] = valueSchema.extractNode(schemaNode).value as CE; + keyValueMatch = true; + break; + } + } + if (!keyValueMatch) { throw SchemaExtractionError(schemaNode); } - childExtracts[key] = valueSchema.extractNode(schemaNode) as CE; } return o.withValue(childExtracts).extractOrRaw(extractor); @@ -224,7 +245,11 @@ class DynamicMapSchema extends Schema> { Map generateJsonSchema(Map defs) { return { "type": "object", - "patternProperties": {".*": valueSchema.getRefOrSchema(defs)} + "patternProperties": { + for (final (keyRegexp: keyRegexp, valueSchema: valueSchema) + in keyValueSchemas) + keyRegexp: valueSchema.getRefOrSchema(defs) + } }; } } @@ -308,6 +333,34 @@ class StringSchema extends Schema { } } +class IntegerSchema extends Schema { + IntegerSchema({ + super.extractor, + super.defName, + }); + + @override + bool validateNode(SchemaNode o, {bool log = true}) { + if (!o.checkType(log: log)) { + return false; + } + return true; + } + + @override + SchemaNode extractNode(SchemaNode o) { + if (!o.checkType(log: false)) { + throw SchemaExtractionError(o); + } + return o.withValue(o.value as int).extractOrRaw(extractor); + } + + @override + Map generateJsonSchema(Map defs) { + return {"type": "integer"}; + } +} + class BooleanSchema extends Schema { BooleanSchema({ super.extractor, @@ -359,7 +412,9 @@ class OneOfSchema extends Schema { SchemaNode extractNode(SchemaNode o) { for (final schema in childSchemas) { if (schema.validateNode(o, log: false)) { - return o.withValue(schema.extractNode(o) as E).extractOrRaw(extractor); + return o + .withValue(schema.extractNode(o).value as E) + .extractOrRaw(extractor); } } throw SchemaExtractionError(o); @@ -413,6 +468,17 @@ void main() { }, extractor: (node) => extractMap[node.pathString] = node.value, ), + "functions": FixedMapSchema(keys: { + "include": ListSchema(childSchema: StringSchema()), + "exclude": ListSchema(childSchema: StringSchema()), + "rename": DynamicMapSchema(keyValueSchemas: [ + ( + keyRegexp: r"^.*$", + valueSchema: + OneOfSchema(childSchemas: [StringSchema(), IntegerSchema()]), + ) + ]) + }), }, ); _logger.onRecord.listen((event) => print(event)); @@ -423,6 +489,10 @@ output: 'generated_bindings.dart' headers: entry-points: - 'headers/example.h' +functions: + rename: + a: b + 0: 1 """); print("validate: ${testSchema.validate(yaml)}"); From 915d56e8cee8b1bf8e9f13c46bbe496d8cd1896f Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 02:36:12 +0530 Subject: [PATCH 06/23] Add EnumSchema --- lib/src/config_provider/schema.dart | 47 +++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index 928f02c8..79d2a72f 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -361,6 +361,40 @@ class IntegerSchema extends Schema { } } +class EnumSchema extends Schema { + Set allowedValues; + EnumSchema({ + required this.allowedValues, + super.extractor, + super.defName, + }); + + @override + bool validateNode(SchemaNode o, {bool log = true}) { + if (!allowedValues.contains(o.value)) { + if (log) { + _logger.severe( + "'${o.pathString}' must be one of the following - $allowedValues (Got ${o.value})"); + } + return false; + } + return true; + } + + @override + SchemaNode extractNode(SchemaNode o) { + if (!allowedValues.contains(o.value)) { + throw SchemaExtractionError(o); + } + return o.withValue(o.value as CE).extractOrRaw(extractor); + } + + @override + Map generateJsonSchema(Map defs) { + return {"enum": allowedValues.toList()}; + } +} + class BooleanSchema extends Schema { BooleanSchema({ super.extractor, @@ -468,7 +502,7 @@ void main() { }, extractor: (node) => extractMap[node.pathString] = node.value, ), - "functions": FixedMapSchema(keys: { + "structs": FixedMapSchema(keys: { "include": ListSchema(childSchema: StringSchema()), "exclude": ListSchema(childSchema: StringSchema()), "rename": DynamicMapSchema(keyValueSchemas: [ @@ -477,6 +511,13 @@ void main() { valueSchema: OneOfSchema(childSchemas: [StringSchema(), IntegerSchema()]), ) + ]), + "pack": DynamicMapSchema(keyValueSchemas: [ + ( + keyRegexp: r"^.*$", + valueSchema: + EnumSchema(allowedValues: {null, 1, 2, 4, 8, 16}), + ) ]) }), }, @@ -489,10 +530,12 @@ output: 'generated_bindings.dart' headers: entry-points: - 'headers/example.h' -functions: +structs: rename: a: b 0: 1 + pack: + 'ABCD': 2 """); print("validate: ${testSchema.validate(yaml)}"); From a55b85902f47728a197f5c9996b91c9c761bc2a0 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 02:52:02 +0530 Subject: [PATCH 07/23] Handle severe logs for OneOfSchema --- lib/src/config_provider/schema.dart | 45 +++++++++++++++++++---------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index 79d2a72f..ad58eec8 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -105,12 +105,17 @@ class FixedMapSchema extends Schema> { var result = true; final inputMap = (o.value as YamlMap); + for (final requiredKey in requiredKeys) { + if (!inputMap.containsKey(requiredKey)) { + _logger.severe( + "Key '${[...o.path, requiredKey].join(' -> ')}' is required."); + result = false; + } + } + for (final MapEntry(key: key, value: value) in keys.entries) { final path = [...o.path, key.toString()]; if (!inputMap.containsKey(key)) { - if (log) { - _logger.severe("Unknown key - '${[...o.path, key].join(' -> ')}'."); - } continue; } final schemaNode = SchemaNode(path: path, value: inputMap[key]); @@ -120,11 +125,11 @@ class FixedMapSchema extends Schema> { } } - for (final requiredKey in requiredKeys) { - if (!inputMap.containsKey(requiredKey)) { - _logger.severe( - "Key '${[...o.path, requiredKey].join(' -> ')}' is required."); - result = false; + for (final key in inputMap.keys) { + if (!keys.containsKey(key)) { + if (log) { + _logger.severe("Unknown key - '${[...o.path, key].join(' -> ')}'."); + } } } @@ -140,6 +145,13 @@ class FixedMapSchema extends Schema> { final inputMap = (o.value as YamlMap); final childExtracts = {}; + for (final requiredKey in requiredKeys) { + if (!inputMap.containsKey(requiredKey)) { + throw SchemaExtractionError( + null, "Invalid schema, missing required key - $requiredKey."); + } + } + for (final MapEntry(key: key, value: value) in keys.entries) { final path = [...o.path, key.toString()]; if (!inputMap.containsKey(key)) { @@ -151,12 +163,6 @@ class FixedMapSchema extends Schema> { } childExtracts[key] = value.extractNode(schemaNode).value as CE; } - for (final requiredKey in requiredKeys) { - if (!inputMap.containsKey(requiredKey)) { - throw SchemaExtractionError( - null, "Invalid schema, missing required key - $requiredKey."); - } - } return o.withValue(childExtracts).extractOrRaw(extractor); } @@ -434,11 +440,20 @@ class OneOfSchema extends Schema { @override bool validateNode(SchemaNode o, {bool log = true}) { + // Running first time with no logs. for (final schema in childSchemas) { - if (schema.validateNode(o, log: log)) { + if (schema.validateNode(o, log: false)) { return true; } } + // No schema matched, running again to print logs this time. + if (log) { + for (final schema in childSchemas) { + if (schema.validateNode(o, log: log)) { + return true; + } + } + } return false; } From 1b086b0d50802fc2af2695c6faf36ebb2edd1bf1 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 12:19:50 +0530 Subject: [PATCH 08/23] Add comments & minor fixes --- lib/src/config_provider/schema.dart | 98 ++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 23 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index ad58eec8..34d5ea70 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -6,24 +6,43 @@ import 'package:yaml/yaml.dart'; final _logger = Logger('ffigen.config_provider.config'); +/// A Schema Node is a container for the [path] and the [value] of schema. +/// +/// During validation, [value] is always the raw underlying object. +/// During extraction. [value] can either be the raw underlying object or +/// the value retuned by the Schema extractor. +/// + +/// A container object for a Schema Object. class SchemaNode { + /// The path to this node. + /// + /// E.g - ["path", "to", "arr", "[1]", "item"] final List path; + + /// Get a string representation for path. + /// + /// E.g - "path -> to -> arr -> [1] -> item" + String get pathString => path.join(" -> "); + final E value; SchemaNode({required this.path, required this.value}); + /// Copy object with a different value. SchemaNode withValue(T value) { return SchemaNode(path: path, value: value); } - SchemaNode extractOrRaw(dynamic Function(SchemaNode value)? extractor) { + /// Transforms this SchemaNode with a nullable [extractor] or return itself. + SchemaNode extractOrThis(dynamic Function(SchemaNode value)? extractor) { if (extractor != null) { return this.withValue(extractor.call(this)); } return this; } - String get pathString => path.join(" -> "); + /// Returns true if [value] is of Type [T]. bool checkType({bool log = true}) { if (value is! T) { if (log) { @@ -50,6 +69,7 @@ class SchemaExtractionError extends Error { } } +/// Base class for all Schemas to extend. abstract class Schema { String? defName; dynamic Function(SchemaNode node)? extractor; @@ -69,15 +89,21 @@ abstract class Schema { Map generateJsonSchema(Map defs); + /// Run validation on an object [value]. bool validate(dynamic value) { return validateNode(SchemaNode(path: [], value: value)); } + /// Extract SchemaNode from [value]. This will call the [extractor] for all + /// underlying Schemas if valid. + /// Should ideally only be called if [validate] returns True. Throws + /// [SchemaExtractionError] if any validation fails. SchemaNode extract(dynamic value) { return extractNode(SchemaNode(path: [], value: value)); } } +/// Schema for a Map which has a fixed set of known keys. class FixedMapSchema extends Schema> { final Map keys; final List requiredKeys; @@ -163,7 +189,7 @@ class FixedMapSchema extends Schema> { } childExtracts[key] = value.extractNode(schemaNode).value as CE; } - return o.withValue(childExtracts).extractOrRaw(extractor); + return o.withValue(childExtracts).extractOrThis(extractor); } @override @@ -179,7 +205,9 @@ class FixedMapSchema extends Schema> { } } +/// Schema for a Map that can have any number of keys. class DynamicMapSchema extends Schema> { + /// [keyRegexp] will convert it's input to a String before matching. final List<({String keyRegexp, Schema valueSchema})> keyValueSchemas; DynamicMapSchema({ @@ -201,17 +229,34 @@ class DynamicMapSchema extends Schema> { final schemaNode = SchemaNode(path: [...o.path, key.toString()], value: value); var keyValueMatch = false; + + /// Running first time with no logs. for (final (keyRegexp: keyRegexp, valueSchema: valueSchema) in keyValueSchemas) { - if (RegExp(keyRegexp).hasMatch(key.toString()) && - valueSchema.validateNode(schemaNode, log: log)) { + if (RegExp(keyRegexp, dotAll: true).hasMatch(key.toString()) && + valueSchema.validateNode(schemaNode, log: false)) { keyValueMatch = true; break; } } if (!keyValueMatch) { result = false; - continue; + // No schema matched, running again to print logs this time. + if (log) { + _logger.severe( + "'${schemaNode.pathString}' must match atleast one of the allowed key regex and schema."); + for (final (keyRegexp: keyRegexp, valueSchema: valueSchema) + in keyValueSchemas) { + if (!RegExp(keyRegexp, dotAll: true).hasMatch(key.toString())) { + _logger.severe( + "'${schemaNode.pathString}' does not match regex - '$keyRegexp' (Input - $key)"); + continue; + } + if (valueSchema.validateNode(schemaNode, log: log)) { + continue; + } + } + } } } @@ -232,7 +277,7 @@ class DynamicMapSchema extends Schema> { var keyValueMatch = false; for (final (keyRegexp: keyRegexp, valueSchema: valueSchema) in keyValueSchemas) { - if (RegExp(keyRegexp).hasMatch(key.toString()) && + if (RegExp(keyRegexp, dotAll: true).hasMatch(key.toString()) && valueSchema.validateNode(schemaNode, log: false)) { childExtracts[key] = valueSchema.extractNode(schemaNode).value as CE; keyValueMatch = true; @@ -244,7 +289,7 @@ class DynamicMapSchema extends Schema> { } } - return o.withValue(childExtracts).extractOrRaw(extractor); + return o.withValue(childExtracts).extractOrThis(extractor); } @override @@ -260,6 +305,7 @@ class DynamicMapSchema extends Schema> { } } +/// Schema for a List. class ListSchema extends Schema> { final Schema childSchema; @@ -302,7 +348,7 @@ class ListSchema extends Schema> { } childExtracts.add(childSchema.extractNode(schemaNode).value as CE); } - return o.withValue(childExtracts).extractOrRaw(extractor); + return o.withValue(childExtracts).extractOrThis(extractor); } @override @@ -311,6 +357,7 @@ class ListSchema extends Schema> { } } +/// Schema for a String. class StringSchema extends Schema { StringSchema({ super.extractor, @@ -330,7 +377,7 @@ class StringSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as String).extractOrRaw(extractor); + return o.withValue(o.value as String).extractOrThis(extractor); } @override @@ -339,8 +386,9 @@ class StringSchema extends Schema { } } -class IntegerSchema extends Schema { - IntegerSchema({ +/// Schema for an Int. +class IntSchema extends Schema { + IntSchema({ super.extractor, super.defName, }); @@ -358,7 +406,7 @@ class IntegerSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as int).extractOrRaw(extractor); + return o.withValue(o.value as int).extractOrThis(extractor); } @override @@ -367,6 +415,7 @@ class IntegerSchema extends Schema { } } +/// Schema for an object where only specific values are allowed. class EnumSchema extends Schema { Set allowedValues; EnumSchema({ @@ -392,7 +441,7 @@ class EnumSchema extends Schema { if (!allowedValues.contains(o.value)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as CE).extractOrRaw(extractor); + return o.withValue(o.value as CE).extractOrThis(extractor); } @override @@ -401,8 +450,9 @@ class EnumSchema extends Schema { } } -class BooleanSchema extends Schema { - BooleanSchema({ +/// Schema for a bool. +class BoolSchema extends Schema { + BoolSchema({ super.extractor, super.defName, }); @@ -420,7 +470,7 @@ class BooleanSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as bool).extractOrRaw(extractor); + return o.withValue(o.value as bool).extractOrThis(extractor); } @override @@ -429,6 +479,7 @@ class BooleanSchema extends Schema { } } +/// Schema which checks if atleast one of the underlying Schema matches. class OneOfSchema extends Schema { final List childSchemas; @@ -448,6 +499,8 @@ class OneOfSchema extends Schema { } // No schema matched, running again to print logs this time. if (log) { + _logger.severe( + "'${o.pathString}' must match atleast one of the allowed schema -"); for (final schema in childSchemas) { if (schema.validateNode(o, log: log)) { return true; @@ -463,7 +516,7 @@ class OneOfSchema extends Schema { if (schema.validateNode(o, log: false)) { return o .withValue(schema.extractNode(o).value as E) - .extractOrRaw(extractor); + .extractOrThis(extractor); } } throw SchemaExtractionError(o); @@ -522,14 +575,14 @@ void main() { "exclude": ListSchema(childSchema: StringSchema()), "rename": DynamicMapSchema(keyValueSchemas: [ ( - keyRegexp: r"^.*$", + keyRegexp: r"^.+$", valueSchema: - OneOfSchema(childSchemas: [StringSchema(), IntegerSchema()]), + OneOfSchema(childSchemas: [StringSchema(), IntSchema()]), ) ]), "pack": DynamicMapSchema(keyValueSchemas: [ ( - keyRegexp: r"^.*$", + keyRegexp: r"^.+$", valueSchema: EnumSchema(allowedValues: {null, 1, 2, 4, 8, 16}), ) @@ -548,9 +601,8 @@ headers: structs: rename: a: b - 0: 1 pack: - 'ABCD': 2 + a: 2 """); print("validate: ${testSchema.validate(yaml)}"); From 9b11a0b5fab5bafa6f55e56ca39eb1362ab5c307 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 14:44:37 +0530 Subject: [PATCH 09/23] Add default value handling --- lib/src/config_provider/schema.dart | 224 +++++++++++++++++++++------- 1 file changed, 169 insertions(+), 55 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index 34d5ea70..001cb87a 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -34,12 +34,19 @@ class SchemaNode { return SchemaNode(path: path, value: value); } - /// Transforms this SchemaNode with a nullable [extractor] or return itself. - SchemaNode extractOrThis(dynamic Function(SchemaNode value)? extractor) { + /// Transforms this SchemaNode with a nullable [extractor] or return itself + /// and calls the [result] callback + SchemaNode extractOrThis( + dynamic Function(SchemaNode value)? extractor, + void Function(SchemaNode node)? result, + ) { + SchemaNode returnValue; if (extractor != null) { - return this.withValue(extractor.call(this)); + returnValue = this.withValue(extractor.call(this)); } - return this; + returnValue = this; + result?.call(returnValue); + return returnValue; } /// Returns true if [value] is of Type [T]. @@ -71,30 +78,58 @@ class SchemaExtractionError extends Error { /// Base class for all Schemas to extend. abstract class Schema { - String? defName; - dynamic Function(SchemaNode node)? extractor; - Schema({required this.extractor, this.defName}); + /// Used to generate and refer the reference definition generated in json + /// schema. Must be unique for a nested Schema. + String? schemaDefName; + + /// Used to generate the description field in json schema. + String? schemaDescription; + + /// Used to transform the payload to another type before passing to parent + /// nodes and [result]. + dynamic Function(SchemaNode node)? transform; + + /// Passed to parent nodes and result (only if required by parent) + E? Function(SchemaNode node)? defaultValue; + + void Function(SchemaNode node)? result; + Schema({ + /// Used + this.schemaDefName, + this.schemaDescription, + this.transform, + this.defaultValue, + this.result, + }); bool validateNode(SchemaNode o, {bool log = true}); SchemaNode extractNode(SchemaNode o); + Map generateJsonSchema(Map defs); + + /// Returns default value or null for a node. Calls [result] if value is + /// not null. + E? getDefaultValue(SchemaNode o) { + final v = defaultValue?.call(o); + if (v != null) result?.call(o.withValue(v)); + return v; + } + Map getRefOrSchema(Map defs) { - if (defName == null) { + if (schemaDefName == null) { return generateJsonSchema(defs); } - defs.putIfAbsent(defName!, () => generateJsonSchema(defs)); - return {r"$ref": "#/\$defs/$defName"}; + defs.putIfAbsent(schemaDefName!, () => generateJsonSchema(defs)); + return {r"$ref": "#/\$defs/$schemaDefName"}; } - Map generateJsonSchema(Map defs); - /// Run validation on an object [value]. bool validate(dynamic value) { return validateNode(SchemaNode(path: [], value: value)); } - /// Extract SchemaNode from [value]. This will call the [extractor] for all + /// Extract SchemaNode from [value]. This will call the [transform] for all /// underlying Schemas if valid. /// Should ideally only be called if [validate] returns True. Throws /// [SchemaExtractionError] if any validation fails. @@ -111,8 +146,11 @@ class FixedMapSchema extends Schema> { FixedMapSchema({ required this.keys, this.requiredKeys = const [], - super.extractor, - super.defName, + super.schemaDefName, + super.schemaDescription, + super.transform, + super.defaultValue, + super.result, }) { final unknownKeys = requiredKeys.where((element) => !keys.containsKey(element)).toList(); @@ -120,6 +158,20 @@ class FixedMapSchema extends Schema> { throw ArgumentError( "Invalid requiredKeys: $unknownKeys, requiredKeys must be a subset of keys"); } + + // Get default values of underlying keys if [defaultValue] is not specified + // for this. + super.defaultValue ??= (SchemaNode o) { + final result = {}; + for (final MapEntry(key: key, value: value) in keys.entries) { + final defaultValue = value.getDefaultValue( + SchemaNode(path: [...o.path, key.toString()], value: value)); + if (defaultValue != null) { + result[key] = defaultValue as CE; + } + } + return result.isEmpty ? null : result; + }; } @override @@ -181,6 +233,12 @@ class FixedMapSchema extends Schema> { for (final MapEntry(key: key, value: value) in keys.entries) { final path = [...o.path, key.toString()]; if (!inputMap.containsKey(key)) { + // No value specified, fill in with default value instead. + final defaultValue = + value.getDefaultValue(SchemaNode(path: path, value: null)); + if (defaultValue != null) { + childExtracts[key] = defaultValue as CE; + } continue; } final schemaNode = SchemaNode(path: path, value: inputMap[key]); @@ -189,13 +247,14 @@ class FixedMapSchema extends Schema> { } childExtracts[key] = value.extractNode(schemaNode).value as CE; } - return o.withValue(childExtracts).extractOrThis(extractor); + return o.withValue(childExtracts).extractOrThis(transform, result); } @override Map generateJsonSchema(Map defs) { return { "type": "object", + if (schemaDescription != null) "description": schemaDescription!, if (keys.isNotEmpty) "properties": { for (final kv in keys.entries) kv.key: kv.value.getRefOrSchema(defs) @@ -212,8 +271,11 @@ class DynamicMapSchema extends Schema> { DynamicMapSchema({ required this.keyValueSchemas, - super.extractor, - super.defName, + super.schemaDefName, + super.schemaDescription, + super.transform, + super.defaultValue, + super.result, }); @override @@ -289,18 +351,20 @@ class DynamicMapSchema extends Schema> { } } - return o.withValue(childExtracts).extractOrThis(extractor); + return o.withValue(childExtracts).extractOrThis(transform, result); } @override Map generateJsonSchema(Map defs) { return { "type": "object", - "patternProperties": { - for (final (keyRegexp: keyRegexp, valueSchema: valueSchema) - in keyValueSchemas) - keyRegexp: valueSchema.getRefOrSchema(defs) - } + if (schemaDescription != null) "description": schemaDescription!, + if (keyValueSchemas.isNotEmpty) + "patternProperties": { + for (final (keyRegexp: keyRegexp, valueSchema: valueSchema) + in keyValueSchemas) + keyRegexp: valueSchema.getRefOrSchema(defs) + } }; } } @@ -311,8 +375,11 @@ class ListSchema extends Schema> { ListSchema({ required this.childSchema, - super.extractor, - super.defName, + super.schemaDefName, + super.schemaDescription, + super.transform, + super.defaultValue, + super.result, }); @override @@ -348,20 +415,27 @@ class ListSchema extends Schema> { } childExtracts.add(childSchema.extractNode(schemaNode).value as CE); } - return o.withValue(childExtracts).extractOrThis(extractor); + return o.withValue(childExtracts).extractOrThis(transform, result); } @override Map generateJsonSchema(Map defs) { - return {"type": "array", "items": childSchema.getRefOrSchema(defs)}; + return { + "type": "array", + if (schemaDescription != null) "description": schemaDescription!, + "items": childSchema.getRefOrSchema(defs), + }; } } /// Schema for a String. class StringSchema extends Schema { StringSchema({ - super.extractor, - super.defName, + super.schemaDefName, + super.schemaDescription, + super.transform, + super.defaultValue, + super.result, }); @override @@ -377,20 +451,26 @@ class StringSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as String).extractOrThis(extractor); + return o.withValue(o.value as String).extractOrThis(transform, result); } @override Map generateJsonSchema(Map defs) { - return {"type": "string"}; + return { + "type": "string", + if (schemaDescription != null) "description": schemaDescription!, + }; } } /// Schema for an Int. class IntSchema extends Schema { IntSchema({ - super.extractor, - super.defName, + super.schemaDefName, + super.schemaDescription, + super.transform, + super.defaultValue, + super.result, }); @override @@ -406,12 +486,15 @@ class IntSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as int).extractOrThis(extractor); + return o.withValue(o.value as int).extractOrThis(transform, result); } @override Map generateJsonSchema(Map defs) { - return {"type": "integer"}; + return { + "type": "integer", + if (schemaDescription != null) "description": schemaDescription!, + }; } } @@ -420,8 +503,11 @@ class EnumSchema extends Schema { Set allowedValues; EnumSchema({ required this.allowedValues, - super.extractor, - super.defName, + super.schemaDefName, + super.schemaDescription, + super.transform, + super.defaultValue, + super.result, }); @override @@ -441,20 +527,26 @@ class EnumSchema extends Schema { if (!allowedValues.contains(o.value)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as CE).extractOrThis(extractor); + return o.withValue(o.value as CE).extractOrThis(transform, result); } @override Map generateJsonSchema(Map defs) { - return {"enum": allowedValues.toList()}; + return { + "enum": allowedValues.toList(), + if (schemaDescription != null) "description": schemaDescription!, + }; } } /// Schema for a bool. class BoolSchema extends Schema { BoolSchema({ - super.extractor, - super.defName, + super.schemaDefName, + super.schemaDescription, + super.transform, + super.defaultValue, + super.result, }); @override @@ -470,12 +562,15 @@ class BoolSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as bool).extractOrThis(extractor); + return o.withValue(o.value as bool).extractOrThis(transform, result); } @override Map generateJsonSchema(Map defs) { - return {"type": "boolean"}; + return { + "type": "boolean", + if (schemaDescription != null) "description": schemaDescription!, + }; } } @@ -485,8 +580,11 @@ class OneOfSchema extends Schema { OneOfSchema({ required this.childSchemas, - super.extractor, - super.defName, + super.schemaDefName, + super.schemaDescription, + super.transform, + super.defaultValue, + super.result, }); @override @@ -516,7 +614,7 @@ class OneOfSchema extends Schema { if (schema.validateNode(o, log: false)) { return o .withValue(schema.extractNode(o).value as E) - .extractOrThis(extractor); + .extractOrThis(transform, result); } } throw SchemaExtractionError(o); @@ -525,8 +623,9 @@ class OneOfSchema extends Schema { @override Map generateJsonSchema(Map defs) { return { + if (schemaDescription != null) "description": schemaDescription!, r"$oneOf": - childSchemas.map((child) => child.getRefOrSchema(defs)).toList() + childSchemas.map((child) => child.getRefOrSchema(defs)).toList(), }; } } @@ -536,21 +635,21 @@ void main() { final testSchema = FixedMapSchema( keys: { "name": StringSchema( - extractor: (node) => extractMap[node.pathString] = node.value, + result: (node) => extractMap[node.pathString] = node.value, ), "description": StringSchema( - extractor: (node) => extractMap[node.pathString] = node.value, + result: (node) => extractMap[node.pathString] = node.value, ), "output": OneOfSchema( childSchemas: [ StringSchema( - defName: "outputBindings", - extractor: (node) => extractMap[node.pathString] = node.value, + schemaDefName: "outputBindings", + transform: (node) => extractMap[node.pathString] = node.value, ), FixedMapSchema( keys: { "bindings": StringSchema( - defName: "outputBindings", + schemaDefName: "outputBindings", ), "symbol-file": FixedMapSchema(keys: { "output": StringSchema(), @@ -558,8 +657,9 @@ void main() { }) }, requiredKeys: ["bindings"], - extractor: (node) => + transform: (node) => OutputConfig(node.value["bindings"] as String, null), + result: (node) => extractMap[node.pathString] = node.value, ) ], ), @@ -568,7 +668,7 @@ void main() { "entry-points": ListSchema(childSchema: StringSchema()), "include-directives": ListSchema(childSchema: StringSchema()), }, - extractor: (node) => extractMap[node.pathString] = node.value, + result: (node) => extractMap[node.pathString] = node.value, ), "structs": FixedMapSchema(keys: { "include": ListSchema(childSchema: StringSchema()), @@ -588,6 +688,20 @@ void main() { ) ]) }), + "comments": FixedMapSchema( + keys: { + "style": EnumSchema( + allowedValues: {"any", "doxygen"}, + defaultValue: (node) => "doxygen", + ), + "length": EnumSchema( + allowedValues: {"brief", "full"}, + defaultValue: (node) => "brief", + result: (node) => extractMap[node.pathString] = node.value, + ), + }, + result: (node) => extractMap[node.pathString] = node.value, + ), }, ); _logger.onRecord.listen((event) => print(event)); From 5b20b9f685e40e01bf305309989a49ea2bc486be Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 14:52:44 +0530 Subject: [PATCH 10/23] Add more comments, minor changes --- lib/src/config_provider/schema.dart | 47 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index 001cb87a..5a9bf4e4 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -6,13 +6,6 @@ import 'package:yaml/yaml.dart'; final _logger = Logger('ffigen.config_provider.config'); -/// A Schema Node is a container for the [path] and the [value] of schema. -/// -/// During validation, [value] is always the raw underlying object. -/// During extraction. [value] can either be the raw underlying object or -/// the value retuned by the Schema extractor. -/// - /// A container object for a Schema Object. class SchemaNode { /// The path to this node. @@ -34,18 +27,18 @@ class SchemaNode { return SchemaNode(path: path, value: value); } - /// Transforms this SchemaNode with a nullable [extractor] or return itself + /// Transforms this SchemaNode with a nullable [transform] or return itself /// and calls the [result] callback - SchemaNode extractOrThis( - dynamic Function(SchemaNode value)? extractor, - void Function(SchemaNode node)? result, + SchemaNode transformOrThis( + dynamic Function(SchemaNode value)? transform, + void Function(SchemaNode node)? resultCallback, ) { SchemaNode returnValue; - if (extractor != null) { - returnValue = this.withValue(extractor.call(this)); + if (transform != null) { + returnValue = this.withValue(transform.call(this)); } returnValue = this; - result?.call(returnValue); + resultCallback?.call(returnValue); return returnValue; } @@ -90,9 +83,13 @@ abstract class Schema { dynamic Function(SchemaNode node)? transform; /// Passed to parent nodes and result (only if required by parent) - E? Function(SchemaNode node)? defaultValue; + /// + /// SchemaNode is used since value should not be accessed here. + E? Function(SchemaNode node)? defaultValue; - void Function(SchemaNode node)? result; + /// Called when final result is prepared via [extractNode] or + /// [getDefaultValue]. + void Function(SchemaNode node)? result; Schema({ /// Used this.schemaDefName, @@ -111,7 +108,7 @@ abstract class Schema { /// Returns default value or null for a node. Calls [result] if value is /// not null. E? getDefaultValue(SchemaNode o) { - final v = defaultValue?.call(o); + final v = defaultValue?.call(o.withValue(null)); if (v != null) result?.call(o.withValue(v)); return v; } @@ -247,7 +244,7 @@ class FixedMapSchema extends Schema> { } childExtracts[key] = value.extractNode(schemaNode).value as CE; } - return o.withValue(childExtracts).extractOrThis(transform, result); + return o.withValue(childExtracts).transformOrThis(transform, result); } @override @@ -351,7 +348,7 @@ class DynamicMapSchema extends Schema> { } } - return o.withValue(childExtracts).extractOrThis(transform, result); + return o.withValue(childExtracts).transformOrThis(transform, result); } @override @@ -415,7 +412,7 @@ class ListSchema extends Schema> { } childExtracts.add(childSchema.extractNode(schemaNode).value as CE); } - return o.withValue(childExtracts).extractOrThis(transform, result); + return o.withValue(childExtracts).transformOrThis(transform, result); } @override @@ -451,7 +448,7 @@ class StringSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as String).extractOrThis(transform, result); + return o.withValue(o.value as String).transformOrThis(transform, result); } @override @@ -486,7 +483,7 @@ class IntSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as int).extractOrThis(transform, result); + return o.withValue(o.value as int).transformOrThis(transform, result); } @override @@ -527,7 +524,7 @@ class EnumSchema extends Schema { if (!allowedValues.contains(o.value)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as CE).extractOrThis(transform, result); + return o.withValue(o.value as CE).transformOrThis(transform, result); } @override @@ -562,7 +559,7 @@ class BoolSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as bool).extractOrThis(transform, result); + return o.withValue(o.value as bool).transformOrThis(transform, result); } @override @@ -614,7 +611,7 @@ class OneOfSchema extends Schema { if (schema.validateNode(o, log: false)) { return o .withValue(schema.extractNode(o).value as E) - .extractOrThis(transform, result); + .transformOrThis(transform, result); } } throw SchemaExtractionError(o); From b8198ce447077ff91da955c17a4276fd9beff7f0 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 15:55:51 +0530 Subject: [PATCH 11/23] nit --- lib/src/config_provider/schema.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index 5a9bf4e4..0bef84c6 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -85,7 +85,7 @@ abstract class Schema { /// Passed to parent nodes and result (only if required by parent) /// /// SchemaNode is used since value should not be accessed here. - E? Function(SchemaNode node)? defaultValue; + dynamic Function(SchemaNode node)? defaultValue; /// Called when final result is prepared via [extractNode] or /// [getDefaultValue]. @@ -107,7 +107,7 @@ abstract class Schema { /// Returns default value or null for a node. Calls [result] if value is /// not null. - E? getDefaultValue(SchemaNode o) { + dynamic getDefaultValue(SchemaNode o) { final v = defaultValue?.call(o.withValue(null)); if (v != null) result?.call(o.withValue(v)); return v; From 8fac11b5a5c9c203d1ea0f21969323a9a3961e5b Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 16:03:00 +0530 Subject: [PATCH 12/23] Add rawValue to SchemaNode --- lib/src/config_provider/schema.dart | 209 +++++++++++++++++----------- 1 file changed, 124 insertions(+), 85 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index 0bef84c6..a86b1927 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -18,13 +18,29 @@ class SchemaNode { /// E.g - "path -> to -> arr -> [1] -> item" String get pathString => path.join(" -> "); + /// Contains the underlying node value after all transformations and + /// default values have been applied. final E value; - SchemaNode({required this.path, required this.value}); + /// Contains the raw underlying node value. Would be null for fields populated + /// but default values + final dynamic rawValue; + + SchemaNode({ + required this.path, + required this.value, + dynamic rawValue, + bool nullRawValue = false, + }) : rawValue = nullRawValue ? null : (rawValue ?? value); /// Copy object with a different value. - SchemaNode withValue(T value) { - return SchemaNode(path: path, value: value); + SchemaNode withValue(T value, dynamic rawValue) { + return SchemaNode( + path: path, + value: value, + rawValue: rawValue, + nullRawValue: rawValue == null, + ); } /// Transforms this SchemaNode with a nullable [transform] or return itself @@ -35,7 +51,7 @@ class SchemaNode { ) { SchemaNode returnValue; if (transform != null) { - returnValue = this.withValue(transform.call(this)); + returnValue = this.withValue(transform.call(this), rawValue); } returnValue = this; resultCallback?.call(returnValue); @@ -108,8 +124,8 @@ abstract class Schema { /// Returns default value or null for a node. Calls [result] if value is /// not null. dynamic getDefaultValue(SchemaNode o) { - final v = defaultValue?.call(o.withValue(null)); - if (v != null) result?.call(o.withValue(v)); + final v = defaultValue?.call(o.withValue(null, null)); + if (v != null) result?.call(o.withValue(v, null)); return v; } @@ -244,7 +260,9 @@ class FixedMapSchema extends Schema> { } childExtracts[key] = value.extractNode(schemaNode).value as CE; } - return o.withValue(childExtracts).transformOrThis(transform, result); + return o + .withValue(childExtracts, o.rawValue) + .transformOrThis(transform, result); } @override @@ -348,7 +366,9 @@ class DynamicMapSchema extends Schema> { } } - return o.withValue(childExtracts).transformOrThis(transform, result); + return o + .withValue(childExtracts, o.rawValue) + .transformOrThis(transform, result); } @override @@ -412,7 +432,9 @@ class ListSchema extends Schema> { } childExtracts.add(childSchema.extractNode(schemaNode).value as CE); } - return o.withValue(childExtracts).transformOrThis(transform, result); + return o + .withValue(childExtracts, o.rawValue) + .transformOrThis(transform, result); } @override @@ -448,7 +470,9 @@ class StringSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as String).transformOrThis(transform, result); + return o + .withValue(o.value as String, o.rawValue) + .transformOrThis(transform, result); } @override @@ -483,7 +507,9 @@ class IntSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as int).transformOrThis(transform, result); + return o + .withValue(o.value as int, o.rawValue) + .transformOrThis(transform, result); } @override @@ -524,7 +550,9 @@ class EnumSchema extends Schema { if (!allowedValues.contains(o.value)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as CE).transformOrThis(transform, result); + return o + .withValue(o.value as CE, o.rawValue) + .transformOrThis(transform, result); } @override @@ -559,7 +587,9 @@ class BoolSchema extends Schema { if (!o.checkType(log: false)) { throw SchemaExtractionError(o); } - return o.withValue(o.value as bool).transformOrThis(transform, result); + return o + .withValue(o.value as bool, o.rawValue) + .transformOrThis(transform, result); } @override @@ -610,7 +640,7 @@ class OneOfSchema extends Schema { for (final schema in childSchemas) { if (schema.validateNode(o, log: false)) { return o - .withValue(schema.extractNode(o).value as E) + .withValue(schema.extractNode(o).value as E, o.rawValue) .transformOrThis(transform, result); } } @@ -630,77 +660,86 @@ class OneOfSchema extends Schema { void main() { final extractMap = {}; final testSchema = FixedMapSchema( - keys: { - "name": StringSchema( - result: (node) => extractMap[node.pathString] = node.value, - ), - "description": StringSchema( - result: (node) => extractMap[node.pathString] = node.value, - ), - "output": OneOfSchema( - childSchemas: [ - StringSchema( - schemaDefName: "outputBindings", - transform: (node) => extractMap[node.pathString] = node.value, - ), - FixedMapSchema( - keys: { - "bindings": StringSchema( - schemaDefName: "outputBindings", - ), - "symbol-file": FixedMapSchema(keys: { - "output": StringSchema(), - "import-path": StringSchema(), - }) - }, - requiredKeys: ["bindings"], - transform: (node) => - OutputConfig(node.value["bindings"] as String, null), - result: (node) => extractMap[node.pathString] = node.value, - ) - ], - ), - "headers": FixedMapSchema>( - keys: { - "entry-points": ListSchema(childSchema: StringSchema()), - "include-directives": ListSchema(childSchema: StringSchema()), - }, - result: (node) => extractMap[node.pathString] = node.value, - ), - "structs": FixedMapSchema(keys: { - "include": ListSchema(childSchema: StringSchema()), - "exclude": ListSchema(childSchema: StringSchema()), - "rename": DynamicMapSchema(keyValueSchemas: [ - ( - keyRegexp: r"^.+$", - valueSchema: - OneOfSchema(childSchemas: [StringSchema(), IntSchema()]), - ) - ]), - "pack": DynamicMapSchema(keyValueSchemas: [ - ( - keyRegexp: r"^.+$", - valueSchema: - EnumSchema(allowedValues: {null, 1, 2, 4, 8, 16}), - ) - ]) - }), - "comments": FixedMapSchema( - keys: { - "style": EnumSchema( - allowedValues: {"any", "doxygen"}, - defaultValue: (node) => "doxygen", - ), - "length": EnumSchema( - allowedValues: {"brief", "full"}, - defaultValue: (node) => "brief", - result: (node) => extractMap[node.pathString] = node.value, - ), - }, - result: (node) => extractMap[node.pathString] = node.value, - ), - }, - ); + keys: { + "name": StringSchema( + result: (node) => extractMap[node.pathString] = node.value, + ), + "description": StringSchema( + result: (node) => extractMap[node.pathString] = node.value, + ), + "output": OneOfSchema( + childSchemas: [ + StringSchema( + schemaDefName: "outputBindings", + transform: (node) => extractMap[node.pathString] = node.value, + ), + FixedMapSchema( + keys: { + "bindings": StringSchema( + schemaDefName: "outputBindings", + ), + "symbol-file": FixedMapSchema(keys: { + "output": StringSchema(), + "import-path": StringSchema(), + }) + }, + requiredKeys: ["bindings"], + transform: (node) => + OutputConfig(node.value["bindings"] as String, null), + result: (node) => extractMap[node.pathString] = node.value, + ) + ], + ), + "headers": FixedMapSchema>( + keys: { + "entry-points": ListSchema(childSchema: StringSchema()), + "include-directives": + ListSchema(childSchema: StringSchema()), + }, + result: (node) => extractMap[node.pathString] = node.value, + ), + "structs": FixedMapSchema(keys: { + "include": ListSchema(childSchema: StringSchema()), + "exclude": ListSchema(childSchema: StringSchema()), + "rename": DynamicMapSchema(keyValueSchemas: [ + ( + keyRegexp: r"^.+$", + valueSchema: + OneOfSchema(childSchemas: [StringSchema(), IntSchema()]), + ) + ]), + "pack": DynamicMapSchema(keyValueSchemas: [ + ( + keyRegexp: r"^.+$", + valueSchema: + EnumSchema(allowedValues: {null, 1, 2, 4, 8, 16}), + ) + ]) + }), + "comments": FixedMapSchema( + keys: { + "style": EnumSchema( + allowedValues: {"any", "doxygen"}, + defaultValue: (node) => "doxygen", + ), + "length": EnumSchema( + allowedValues: {"brief", "full"}, + defaultValue: (node) => "brief", + result: (node) => extractMap[node.pathString] = node.value, + ), + }, + result: (node) { + print("comments rawValue: ${node.rawValue}"); + print("comments value: ${node.value}"); + extractMap[node.pathString] = node.value; + }, + ), + }, + result: (node) { + print("root rawValue: ${node.rawValue}"); + print("root value: ${node.value}"); + extractMap[node.pathString] = node.value; + }); _logger.onRecord.listen((event) => print(event)); final yaml = loadYaml(""" name: NativeLibrary From 1e7071da24bd1ac8e3a87663965543d8a3dc3e7b Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 16:27:27 +0530 Subject: [PATCH 13/23] Fix transformOrThis not using transformed result type --- lib/src/config_provider/schema.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index a86b1927..1892e124 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -49,11 +49,10 @@ class SchemaNode { dynamic Function(SchemaNode value)? transform, void Function(SchemaNode node)? resultCallback, ) { - SchemaNode returnValue; + SchemaNode returnValue = this; if (transform != null) { returnValue = this.withValue(transform.call(this), rawValue); } - returnValue = this; resultCallback?.call(returnValue); return returnValue; } From 72b9297bfb672df0ab81ab005175ff676558e8a6 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 22:33:04 +0530 Subject: [PATCH 14/23] Create and use rough schema in config provider --- lib/src/config_provider/config.dart | 448 +++++++++++++++++- lib/src/config_provider/schema.dart | 4 +- lib/src/config_provider/spec_utils.dart | 11 +- .../clang_bindings/clang_bindings.dart | 4 +- 4 files changed, 455 insertions(+), 12 deletions(-) diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart index 12a7e69f..d52a46eb 100644 --- a/lib/src/config_provider/config.dart +++ b/lib/src/config_provider/config.dart @@ -4,6 +4,7 @@ /// Validates the yaml input by the user, prints useful info for the user +import 'dart:convert'; import 'dart:io'; import 'package:ffigen/src/code_generator.dart'; @@ -13,6 +14,7 @@ import 'package:yaml/yaml.dart'; import '../strings.dart' as strings; import 'config_types.dart'; +import 'schema.dart'; import 'spec_utils.dart'; final _logger = Logger('ffigen.config_provider.config'); @@ -184,14 +186,13 @@ class Config { final configspecs = Config._(filename, packageConfig); _logger.finest('Config Map: $map'); - final specs = configspecs._getSpecs(); - - final result = configspecs._checkConfigs(map, specs); + final ffigenSchema = configspecs.getRootSchema(); + final result = ffigenSchema.validate(map); if (!result) { throw FormatException('Invalid configurations provided.'); } - configspecs._extract(map, specs); + ffigenSchema.extract(map); return configspecs; } @@ -574,4 +575,443 @@ class Config { ) }; } + + Schema getRootSchema() { + return FixedMapSchema( + requiredKeys: [strings.output, strings.headers], + keys: { + strings.llvmPath: ListSchema( + childSchema: StringSchema(), + transform: (node) => llvmPathExtractor(YamlList.wrap(node.value)), + defaultValue: (node) => findDylibAtDefaultLocations(), + result: (node) => _libclangDylib = node.value as String, + ), + strings.output: OneOfSchema( + childSchemas: [ + StringSchema(), + FixedMapSchema( + requiredKeys: [strings.bindings], + keys: { + strings.bindings: StringSchema(), + strings.symbolFile: FixedMapSchema( + requiredKeys: [strings.name, strings.importPath], + keys: { + strings.name: StringSchema(), + strings.importPath: StringSchema() + }, + ) + }, + ) + ], + transform: (node) => + outputExtractor(node.rawValue, filename, packageConfig), + result: (node) { + _output = (node.value as OutputConfig).output; + _symbolFile = (node.value as OutputConfig).symbolFile; + }, + ), + strings.language: EnumSchema( + allowedValues: {strings.langC, strings.langObjC}, + transform: (node) => + (node.value == strings.langObjC) ? Language.objc : Language.c, + defaultValue: (node) => Language.c, + result: (node) => _language = node.value as Language, + ), + strings.headers: FixedMapSchema>( + requiredKeys: [strings.entryPoints], + keys: { + strings.entryPoints: + ListSchema(childSchema: StringSchema()), + strings.includeDirectives: + ListSchema(childSchema: StringSchema()), + }, + transform: (node) => headersExtractor(node.rawValue, filename), + result: (node) => _headers = node.value as Headers, + ), + strings.compilerOpts: OneOfSchema( + childSchemas: [ + StringSchema(), + ListSchema(childSchema: StringSchema()) + ], + transform: (node) => compilerOptsExtractor(node.rawValue), + defaultValue: (node) => [], + result: (node) => _compilerOpts = node.value as List, + ), + strings.compilerOptsAuto: FixedMapSchema( + keys: { + strings.macos: FixedMapSchema( + keys: { + strings.includeCStdLib: BoolSchema(), + }, + ) + }, + transform: (node) => compilerOptsAutoExtractor(node.rawValue), + defaultValue: (node) => CompilerOptsAuto(), + result: (node) => _compilerOpts + .addAll((node.value as CompilerOptsAuto).extractCompilerOpts()), + ), + strings.libraryImports: DynamicMapSchema( + keyValueSchemas: [ + (keyRegexp: ".*", valueSchema: StringSchema()), + ], + transform: (node) => libraryImportsExtractor(node.rawValue), + defaultValue: (node) => {}, + result: (node) => + _libraryImports = (node.value) as Map, + ), + strings.functions: FixedMapSchema( + keys: { + ...includeExcludeProperties(), + ...renameProperties(), + strings.symbolAddress: includeExcludeObject(), + strings.exposeFunctionTypedefs: includeExcludeObject( + defaultValue: (node) => Includer.excludeByDefault(), + ), + strings.leafFunctions: includeExcludeObject( + defaultValue: (node) => Includer.excludeByDefault(), + ), + strings.varArgFunctions: DynamicMapSchema( + keyValueSchemas: [ + ( + keyRegexp: ".*", + valueSchema: ListSchema(childSchema: StringSchema()) + ) + ], + defaultValue: (node) => >{}, + transform: (node) => varArgFunctionConfigExtractor(node.rawValue), + result: (node) { + _varArgFunctions = makeVarArgFunctionsMapping( + node.value as Map>, + _libraryImports); + }, + ) + }, + result: (node) { + _functionDecl = + declarationConfigExtractor(node.rawValue ?? YamlMap()); + _exposeFunctionTypedefs = + (node.value as Map)[strings.exposeFunctionTypedefs] as Includer; + _leafFunctions = + (node.value as Map)[strings.leafFunctions] as Includer; + }, + ), + strings.structs: FixedMapSchema( + keys: { + ...includeExcludeProperties(), + ...renameProperties(), + ...memberRenameProperties(), + strings.dependencyOnly: dependencyOnlyObject(), + strings.structPack: DynamicMapSchema( + keyValueSchemas: [ + ( + keyRegexp: '.*', + valueSchema: EnumSchema( + allowedValues: {null, 1, 2, 4, 8, 16}, + ), + ) + ], + transform: (node) => + structPackingOverrideExtractor(node.rawValue), + defaultValue: (node) => StructPackingOverride(), + result: (node) => + _structPackingOverride = node.value as StructPackingOverride, + ) + }, + result: (node) { + _structDecl = + declarationConfigExtractor(node.rawValue ?? YamlMap()); + _structDependencies = (node.value as Map)[strings.dependencyOnly] + as CompoundDependencies; + }, + ), + strings.unions: FixedMapSchema( + keys: { + ...includeExcludeProperties(), + ...renameProperties(), + ...memberRenameProperties(), + strings.dependencyOnly: dependencyOnlyObject(), + }, + result: (node) { + _unionDecl = declarationConfigExtractor(node.rawValue ?? YamlMap()); + _unionDependencies = (node.value as Map)[strings.dependencyOnly] + as CompoundDependencies; + }, + ), + strings.enums: FixedMapSchema( + keys: { + ...includeExcludeProperties(), + ...renameProperties(), + ...memberRenameProperties(), + }, + result: (node) { + _enumClassDecl = + declarationConfigExtractor(node.rawValue ?? YamlMap()); + }, + ), + strings.unnamedEnums: FixedMapSchema( + keys: { + ...includeExcludeProperties(), + ...renameProperties(), + }, + result: (node) { + _unnamedEnumConstants = + declarationConfigExtractor(node.rawValue ?? YamlMap()); + }, + ), + strings.globals: FixedMapSchema( + keys: { + ...includeExcludeProperties(), + ...renameProperties(), + }, + result: (node) { + _globals = declarationConfigExtractor(node.rawValue ?? YamlMap()); + }, + ), + strings.macros: FixedMapSchema( + keys: { + ...includeExcludeProperties(), + ...renameProperties(), + }, + result: (node) { + _macroDecl = declarationConfigExtractor(node.rawValue ?? YamlMap()); + }, + ), + strings.typedefs: FixedMapSchema( + keys: { + ...includeExcludeProperties(), + ...renameProperties(), + }, + result: (node) { + _typedefs = declarationConfigExtractor(node.rawValue ?? YamlMap()); + }, + ), + strings.objcInterfaces: FixedMapSchema( + keys: { + ...includeExcludeProperties(), + ...renameProperties(), + ...memberRenameProperties(), + strings.objcModule: objcInterfaceModuleObject(), + }, + result: (node) { + _objcInterfaces = + declarationConfigExtractor(node.rawValue ?? YamlMap()); + _objcModulePrefixer = + (node.value as Map)[strings.objcModule] as ObjCModulePrefixer; + }, + ), + strings.import: FixedMapSchema( + keys: { + strings.symbolFilesImport: ListSchema( + childSchema: StringSchema(), + transform: (node) => symbolFileImportExtractor( + node.rawValue, _libraryImports, filename, packageConfig), + defaultValue: (node) => {}, + result: (node) => + _usrTypeMappings = node.value as Map, + ), + }, + ), + strings.typeMap: FixedMapSchema( + keys: { + strings.typeMapTypedefs: mappedTypeObject(), + strings.typeMapStructs: mappedTypeObject(), + strings.typeMapUnions: mappedTypeObject(), + strings.typeMapNativeTypes: mappedTypeObject(), + }, + result: (node) { + _typedefTypeMappings = makeImportTypeMapping( + (node.value[strings.typeMapTypedefs]) + as Map>, + _libraryImports, + ); + _structTypeMappings = makeImportTypeMapping( + (node.value[strings.typeMapStructs]) as Map>, + _libraryImports, + ); + _unionTypeMappings = makeImportTypeMapping( + (node.value[strings.typeMapUnions]) as Map>, + _libraryImports, + ); + _nativeTypeMappings = makeImportTypeMapping( + (node.value[strings.typeMapNativeTypes]) + as Map>, + _libraryImports, + ); + }, + ), + strings.excludeAllByDefault: BoolSchema( + defaultValue: (node) => false, + result: (node) => _excludeAllByDefault = node.value as bool, + ), + strings.sort: BoolSchema( + defaultValue: (node) => false, + result: (node) => _sort = node.value as bool, + ), + strings.useSupportedTypedefs: BoolSchema( + defaultValue: (node) => true, + result: (node) => _useSupportedTypedefs = node.value as bool, + ), + strings.comments: OneOfSchema( + childSchemas: [ + BoolSchema( + transform: (node) => + (node.value == true) ? CommentType.def() : CommentType.none(), + ), + FixedMapSchema( + keys: { + strings.style: EnumSchema( + allowedValues: {strings.doxygen, strings.any}, + transform: (node) => node.value == strings.doxygen + ? CommentStyle.doxygen + : CommentStyle.any, + defaultValue: (node) => CommentStyle.doxygen, + ), + strings.length: EnumSchema( + allowedValues: {strings.brief, strings.full}, + transform: (node) => node.value == strings.brief + ? CommentLength.brief + : CommentLength.full, + defaultValue: (node) => CommentLength.full, + ) + }, + transform: (node) => CommentType( + (node.value)[strings.style] as CommentStyle, + (node.value)[strings.length] as CommentLength, + ), + ), + ], + defaultValue: (node) => CommentType.def(), + result: (node) => _commentType = node.value as CommentType, + ), + strings.name: StringSchema( + defaultValue: (node) { + _logger.warning( + "Prefer adding Key '${node.pathString}' to your config."); + return 'NativeLibrary'; + }, + result: (node) => _wrapperName = node.value as String, + ), + strings.description: StringSchema( + defaultValue: (node) { + _logger.warning( + "Prefer adding Key '${node.pathString}' to your config."); + return null; + }, + result: (node) => _wrapperDocComment = node.value as String?, + ), + strings.preamble: StringSchema( + result: (node) => _preamble = node.value as String?, + ), + strings.useDartHandle: BoolSchema( + defaultValue: (node) => true, + result: (node) => _useDartHandle = node.value as bool, + ), + strings.ffiNative: BoolSchema( + transform: (node) => ffiNativeExtractor(node.rawValue), + defaultValue: (node) => FfiNativeConfig(enabled: false), + result: (node) => _ffiNativeConfig = (node.value) as FfiNativeConfig, + ), + }, + ); + } + + Map includeExcludeProperties() { + return { + strings.include: ListSchema( + schemaDefName: "include", + childSchema: StringSchema(), + ), + strings.exclude: ListSchema( + schemaDefName: "exclude", + childSchema: StringSchema(), + defaultValue: (node) => [], + ), + }; + } + + Map renameProperties() { + return { + strings.rename: DynamicMapSchema( + schemaDefName: "rename", + keyValueSchemas: [ + (keyRegexp: ".+", valueSchema: StringSchema()), + ], + ), + }; + } + + Map memberRenameProperties() { + return { + strings.memberRename: DynamicMapSchema( + schemaDefName: "memberRename", + keyValueSchemas: [ + ( + keyRegexp: ".+", + valueSchema: DynamicMapSchema( + keyValueSchemas: [(keyRegexp: ".+", valueSchema: StringSchema())], + ), + ), + ], + ), + }; + } + + FixedMapSchema> includeExcludeObject( + {dynamic Function(SchemaNode node)? defaultValue}) { + return FixedMapSchema>( + schemaDefName: "includeExclude", + keys: { + ...includeExcludeProperties(), + }, + transform: (node) => extractIncluderFromYaml(node.rawValue ?? YamlMap()), + defaultValue: defaultValue, + ); + } + + EnumSchema dependencyOnlyObject() { + return EnumSchema( + schemaDefName: "dependencyOnly", + allowedValues: { + strings.fullCompoundDependencies, + strings.opaqueCompoundDependencies, + }, + defaultValue: (node) => CompoundDependencies.full, + transform: (node) => node.value == strings.opaqueCompoundDependencies + ? CompoundDependencies.opaque + : CompoundDependencies.full, + ); + } + + DynamicMapSchema mappedTypeObject() { + return DynamicMapSchema( + schemaDefName: "mappedTypes", + keyValueSchemas: [ + ( + keyRegexp: ".*", + valueSchema: FixedMapSchema( + requiredKeys: [strings.lib, strings.cType, strings.dartType], + keys: { + strings.lib: StringSchema(), + strings.cType: StringSchema(), + strings.dartType: StringSchema(), + }, + ) + ) + ], + defaultValue: (node) => >{}, + transform: (node) => typeMapExtractor(node.rawValue), + ); + } + + DynamicMapSchema objcInterfaceModuleObject() { + return DynamicMapSchema( + schemaDefName: "objcInterfaceModule", + keyValueSchemas: [ + (keyRegexp: ".*", valueSchema: StringSchema()), + ], + transform: (node) => + ObjCModulePrefixer(node.value.cast()), + defaultValue: (node) => ObjCModulePrefixer({}), + ); + } } diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index 1892e124..fbb38ef1 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -182,7 +182,9 @@ class FixedMapSchema extends Schema> { result[key] = defaultValue as CE; } } - return result.isEmpty ? null : result; + return result.isEmpty + ? null + : o.withValue(result, null).transformOrThis(transform, null).value; }; } diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart index 8bb3e2b8..09387475 100644 --- a/lib/src/config_provider/spec_utils.dart +++ b/lib/src/config_provider/spec_utils.dart @@ -798,7 +798,7 @@ bool languageValidator(List name, dynamic value) { bool isFullDeclarationName(String str) => quiver.matchesFull(RegExp('[a-zA-Z_0-9]*'), str); -Includer _extractIncluderFromYaml(dynamic yamlMap) { +Includer extractIncluderFromYaml(dynamic yamlMap) { final includeMatchers = [], includeFull = {}, excludeMatchers = [], @@ -922,11 +922,11 @@ Declaration declarationConfigExtractor(dynamic yamlMap) { final memberRenamePatterns = []; final memberRenamerFull = {}; - final includer = _extractIncluderFromYaml(yamlMap); + final includer = extractIncluderFromYaml(yamlMap); Includer? symbolIncluder; if (yamlMap[strings.symbolAddress] != null) { - symbolIncluder = _extractIncluderFromYaml(yamlMap[strings.symbolAddress]); + symbolIncluder = extractIncluderFromYaml(yamlMap[strings.symbolAddress]); } final rename = (yamlMap[strings.rename] as YamlMap?)?.cast(); @@ -1060,7 +1060,7 @@ bool declarationConfigValidator(List name, dynamic value) { } Includer exposeFunctionTypeExtractor(dynamic value) => - _extractIncluderFromYaml(value); + extractIncluderFromYaml(value); bool exposeFunctionTypeValidator(List name, dynamic value) { var result = true; @@ -1084,8 +1084,7 @@ bool exposeFunctionTypeValidator(List name, dynamic value) { return result; } -Includer leafFunctionExtractor(dynamic value) => - _extractIncluderFromYaml(value); +Includer leafFunctionExtractor(dynamic value) => extractIncluderFromYaml(value); bool leafFunctionValidator(List name, dynamic value) { var result = true; diff --git a/lib/src/header_parser/clang_bindings/clang_bindings.dart b/lib/src/header_parser/clang_bindings/clang_bindings.dart index c7d6e2f4..a2217b43 100644 --- a/lib/src/header_parser/clang_bindings/clang_bindings.dart +++ b/lib/src/header_parser/clang_bindings/clang_bindings.dart @@ -2593,7 +2593,9 @@ abstract class CXChildVisitResult { /// The visitor should return one of the \c CXChildVisitResult values /// to direct clang_visitCursorChildren(). typedef CXCursorVisitor = ffi.Pointer< - ffi.NativeFunction>; + ffi.NativeFunction< + ffi.Int32 Function( + CXCursor cursor, CXCursor parent, CXClientData client_data)>>; /// Opaque pointer representing client data that will be passed through /// to various callbacks and visitors. From dc035eb126739df88ffe8a266a7e4c4d230f5bb0 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 22:37:11 +0530 Subject: [PATCH 15/23] TEMP: comment old specs code for analyzer --- lib/src/config_provider/config.dart | 701 ++++++++++++++-------------- 1 file changed, 350 insertions(+), 351 deletions(-) diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart index d52a46eb..d72ba1f3 100644 --- a/lib/src/config_provider/config.dart +++ b/lib/src/config_provider/config.dart @@ -4,7 +4,6 @@ /// Validates the yaml input by the user, prints useful info for the user -import 'dart:convert'; import 'dart:io'; import 'package:ffigen/src/code_generator.dart'; @@ -217,364 +216,364 @@ class Config { } /// Validates Yaml according to given specs. - bool _checkConfigs(YamlMap map, Map, Specification> specs) { - var result = true; - for (final key in specs.keys) { - final spec = specs[key]; - if (checkKeyInYaml(key, map)) { - result = result && spec!.validator(key, getKeyValueFromYaml(key, map)); - } else if (spec!.requirement == Requirement.yes) { - _logger.severe("Key '$key' is required."); - result = false; - } else if (spec.requirement == Requirement.prefer) { - _logger.warning("Prefer adding Key '$key' to your config."); - } - } - // Warn about unknown keys. - warnUnknownKeys(specs.keys.toList(), map); - - return result; - } + // bool _checkConfigs(YamlMap map, Map, Specification> specs) { + // var result = true; + // for (final key in specs.keys) { + // final spec = specs[key]; + // if (checkKeyInYaml(key, map)) { + // result = result && spec!.validator(key, getKeyValueFromYaml(key, map)); + // } else if (spec!.requirement == Requirement.yes) { + // _logger.severe("Key '$key' is required."); + // result = false; + // } else if (spec.requirement == Requirement.prefer) { + // _logger.warning("Prefer adding Key '$key' to your config."); + // } + // } + // // Warn about unknown keys. + // warnUnknownKeys(specs.keys.toList(), map); + + // return result; + // } /// Extracts variables from Yaml according to given specs. /// /// Validation must be done beforehand, using [_checkConfigs]. - void _extract(YamlMap map, Map, Specification> specs) { - for (final key in specs.keys) { - final spec = specs[key]; - if (checkKeyInYaml(key, map)) { - spec!.extractedResult(spec.extractor(getKeyValueFromYaml(key, map))); - } else { - spec!.extractedResult(spec.defaultValue?.call()); - } - } - } + // void _extract(YamlMap map, Map, Specification> specs) { + // for (final key in specs.keys) { + // final spec = specs[key]; + // if (checkKeyInYaml(key, map)) { + // spec!.extractedResult(spec.extractor(getKeyValueFromYaml(key, map))); + // } else { + // spec!.extractedResult(spec.defaultValue?.call()); + // } + // } + // } /// Returns map of various specifications avaialble for our tool. /// /// Key: Name, Value: [Specification] - Map, Specification> _getSpecs() { - return , Specification>{ - [strings.llvmPath]: Specification( - requirement: Requirement.no, - validator: llvmPathValidator, - extractor: llvmPathExtractor, - defaultValue: () => findDylibAtDefaultLocations(), - extractedResult: (dynamic result) { - _libclangDylib = result as String; - }, - ), - [strings.output]: Specification( - requirement: Requirement.yes, - validator: outputValidator, - extractor: (dynamic value) => - outputExtractor(value, filename, packageConfig), - extractedResult: (dynamic result) { - _output = (result as OutputConfig).output; - _symbolFile = result.symbolFile; - }, - ), - [strings.language]: Specification( - requirement: Requirement.no, - validator: languageValidator, - extractor: languageExtractor, - defaultValue: () => Language.c, - extractedResult: (dynamic result) => _language = result as Language, - ), - [strings.headers]: Specification( - requirement: Requirement.yes, - validator: headersValidator, - extractor: (dynamic value) => headersExtractor(value, filename), - extractedResult: (dynamic result) => _headers = result as Headers, - ), - [strings.compilerOpts]: Specification>( - requirement: Requirement.no, - validator: compilerOptsValidator, - extractor: compilerOptsExtractor, - defaultValue: () => [], - extractedResult: (dynamic result) => - _compilerOpts = result as List, - ), - [strings.compilerOptsAuto]: Specification( - requirement: Requirement.no, - validator: compilerOptsAutoValidator, - extractor: compilerOptsAutoExtractor, - defaultValue: () => CompilerOptsAuto(), - extractedResult: (dynamic result) { - _compilerOpts - .addAll((result as CompilerOptsAuto).extractCompilerOpts()); - }), - [strings.functions]: Specification( - requirement: Requirement.no, - validator: declarationConfigValidator, - extractor: declarationConfigExtractor, - defaultValue: () => Declaration(), - extractedResult: (dynamic result) { - _functionDecl = result as Declaration; - }, - ), - [strings.structs]: Specification( - requirement: Requirement.no, - validator: declarationConfigValidator, - extractor: declarationConfigExtractor, - defaultValue: () => Declaration(), - extractedResult: (dynamic result) { - _structDecl = result as Declaration; - }, - ), - [strings.unions]: Specification( - requirement: Requirement.no, - validator: declarationConfigValidator, - extractor: declarationConfigExtractor, - defaultValue: () => Declaration(), - extractedResult: (dynamic result) { - _unionDecl = result as Declaration; - }, - ), - [strings.enums]: Specification( - requirement: Requirement.no, - validator: declarationConfigValidator, - extractor: declarationConfigExtractor, - defaultValue: () => Declaration(), - extractedResult: (dynamic result) { - _enumClassDecl = result as Declaration; - }, - ), - [strings.unnamedEnums]: Specification( - requirement: Requirement.no, - validator: declarationConfigValidator, - extractor: declarationConfigExtractor, - defaultValue: () => Declaration(), - extractedResult: (dynamic result) => - _unnamedEnumConstants = result as Declaration, - ), - [strings.globals]: Specification( - requirement: Requirement.no, - validator: declarationConfigValidator, - extractor: declarationConfigExtractor, - defaultValue: () => Declaration(), - extractedResult: (dynamic result) { - _globals = result as Declaration; - }, - ), - [strings.macros]: Specification( - requirement: Requirement.no, - validator: declarationConfigValidator, - extractor: declarationConfigExtractor, - defaultValue: () => Declaration(), - extractedResult: (dynamic result) { - _macroDecl = result as Declaration; - }, - ), - [strings.typedefs]: Specification( - requirement: Requirement.no, - validator: declarationConfigValidator, - extractor: declarationConfigExtractor, - defaultValue: () => Declaration(), - extractedResult: (dynamic result) { - _typedefs = result as Declaration; - }, - ), - [strings.objcInterfaces]: Specification( - requirement: Requirement.no, - validator: declarationConfigValidator, - extractor: declarationConfigExtractor, - defaultValue: () => Declaration(), - extractedResult: (dynamic result) { - _objcInterfaces = result as Declaration; - }, - ), - [strings.objcInterfaces, strings.objcModule]: - Specification>( - requirement: Requirement.no, - validator: stringStringMapValidator, - extractor: stringStringMapExtractor, - defaultValue: () => {}, - extractedResult: (dynamic result) => _objcModulePrefixer = - ObjCModulePrefixer(result as Map), - ), - [strings.libraryImports]: Specification>( - validator: libraryImportsValidator, - extractor: libraryImportsExtractor, - defaultValue: () => {}, - extractedResult: (dynamic result) { - _libraryImports = result as Map; - }, - ), - [strings.import, strings.symbolFilesImport]: - Specification>( - validator: symbolFileImportValidator, - extractor: (value) => symbolFileImportExtractor( - value, _libraryImports, filename, packageConfig), - defaultValue: () => {}, - extractedResult: (dynamic result) { - _usrTypeMappings = result as Map; - }, - ), - [strings.typeMap, strings.typeMapTypedefs]: - Specification>>( - validator: typeMapValidator, - extractor: typeMapExtractor, - defaultValue: () => >{}, - extractedResult: (dynamic result) { - _typedefTypeMappings = makeImportTypeMapping( - result as Map>, _libraryImports); - }, - ), - [strings.typeMap, strings.typeMapStructs]: - Specification>>( - validator: typeMapValidator, - extractor: typeMapExtractor, - defaultValue: () => >{}, - extractedResult: (dynamic result) { - _structTypeMappings = makeImportTypeMapping( - result as Map>, _libraryImports); - }, - ), - [strings.typeMap, strings.typeMapUnions]: - Specification>>( - validator: typeMapValidator, - extractor: typeMapExtractor, - defaultValue: () => >{}, - extractedResult: (dynamic result) { - _unionTypeMappings = makeImportTypeMapping( - result as Map>, _libraryImports); - }, - ), - [strings.typeMap, strings.typeMapNativeTypes]: - Specification>>( - validator: typeMapValidator, - extractor: typeMapExtractor, - defaultValue: () => >{}, - extractedResult: (dynamic result) { - _nativeTypeMappings = makeImportTypeMapping( - result as Map>, _libraryImports); - }, - ), - [strings.functions, strings.varArgFunctions]: - Specification>>( - requirement: Requirement.no, - validator: varArgFunctionConfigValidator, - extractor: varArgFunctionConfigExtractor, - defaultValue: () => >{}, - extractedResult: (dynamic result) { - _varArgFunctions = makeVarArgFunctionsMapping( - result as Map>, _libraryImports); - }, - ), - [strings.excludeAllByDefault]: Specification( - requirement: Requirement.no, - validator: booleanValidator, - extractor: booleanExtractor, - defaultValue: () => false, - extractedResult: (dynamic result) => - _excludeAllByDefault = result as bool, - ), - [strings.sort]: Specification( - requirement: Requirement.no, - validator: booleanValidator, - extractor: booleanExtractor, - defaultValue: () => false, - extractedResult: (dynamic result) => _sort = result as bool, - ), - [strings.useSupportedTypedefs]: Specification( - requirement: Requirement.no, - validator: booleanValidator, - extractor: booleanExtractor, - defaultValue: () => true, - extractedResult: (dynamic result) => - _useSupportedTypedefs = result as bool, - ), - [strings.comments]: Specification( - requirement: Requirement.no, - validator: commentValidator, - extractor: commentExtractor, - defaultValue: () => CommentType.def(), - extractedResult: (dynamic result) => - _commentType = result as CommentType, - ), - [strings.structs, strings.dependencyOnly]: - Specification( - requirement: Requirement.no, - validator: dependencyOnlyValidator, - extractor: dependencyOnlyExtractor, - defaultValue: () => CompoundDependencies.full, - extractedResult: (dynamic result) => - _structDependencies = result as CompoundDependencies, - ), - [strings.unions, strings.dependencyOnly]: - Specification( - requirement: Requirement.no, - validator: dependencyOnlyValidator, - extractor: dependencyOnlyExtractor, - defaultValue: () => CompoundDependencies.full, - extractedResult: (dynamic result) => - _unionDependencies = result as CompoundDependencies, - ), - [strings.structs, strings.structPack]: - Specification( - requirement: Requirement.no, - validator: structPackingOverrideValidator, - extractor: structPackingOverrideExtractor, - defaultValue: () => StructPackingOverride(), - extractedResult: (dynamic result) => - _structPackingOverride = result as StructPackingOverride, - ), - [strings.name]: Specification( - requirement: Requirement.prefer, - validator: dartClassNameValidator, - extractor: stringExtractor, - defaultValue: () => 'NativeLibrary', - extractedResult: (dynamic result) => _wrapperName = result as String, - ), - [strings.description]: Specification( - requirement: Requirement.prefer, - validator: nonEmptyStringValidator, - extractor: stringExtractor, - defaultValue: () => null, - extractedResult: (dynamic result) => - _wrapperDocComment = result as String?, - ), - [strings.preamble]: Specification( - requirement: Requirement.no, - validator: nonEmptyStringValidator, - extractor: stringExtractor, - extractedResult: (dynamic result) => _preamble = result as String?, - ), - [strings.useDartHandle]: Specification( - requirement: Requirement.no, - validator: booleanValidator, - extractor: booleanExtractor, - defaultValue: () => true, - extractedResult: (dynamic result) => _useDartHandle = result as bool, - ), - [strings.functions, strings.exposeFunctionTypedefs]: - Specification( - requirement: Requirement.no, - validator: exposeFunctionTypeValidator, - extractor: exposeFunctionTypeExtractor, - defaultValue: () => Includer.excludeByDefault(), - extractedResult: (dynamic result) => - _exposeFunctionTypedefs = result as Includer, - ), - [strings.functions, strings.leafFunctions]: Specification( - requirement: Requirement.no, - validator: leafFunctionValidator, - extractor: leafFunctionExtractor, - defaultValue: () => Includer.excludeByDefault(), - extractedResult: (dynamic result) => - _leafFunctions = result as Includer, - ), - [strings.ffiNative]: Specification( - requirement: Requirement.no, - validator: ffiNativeValidator, - extractor: ffiNativeExtractor, - defaultValue: () => FfiNativeConfig(enabled: false), - extractedResult: (dynamic result) => - _ffiNativeConfig = result as FfiNativeConfig, - ) - }; - } + // Map, Specification> _getSpecs() { + // return , Specification>{ + // [strings.llvmPath]: Specification( + // requirement: Requirement.no, + // validator: llvmPathValidator, + // extractor: llvmPathExtractor, + // defaultValue: () => findDylibAtDefaultLocations(), + // extractedResult: (dynamic result) { + // _libclangDylib = result as String; + // }, + // ), + // [strings.output]: Specification( + // requirement: Requirement.yes, + // validator: outputValidator, + // extractor: (dynamic value) => + // outputExtractor(value, filename, packageConfig), + // extractedResult: (dynamic result) { + // _output = (result as OutputConfig).output; + // _symbolFile = result.symbolFile; + // }, + // ), + // [strings.language]: Specification( + // requirement: Requirement.no, + // validator: languageValidator, + // extractor: languageExtractor, + // defaultValue: () => Language.c, + // extractedResult: (dynamic result) => _language = result as Language, + // ), + // [strings.headers]: Specification( + // requirement: Requirement.yes, + // validator: headersValidator, + // extractor: (dynamic value) => headersExtractor(value, filename), + // extractedResult: (dynamic result) => _headers = result as Headers, + // ), + // [strings.compilerOpts]: Specification>( + // requirement: Requirement.no, + // validator: compilerOptsValidator, + // extractor: compilerOptsExtractor, + // defaultValue: () => [], + // extractedResult: (dynamic result) => + // _compilerOpts = result as List, + // ), + // [strings.compilerOptsAuto]: Specification( + // requirement: Requirement.no, + // validator: compilerOptsAutoValidator, + // extractor: compilerOptsAutoExtractor, + // defaultValue: () => CompilerOptsAuto(), + // extractedResult: (dynamic result) { + // _compilerOpts + // .addAll((result as CompilerOptsAuto).extractCompilerOpts()); + // }), + // [strings.functions]: Specification( + // requirement: Requirement.no, + // validator: declarationConfigValidator, + // extractor: declarationConfigExtractor, + // defaultValue: () => Declaration(), + // extractedResult: (dynamic result) { + // _functionDecl = result as Declaration; + // }, + // ), + // [strings.structs]: Specification( + // requirement: Requirement.no, + // validator: declarationConfigValidator, + // extractor: declarationConfigExtractor, + // defaultValue: () => Declaration(), + // extractedResult: (dynamic result) { + // _structDecl = result as Declaration; + // }, + // ), + // [strings.unions]: Specification( + // requirement: Requirement.no, + // validator: declarationConfigValidator, + // extractor: declarationConfigExtractor, + // defaultValue: () => Declaration(), + // extractedResult: (dynamic result) { + // _unionDecl = result as Declaration; + // }, + // ), + // [strings.enums]: Specification( + // requirement: Requirement.no, + // validator: declarationConfigValidator, + // extractor: declarationConfigExtractor, + // defaultValue: () => Declaration(), + // extractedResult: (dynamic result) { + // _enumClassDecl = result as Declaration; + // }, + // ), + // [strings.unnamedEnums]: Specification( + // requirement: Requirement.no, + // validator: declarationConfigValidator, + // extractor: declarationConfigExtractor, + // defaultValue: () => Declaration(), + // extractedResult: (dynamic result) => + // _unnamedEnumConstants = result as Declaration, + // ), + // [strings.globals]: Specification( + // requirement: Requirement.no, + // validator: declarationConfigValidator, + // extractor: declarationConfigExtractor, + // defaultValue: () => Declaration(), + // extractedResult: (dynamic result) { + // _globals = result as Declaration; + // }, + // ), + // [strings.macros]: Specification( + // requirement: Requirement.no, + // validator: declarationConfigValidator, + // extractor: declarationConfigExtractor, + // defaultValue: () => Declaration(), + // extractedResult: (dynamic result) { + // _macroDecl = result as Declaration; + // }, + // ), + // [strings.typedefs]: Specification( + // requirement: Requirement.no, + // validator: declarationConfigValidator, + // extractor: declarationConfigExtractor, + // defaultValue: () => Declaration(), + // extractedResult: (dynamic result) { + // _typedefs = result as Declaration; + // }, + // ), + // [strings.objcInterfaces]: Specification( + // requirement: Requirement.no, + // validator: declarationConfigValidator, + // extractor: declarationConfigExtractor, + // defaultValue: () => Declaration(), + // extractedResult: (dynamic result) { + // _objcInterfaces = result as Declaration; + // }, + // ), + // [strings.objcInterfaces, strings.objcModule]: + // Specification>( + // requirement: Requirement.no, + // validator: stringStringMapValidator, + // extractor: stringStringMapExtractor, + // defaultValue: () => {}, + // extractedResult: (dynamic result) => _objcModulePrefixer = + // ObjCModulePrefixer(result as Map), + // ), + // [strings.libraryImports]: Specification>( + // validator: libraryImportsValidator, + // extractor: libraryImportsExtractor, + // defaultValue: () => {}, + // extractedResult: (dynamic result) { + // _libraryImports = result as Map; + // }, + // ), + // [strings.import, strings.symbolFilesImport]: + // Specification>( + // validator: symbolFileImportValidator, + // extractor: (value) => symbolFileImportExtractor( + // value, _libraryImports, filename, packageConfig), + // defaultValue: () => {}, + // extractedResult: (dynamic result) { + // _usrTypeMappings = result as Map; + // }, + // ), + // [strings.typeMap, strings.typeMapTypedefs]: + // Specification>>( + // validator: typeMapValidator, + // extractor: typeMapExtractor, + // defaultValue: () => >{}, + // extractedResult: (dynamic result) { + // _typedefTypeMappings = makeImportTypeMapping( + // result as Map>, _libraryImports); + // }, + // ), + // [strings.typeMap, strings.typeMapStructs]: + // Specification>>( + // validator: typeMapValidator, + // extractor: typeMapExtractor, + // defaultValue: () => >{}, + // extractedResult: (dynamic result) { + // _structTypeMappings = makeImportTypeMapping( + // result as Map>, _libraryImports); + // }, + // ), + // [strings.typeMap, strings.typeMapUnions]: + // Specification>>( + // validator: typeMapValidator, + // extractor: typeMapExtractor, + // defaultValue: () => >{}, + // extractedResult: (dynamic result) { + // _unionTypeMappings = makeImportTypeMapping( + // result as Map>, _libraryImports); + // }, + // ), + // [strings.typeMap, strings.typeMapNativeTypes]: + // Specification>>( + // validator: typeMapValidator, + // extractor: typeMapExtractor, + // defaultValue: () => >{}, + // extractedResult: (dynamic result) { + // _nativeTypeMappings = makeImportTypeMapping( + // result as Map>, _libraryImports); + // }, + // ), + // [strings.functions, strings.varArgFunctions]: + // Specification>>( + // requirement: Requirement.no, + // validator: varArgFunctionConfigValidator, + // extractor: varArgFunctionConfigExtractor, + // defaultValue: () => >{}, + // extractedResult: (dynamic result) { + // _varArgFunctions = makeVarArgFunctionsMapping( + // result as Map>, _libraryImports); + // }, + // ), + // [strings.excludeAllByDefault]: Specification( + // requirement: Requirement.no, + // validator: booleanValidator, + // extractor: booleanExtractor, + // defaultValue: () => false, + // extractedResult: (dynamic result) => + // _excludeAllByDefault = result as bool, + // ), + // [strings.sort]: Specification( + // requirement: Requirement.no, + // validator: booleanValidator, + // extractor: booleanExtractor, + // defaultValue: () => false, + // extractedResult: (dynamic result) => _sort = result as bool, + // ), + // [strings.useSupportedTypedefs]: Specification( + // requirement: Requirement.no, + // validator: booleanValidator, + // extractor: booleanExtractor, + // defaultValue: () => true, + // extractedResult: (dynamic result) => + // _useSupportedTypedefs = result as bool, + // ), + // [strings.comments]: Specification( + // requirement: Requirement.no, + // validator: commentValidator, + // extractor: commentExtractor, + // defaultValue: () => CommentType.def(), + // extractedResult: (dynamic result) => + // _commentType = result as CommentType, + // ), + // [strings.structs, strings.dependencyOnly]: + // Specification( + // requirement: Requirement.no, + // validator: dependencyOnlyValidator, + // extractor: dependencyOnlyExtractor, + // defaultValue: () => CompoundDependencies.full, + // extractedResult: (dynamic result) => + // _structDependencies = result as CompoundDependencies, + // ), + // [strings.unions, strings.dependencyOnly]: + // Specification( + // requirement: Requirement.no, + // validator: dependencyOnlyValidator, + // extractor: dependencyOnlyExtractor, + // defaultValue: () => CompoundDependencies.full, + // extractedResult: (dynamic result) => + // _unionDependencies = result as CompoundDependencies, + // ), + // [strings.structs, strings.structPack]: + // Specification( + // requirement: Requirement.no, + // validator: structPackingOverrideValidator, + // extractor: structPackingOverrideExtractor, + // defaultValue: () => StructPackingOverride(), + // extractedResult: (dynamic result) => + // _structPackingOverride = result as StructPackingOverride, + // ), + // [strings.name]: Specification( + // requirement: Requirement.prefer, + // validator: dartClassNameValidator, + // extractor: stringExtractor, + // defaultValue: () => 'NativeLibrary', + // extractedResult: (dynamic result) => _wrapperName = result as String, + // ), + // [strings.description]: Specification( + // requirement: Requirement.prefer, + // validator: nonEmptyStringValidator, + // extractor: stringExtractor, + // defaultValue: () => null, + // extractedResult: (dynamic result) => + // _wrapperDocComment = result as String?, + // ), + // [strings.preamble]: Specification( + // requirement: Requirement.no, + // validator: nonEmptyStringValidator, + // extractor: stringExtractor, + // extractedResult: (dynamic result) => _preamble = result as String?, + // ), + // [strings.useDartHandle]: Specification( + // requirement: Requirement.no, + // validator: booleanValidator, + // extractor: booleanExtractor, + // defaultValue: () => true, + // extractedResult: (dynamic result) => _useDartHandle = result as bool, + // ), + // [strings.functions, strings.exposeFunctionTypedefs]: + // Specification( + // requirement: Requirement.no, + // validator: exposeFunctionTypeValidator, + // extractor: exposeFunctionTypeExtractor, + // defaultValue: () => Includer.excludeByDefault(), + // extractedResult: (dynamic result) => + // _exposeFunctionTypedefs = result as Includer, + // ), + // [strings.functions, strings.leafFunctions]: Specification( + // requirement: Requirement.no, + // validator: leafFunctionValidator, + // extractor: leafFunctionExtractor, + // defaultValue: () => Includer.excludeByDefault(), + // extractedResult: (dynamic result) => + // _leafFunctions = result as Includer, + // ), + // [strings.ffiNative]: Specification( + // requirement: Requirement.no, + // validator: ffiNativeValidator, + // extractor: ffiNativeExtractor, + // defaultValue: () => FfiNativeConfig(enabled: false), + // extractedResult: (dynamic result) => + // _ffiNativeConfig = result as FfiNativeConfig, + // ) + // }; + // } Schema getRootSchema() { return FixedMapSchema( From 478167ff4c1011dce470c996ef6ef2149f3889a3 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Sun, 18 Jun 2023 23:50:20 +0530 Subject: [PATCH 16/23] Fix config --- example/ffinative/config.yaml | 2 +- lib/src/config_provider/config.dart | 24 +++++++++++++++---- test/config_tests/unknown_keys_warn_test.dart | 11 --------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/example/ffinative/config.yaml b/example/ffinative/config.yaml index 449275f4..397dbba8 100644 --- a/example/ffinative/config.yaml +++ b/example/ffinative/config.yaml @@ -9,4 +9,4 @@ headers: entry-points: - 'headers/example.h' preamble: | - // ignore_for_file: deprecated_member_use \ No newline at end of file + // ignore_for_file: deprecated_member_use diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart index d72ba1f3..4b4fd887 100644 --- a/lib/src/config_provider/config.dart +++ b/lib/src/config_provider/config.dart @@ -593,9 +593,9 @@ class Config { keys: { strings.bindings: StringSchema(), strings.symbolFile: FixedMapSchema( - requiredKeys: [strings.name, strings.importPath], + requiredKeys: [strings.output, strings.importPath], keys: { - strings.name: StringSchema(), + strings.output: StringSchema(), strings.importPath: StringSchema() }, ) @@ -673,7 +673,10 @@ class Config { keyValueSchemas: [ ( keyRegexp: ".*", - valueSchema: ListSchema(childSchema: StringSchema()) + valueSchema: ListSchema>( + childSchema: + ListSchema(childSchema: StringSchema()), + ) ) ], defaultValue: (node) => >{}, @@ -705,7 +708,9 @@ class Config { ( keyRegexp: '.*', valueSchema: EnumSchema( - allowedValues: {null, 1, 2, 4, 8, 16}, + allowedValues: {'none', null, 1, 2, 4, 8, 16}, + transform: (node) => + node.value == 'none' ? null : node.value, ), ) ], @@ -905,7 +910,16 @@ class Config { defaultValue: (node) => true, result: (node) => _useDartHandle = node.value as bool, ), - strings.ffiNative: BoolSchema( + strings.ffiNative: OneOfSchema( + childSchemas: [ + EnumSchema(allowedValues: {null}), + FixedMapSchema( + requiredKeys: [strings.ffiNativeAsset], + keys: { + strings.ffiNativeAsset: StringSchema(), + }, + ) + ], transform: (node) => ffiNativeExtractor(node.rawValue), defaultValue: (node) => FfiNativeConfig(enabled: false), result: (node) => _ffiNativeConfig = (node.value) as FfiNativeConfig, diff --git a/test/config_tests/unknown_keys_warn_test.dart b/test/config_tests/unknown_keys_warn_test.dart index 3dd04517..6f80757f 100644 --- a/test/config_tests/unknown_keys_warn_test.dart +++ b/test/config_tests/unknown_keys_warn_test.dart @@ -28,12 +28,6 @@ ${strings.headers}: ${strings.typeMap}: 'warn-2': 'warn' 'warn-3': 'warn' -${strings.functions}: - 'warn-4': 'skip' -${strings.structs}: - 'warn-5': 'skip' -${strings.unions}: - 'warn-6': 'skip' '''); logString = logArr.join("\n"); }); @@ -42,10 +36,5 @@ ${strings.unions}: expect(logString.contains('warn-2'), true); expect(logString.contains('warn-3'), true); }); - test('Do not warn for unknown keys in declarations.', () { - expect(logString.contains('warn-4'), false); - expect(logString.contains('warn-5'), false); - expect(logString.contains('warn-6'), false); - }); }); } From b3963eece3069d51ad2687d7442c75a175f7658f Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Mon, 19 Jun 2023 00:16:49 +0530 Subject: [PATCH 17/23] Fix function->varArg config --- lib/src/config_provider/config.dart | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart index 4b4fd887..047ee50b 100644 --- a/lib/src/config_provider/config.dart +++ b/lib/src/config_provider/config.dart @@ -673,9 +673,20 @@ class Config { keyValueSchemas: [ ( keyRegexp: ".*", - valueSchema: ListSchema>( - childSchema: + valueSchema: ListSchema( + childSchema: OneOfSchema( + childSchemas: [ ListSchema(childSchema: StringSchema()), + FixedMapSchema( + requiredKeys: [strings.types], + keys: { + strings.types: + ListSchema(childSchema: StringSchema()), + strings.postfix: StringSchema(), + }, + ) + ], + ), ) ) ], From 0a2455624de8b9ee5d7d19153958a4ac97a10c14 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Mon, 19 Jun 2023 00:27:38 +0530 Subject: [PATCH 18/23] Remove null from structs->Pack --- lib/src/config_provider/config.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart index 047ee50b..6a12bc55 100644 --- a/lib/src/config_provider/config.dart +++ b/lib/src/config_provider/config.dart @@ -719,7 +719,7 @@ class Config { ( keyRegexp: '.*', valueSchema: EnumSchema( - allowedValues: {'none', null, 1, 2, 4, 8, 16}, + allowedValues: {'none', 1, 2, 4, 8, 16}, transform: (node) => node.value == 'none' ? null : node.value, ), From 27e2ea8dfbbc06a0350b703fd363f6d186a11b34 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Mon, 19 Jun 2023 01:53:04 +0530 Subject: [PATCH 19/23] Generate Json Schema from config, Add test to check its value. --- ffigen.schema.json | 541 ++++++++++++++---------- lib/src/config_provider/config.dart | 10 +- lib/src/config_provider/schema.dart | 59 ++- lib/src/strings.dart | 4 + test/config_tests/json_schema_test.dart | 26 ++ tool/generate_json_schema.dart | 26 ++ 6 files changed, 415 insertions(+), 251 deletions(-) create mode 100644 test/config_tests/json_schema_test.dart create mode 100644 tool/generate_json_schema.dart diff --git a/ffigen.schema.json b/ffigen.schema.json index b1770474..78e92d83 100644 --- a/ffigen.schema.json +++ b/ffigen.schema.json @@ -1,22 +1,39 @@ { "$id": "https://json.schemastore.org/ffigen", "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "Configuration for generating dart ffi bindings via ffigen", "type": "object", "properties": { + "llvm-path": { + "type": "array", + "items": { + "type": "string" + } + }, "output": { - "oneOf": [ + "$oneOf": [ { - "$ref": "#/$defs/outputBindings" + "type": "string" }, { "type": "object", "properties": { "bindings": { - "$ref": "#/$defs/outputBindings" + "type": "string" }, "symbol-file": { - "$ref": "#/$defs/outputSymbolFile" + "type": "object", + "properties": { + "output": { + "type": "string" + }, + "import-path": { + "type": "string" + } + }, + "required": [ + "output", + "import-path" + ] } }, "required": [ @@ -25,26 +42,22 @@ } ] }, - "llvm-path": { - "description": "Path to llvm folder or the libclang dynamic library.", - "type": "array", - "items": { - "type": "string" - } + "language": { + "enum": [ + "c", + "objc" + ] }, "headers": { - "description": "Input header files", "type": "object", "properties": { "entry-points": { - "description": "Header entry-points to start parsing C files. Supports Glob syntax.", "type": "array", "items": { "type": "string" } }, "include-directives": { - "description": "Header include-directives from which declarations to generate. Supports Glob syntax.", "type": "array", "items": { "type": "string" @@ -55,23 +68,20 @@ "entry-points" ] }, - "name": { - "description": "Name of generated class.", - "type": "string" - }, - "description": { - "description": "Dart Doc for generated class.", - "type": "string" - }, - "compilerOpts": { - "description": "Pass compiler options to clang.", - "type": "array", - "items": { - "type": "string" - } + "compiler-opts": { + "$oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] }, - "compilerOptsAutomatic": { - "description": "Tries to automatically find and add C standard library path to compiler-opts on macos", + "compiler-opts-automatic": { "type": "object", "properties": { "macos": { @@ -84,64 +94,96 @@ } } }, - "functions": { - "allOf": [ - { - "$ref": "#/$defs/includeExcludeRenameProperties" + "library-imports": { + "type": "object", + "patternProperties": { + ".*": { + "type": "string" } - ], + } + }, + "functions": { "type": "object", "properties": { + "include": { + "$ref": "#/$defs/include" + }, + "exclude": { + "$ref": "#/$defs/exclude" + }, + "rename": { + "$ref": "#/$defs/rename" + }, "symbol-address": { - "$ref": "#/$defs/includeExcludeProperties" + "$ref": "#/$defs/includeExclude" }, "expose-typedefs": { - "$ref": "#/$defs/includeExcludeProperties" + "$ref": "#/$defs/includeExclude" }, "leaf": { - "$ref": "#/$defs/includeExcludeProperties" - } - } - }, - "typedefs": { - "$ref": "#/$defs/includeExcludeRenameProperties" - }, - "unnamed-enums": { - "$ref": "#/$defs/includeExcludeRenameProperties" - }, - "macros": { - "$ref": "#/$defs/includeExcludeRenameProperties" - }, - "globals": { - "allOf": [ - { - "$ref": "#/$defs/includeExcludeRenameProperties" - } - ], - "type": "object", - "properties": { - "symbol-address": { - "$ref": "#/$defs/includeExcludeProperties" + "$ref": "#/$defs/includeExclude" + }, + "variadic-arguments": { + "type": "object", + "patternProperties": { + ".*": { + "type": "array", + "items": { + "$oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "properties": { + "types": { + "type": "array", + "items": { + "type": "string" + } + }, + "postfix": { + "type": "string" + } + }, + "required": [ + "types" + ] + } + ] + } + } + } } } }, - "enums": { - "$ref": "#/$defs/includeExcludeRenameMemberProperties" - }, "structs": { - "allOf": [ - { - "$ref": "#/$defs/compound" - } - ], "type": "object", "properties": { + "include": { + "$ref": "#/$defs/include" + }, + "exclude": { + "$ref": "#/$defs/exclude" + }, + "rename": { + "$ref": "#/$defs/rename" + }, + "member-rename": { + "$ref": "#/$defs/memberRename" + }, + "dependency-only": { + "$ref": "#/$defs/dependencyOnly" + }, "pack": { "type": "object", "patternProperties": { ".*": { "enum": [ - null, + "none", 1, 2, 4, @@ -154,90 +196,119 @@ } }, "unions": { - "$ref": "#/$defs/compound" - }, - "comments": { - "description": "Extract documentation comments for declarations.", - "anyOf": [ - { - "type": "object", - "properties": { - "style": { - "enum": [ - "doxygen", - "any" - ] - }, - "length": { - "enum": [ - "brief", - "full" - ] - } - } + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - { - "type": "boolean" + "exclude": { + "$ref": "#/$defs/exclude" + }, + "rename": { + "$ref": "#/$defs/rename" + }, + "member-rename": { + "$ref": "#/$defs/memberRename" + }, + "dependency-only": { + "$ref": "#/$defs/dependencyOnly" } - ] - }, - "sort": { - "description": "Sort the bindings according to name.", - "type": "boolean" - }, - "use-supported-typedefs": { - "description": "Should automatically map typedefs, E.g uint8_t => Uint8, int16_t => Int16, size_t => Size etc", - "type": "boolean" - }, - "use-dart-handle": { - "description": "Should map `Dart_Handle` to `Handle`.", - "type": "boolean" - }, - "exclude-all-by-default": { - "description": "When a declaration filter (eg `functions:` or `structs:`) is empty or unset, it defaults to including everything. If this flag is enabled, the default behavior is to exclude everything instead.", - "type": "boolean" + } }, - "preamble": { - "description": "Raw header of the file, pasted as-it-is.", - "type": "string" + "enums": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" + }, + "exclude": { + "$ref": "#/$defs/exclude" + }, + "rename": { + "$ref": "#/$defs/rename" + }, + "member-rename": { + "$ref": "#/$defs/memberRename" + } + } }, - "library-imports": { - "description": "Specify library imports for use in type-map.", - "type": "object" + "unnamed-enums": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" + }, + "exclude": { + "$ref": "#/$defs/exclude" + }, + "rename": { + "$ref": "#/$defs/rename" + } + } }, - "type-map": { - "description": "Map types like integers, typedefs, structs, unions to any other type.", + "globals": { "type": "object", "properties": { - "native-types": { - "$ref": "#/$defs/mappedTypes" + "include": { + "$ref": "#/$defs/include" }, - "typedefs": { - "$ref": "#/$defs/mappedTypes" + "exclude": { + "$ref": "#/$defs/exclude" }, - "structs": { - "$ref": "#/$defs/mappedTypes" + "rename": { + "$ref": "#/$defs/rename" + } + } + }, + "macros": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "unions": { - "$ref": "#/$defs/mappedTypes" + "exclude": { + "$ref": "#/$defs/exclude" + }, + "rename": { + "$ref": "#/$defs/rename" } } }, - "ffi-native": { + "typedefs": { + "type": "object", "properties": { - "assets": { - "asset": "string" + "include": { + "$ref": "#/$defs/include" + }, + "exclude": { + "$ref": "#/$defs/exclude" + }, + "rename": { + "$ref": "#/$defs/rename" } } }, - "language": { - "enum": [ - "c", - "objc" - ] + "objc-interfaces": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" + }, + "exclude": { + "$ref": "#/$defs/exclude" + }, + "rename": { + "$ref": "#/$defs/rename" + }, + "member-rename": { + "$ref": "#/$defs/memberRename" + }, + "module": { + "$ref": "#/$defs/objcInterfaceModule" + } + } }, "import": { - "description": "Import symbols from a symbol file.", "type": "object", "properties": { "symbol-files": { @@ -248,24 +319,87 @@ } } }, - "objc-interfaces": { - "allOf": [ - { - "$ref": "#/$defs/includeExcludeRenameProperties" - } - ], + "type-map": { "type": "object", "properties": { - "module": { - "description": "Adds a module prefix to the class name when loading the class from the dylib. This is only relevent for ObjC headers that are generated wrappers for a Swift library.", + "typedefs": { + "$ref": "#/$defs/mappedTypes" + }, + "structs": { + "$ref": "#/$defs/mappedTypes" + }, + "unions": { + "$ref": "#/$defs/mappedTypes" + }, + "native-types": { + "$ref": "#/$defs/mappedTypes" + } + } + }, + "exclude-all-by-default": { + "type": "boolean" + }, + "sort": { + "type": "boolean" + }, + "use-supported-typedefs": { + "type": "boolean" + }, + "comments": { + "$oneOf": [ + { + "type": "boolean" + }, + { "type": "object", - "patternProperties": { - ".*": { - "type": "string" + "properties": { + "style": { + "enum": [ + "doxygen", + "any" + ] + }, + "length": { + "enum": [ + "brief", + "full" + ] } } } - } + ] + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "preamble": { + "type": "string" + }, + "use-dart-handle": { + "type": "boolean" + }, + "ffi-native": { + "$oneOf": [ + { + "enum": [ + null + ] + }, + { + "type": "object", + "properties": { + "asset": { + "type": "string" + } + }, + "required": [ + "asset" + ] + } + ] } }, "required": [ @@ -273,111 +407,61 @@ "headers" ], "$defs": { - "outputBindings": { - "description": "Output path of the generated bindings.", - "type": "string" + "include": { + "type": "array", + "items": { + "type": "string" + } + }, + "exclude": { + "type": "array", + "items": { + "type": "string" + } }, - "outputSymbolFile": { - "description": "Generates a symbol file yaml containing all types defined in the generated output.", + "rename": { "type": "object", - "properties": { - "output": { - "description": "Output path of the generated symbol file.", - "type": "string" - }, - "import-path": { - "description": "Import path for the dart bindings symbols.", + "patternProperties": { + ".+": { "type": "string" } } }, - "includeExcludeProperties": { + "includeExclude": { "type": "object", "properties": { "include": { - "description": "Match declarations to include. Supports Regexps.", - "type": "array", - "items": { - "type": "string", - "format": "regex" - } + "$ref": "#/$defs/include" }, "exclude": { - "description": "Match declarations to exclude (overrides include). Supports Regexps.", - "type": "array", - "items": { - "type": "string", - "format": "regex" - } - } - } - }, - "renameProperties": { - "type": "object", - "properties": { - "rename": { - "description": "Match and rename declarations. Supports Regexps group based replacement.", - "type": "object", - "patternProperties": { - ".+": { - "type": "string", - "format": "regex" - } - } + "$ref": "#/$defs/exclude" } } }, - "memberRenameProperties": { + "memberRename": { "type": "object", - "properties": { - "member-rename": { - "description": "Match and rename declaration members. Supports Regexps group based replacement.", + "patternProperties": { + ".+": { "type": "object", "patternProperties": { ".+": { - "type": "string", - "format": "regex" + "type": "string" } } } } }, - "includeExcludeRenameProperties": { - "allOf": [ - { - "$ref": "#/$defs/includeExcludeProperties" - }, - { - "$ref": "#/$defs/renameProperties" - } - ] - }, - "includeExcludeRenameMemberProperties": { - "allOf": [ - { - "$ref": "#/$defs/includeExcludeProperties" - }, - { - "$ref": "#/$defs/renameProperties" - }, - { - "$ref": "#/$defs/memberRenameProperties" - } + "dependencyOnly": { + "enum": [ + "full", + "opaque" ] }, - "compound": { - "allOf": [ - { - "$ref": "#/$defs/includeExcludeRenameMemberProperties" - } - ], + "objcInterfaceModule": { "type": "object", - "properties": { - "dependency-only": { - "enum": [ - "full", - "opaque" - ] + "patternProperties": { + ".*": { + "type": "string" } } }, @@ -396,7 +480,12 @@ "dart-type": { "type": "string" } - } + }, + "required": [ + "lib", + "c-type", + "dart-type" + ] } } } diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart index 6a12bc55..d62198aa 100644 --- a/lib/src/config_provider/config.dart +++ b/lib/src/config_provider/config.dart @@ -185,7 +185,7 @@ class Config { final configspecs = Config._(filename, packageConfig); _logger.finest('Config Map: $map'); - final ffigenSchema = configspecs.getRootSchema(); + final ffigenSchema = configspecs._getRootSchema(); final result = ffigenSchema.validate(map); if (!result) { throw FormatException('Invalid configurations provided.'); @@ -204,6 +204,12 @@ class Config { filename: file.path, packageConfig: packageConfig); } + /// Returns the root Schema object. + static Schema getsRootSchema() { + final configspecs = Config._(null, null); + return configspecs._getRootSchema(); + } + /// Add compiler options for clang. If [highPriority] is true these are added /// to the front of the list. void addCompilerOpts(String compilerOpts, {bool highPriority = false}) { @@ -575,7 +581,7 @@ class Config { // }; // } - Schema getRootSchema() { + Schema _getRootSchema() { return FixedMapSchema( requiredKeys: [strings.output, strings.headers], keys: { diff --git a/lib/src/config_provider/schema.dart b/lib/src/config_provider/schema.dart index fbb38ef1..8ac5b044 100644 --- a/lib/src/config_provider/schema.dart +++ b/lib/src/config_provider/schema.dart @@ -118,7 +118,26 @@ abstract class Schema { SchemaNode extractNode(SchemaNode o); - Map generateJsonSchema(Map defs); + Map generateJsonSchemaNode(Map defs); + + Map getJsonRefOrSchemaNode(Map defs) { + if (schemaDefName == null) { + return generateJsonSchemaNode(defs); + } + defs.putIfAbsent(schemaDefName!, () => generateJsonSchemaNode(defs)); + return {r"$ref": "#/\$defs/$schemaDefName"}; + } + + Map generateJsonSchema(String schemaId) { + final defs = {}; + final schemaMap = generateJsonSchemaNode(defs); + return { + r"$id": schemaId, + r"$schema": "https://json-schema.org/draft/2020-12/schema", + ...schemaMap, + r"$defs": defs, + }; + } /// Returns default value or null for a node. Calls [result] if value is /// not null. @@ -128,14 +147,6 @@ abstract class Schema { return v; } - Map getRefOrSchema(Map defs) { - if (schemaDefName == null) { - return generateJsonSchema(defs); - } - defs.putIfAbsent(schemaDefName!, () => generateJsonSchema(defs)); - return {r"$ref": "#/\$defs/$schemaDefName"}; - } - /// Run validation on an object [value]. bool validate(dynamic value) { return validateNode(SchemaNode(path: [], value: value)); @@ -267,13 +278,14 @@ class FixedMapSchema extends Schema> { } @override - Map generateJsonSchema(Map defs) { + Map generateJsonSchemaNode(Map defs) { return { "type": "object", if (schemaDescription != null) "description": schemaDescription!, if (keys.isNotEmpty) "properties": { - for (final kv in keys.entries) kv.key: kv.value.getRefOrSchema(defs) + for (final kv in keys.entries) + kv.key: kv.value.getJsonRefOrSchemaNode(defs) }, if (requiredKeys.isNotEmpty) "required": requiredKeys, }; @@ -373,7 +385,7 @@ class DynamicMapSchema extends Schema> { } @override - Map generateJsonSchema(Map defs) { + Map generateJsonSchemaNode(Map defs) { return { "type": "object", if (schemaDescription != null) "description": schemaDescription!, @@ -381,7 +393,7 @@ class DynamicMapSchema extends Schema> { "patternProperties": { for (final (keyRegexp: keyRegexp, valueSchema: valueSchema) in keyValueSchemas) - keyRegexp: valueSchema.getRefOrSchema(defs) + keyRegexp: valueSchema.getJsonRefOrSchemaNode(defs) } }; } @@ -439,11 +451,11 @@ class ListSchema extends Schema> { } @override - Map generateJsonSchema(Map defs) { + Map generateJsonSchemaNode(Map defs) { return { "type": "array", if (schemaDescription != null) "description": schemaDescription!, - "items": childSchema.getRefOrSchema(defs), + "items": childSchema.getJsonRefOrSchemaNode(defs), }; } } @@ -477,7 +489,7 @@ class StringSchema extends Schema { } @override - Map generateJsonSchema(Map defs) { + Map generateJsonSchemaNode(Map defs) { return { "type": "string", if (schemaDescription != null) "description": schemaDescription!, @@ -514,7 +526,7 @@ class IntSchema extends Schema { } @override - Map generateJsonSchema(Map defs) { + Map generateJsonSchemaNode(Map defs) { return { "type": "integer", if (schemaDescription != null) "description": schemaDescription!, @@ -557,7 +569,7 @@ class EnumSchema extends Schema { } @override - Map generateJsonSchema(Map defs) { + Map generateJsonSchemaNode(Map defs) { return { "enum": allowedValues.toList(), if (schemaDescription != null) "description": schemaDescription!, @@ -594,7 +606,7 @@ class BoolSchema extends Schema { } @override - Map generateJsonSchema(Map defs) { + Map generateJsonSchemaNode(Map defs) { return { "type": "boolean", if (schemaDescription != null) "description": schemaDescription!, @@ -649,11 +661,12 @@ class OneOfSchema extends Schema { } @override - Map generateJsonSchema(Map defs) { + Map generateJsonSchemaNode(Map defs) { return { if (schemaDescription != null) "description": schemaDescription!, - r"$oneOf": - childSchemas.map((child) => child.getRefOrSchema(defs)).toList(), + r"$oneOf": childSchemas + .map((child) => child.getJsonRefOrSchemaNode(defs)) + .toList(), }; } } @@ -760,7 +773,7 @@ structs: print("extract: ${testSchema.extract(yaml).value}"); print("extractMap: $extractMap"); final defs = {}; - final jsonSchema = testSchema.generateJsonSchema(defs); + final jsonSchema = testSchema.generateJsonSchemaNode(defs); print("jsonschema object: $jsonSchema"); print("defs: $defs"); final jsonSchemaJson = jsonEncode({ diff --git a/lib/src/strings.dart b/lib/src/strings.dart index 245dd7c4..8d4b4cb9 100644 --- a/lib/src/strings.dart +++ b/lib/src/strings.dart @@ -277,3 +277,7 @@ String get tmpDir { _tmpDir ??= Directory.systemTemp.createTempSync(); return _tmpDir!.path; } + +const ffigenJsonSchemaIndent = ' '; +const ffigenJsonSchemaId = "https://json.schemastore.org/ffigen"; +const ffigenJsonSchemaFileName = "ffigen.schema.json"; diff --git a/test/config_tests/json_schema_test.dart b/test/config_tests/json_schema_test.dart new file mode 100644 index 00000000..26698242 --- /dev/null +++ b/test/config_tests/json_schema_test.dart @@ -0,0 +1,26 @@ +// Copyright (c) 2023, 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:convert'; +import 'dart:io'; + +import 'package:ffigen/ffigen.dart'; +import 'package:ffigen/src/strings.dart' as strings; +import 'package:test/test.dart'; + +late Library actual, expected; + +void main() { + group('json_schema_test', () { + test('Schema Changes', () { + final actualJsonSchema = + JsonEncoder.withIndent(strings.ffigenJsonSchemaIndent).convert( + Config.getsRootSchema().generateJsonSchema(strings.ffigenJsonSchemaId), + ); + final expectedJsonSchema = + File(strings.ffigenJsonSchemaFileName).readAsStringSync(); + expect(actualJsonSchema, expectedJsonSchema); + }); + }); +} diff --git a/tool/generate_json_schema.dart b/tool/generate_json_schema.dart new file mode 100644 index 00000000..41bb398e --- /dev/null +++ b/tool/generate_json_schema.dart @@ -0,0 +1,26 @@ +// Copyright (c) 2023, 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. + +// ================== GENERATING JSON SCHEMA ===================== +// cd to project's root, and run - +// dart generate_json_schema.dart +// =============================================================== +import 'dart:convert'; +import 'dart:io'; + +import 'package:ffigen/ffigen.dart'; +import 'package:ffigen/src/strings.dart' as strings; + +void main() async { + final actualJsonSchema = + JsonEncoder.withIndent(strings.ffigenJsonSchemaIndent).convert( + Config.getsRootSchema().generateJsonSchema(strings.ffigenJsonSchemaId), + ); + + final file = File(strings.ffigenJsonSchemaFileName); + if (!await file.exists()) { + throw Exception("File '${file.absolute.path}' does not exist."); + } + await file.writeAsString(actualJsonSchema); +} From 06a73a95d7deecead00c051facea184f1bcc3f1d Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Mon, 19 Jun 2023 02:43:27 +0530 Subject: [PATCH 20/23] Remove most old dead code, add TODOs --- lib/src/config_provider/config.dart | 406 ++--------------- lib/src/config_provider/spec_utils.dart | 556 ++---------------------- 2 files changed, 60 insertions(+), 902 deletions(-) diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart index d62198aa..7d7a6216 100644 --- a/lib/src/config_provider/config.dart +++ b/lib/src/config_provider/config.dart @@ -221,373 +221,13 @@ class Config { } } - /// Validates Yaml according to given specs. - // bool _checkConfigs(YamlMap map, Map, Specification> specs) { - // var result = true; - // for (final key in specs.keys) { - // final spec = specs[key]; - // if (checkKeyInYaml(key, map)) { - // result = result && spec!.validator(key, getKeyValueFromYaml(key, map)); - // } else if (spec!.requirement == Requirement.yes) { - // _logger.severe("Key '$key' is required."); - // result = false; - // } else if (spec.requirement == Requirement.prefer) { - // _logger.warning("Prefer adding Key '$key' to your config."); - // } - // } - // // Warn about unknown keys. - // warnUnknownKeys(specs.keys.toList(), map); - - // return result; - // } - - /// Extracts variables from Yaml according to given specs. - /// - /// Validation must be done beforehand, using [_checkConfigs]. - // void _extract(YamlMap map, Map, Specification> specs) { - // for (final key in specs.keys) { - // final spec = specs[key]; - // if (checkKeyInYaml(key, map)) { - // spec!.extractedResult(spec.extractor(getKeyValueFromYaml(key, map))); - // } else { - // spec!.extractedResult(spec.defaultValue?.call()); - // } - // } - // } - - /// Returns map of various specifications avaialble for our tool. - /// - /// Key: Name, Value: [Specification] - // Map, Specification> _getSpecs() { - // return , Specification>{ - // [strings.llvmPath]: Specification( - // requirement: Requirement.no, - // validator: llvmPathValidator, - // extractor: llvmPathExtractor, - // defaultValue: () => findDylibAtDefaultLocations(), - // extractedResult: (dynamic result) { - // _libclangDylib = result as String; - // }, - // ), - // [strings.output]: Specification( - // requirement: Requirement.yes, - // validator: outputValidator, - // extractor: (dynamic value) => - // outputExtractor(value, filename, packageConfig), - // extractedResult: (dynamic result) { - // _output = (result as OutputConfig).output; - // _symbolFile = result.symbolFile; - // }, - // ), - // [strings.language]: Specification( - // requirement: Requirement.no, - // validator: languageValidator, - // extractor: languageExtractor, - // defaultValue: () => Language.c, - // extractedResult: (dynamic result) => _language = result as Language, - // ), - // [strings.headers]: Specification( - // requirement: Requirement.yes, - // validator: headersValidator, - // extractor: (dynamic value) => headersExtractor(value, filename), - // extractedResult: (dynamic result) => _headers = result as Headers, - // ), - // [strings.compilerOpts]: Specification>( - // requirement: Requirement.no, - // validator: compilerOptsValidator, - // extractor: compilerOptsExtractor, - // defaultValue: () => [], - // extractedResult: (dynamic result) => - // _compilerOpts = result as List, - // ), - // [strings.compilerOptsAuto]: Specification( - // requirement: Requirement.no, - // validator: compilerOptsAutoValidator, - // extractor: compilerOptsAutoExtractor, - // defaultValue: () => CompilerOptsAuto(), - // extractedResult: (dynamic result) { - // _compilerOpts - // .addAll((result as CompilerOptsAuto).extractCompilerOpts()); - // }), - // [strings.functions]: Specification( - // requirement: Requirement.no, - // validator: declarationConfigValidator, - // extractor: declarationConfigExtractor, - // defaultValue: () => Declaration(), - // extractedResult: (dynamic result) { - // _functionDecl = result as Declaration; - // }, - // ), - // [strings.structs]: Specification( - // requirement: Requirement.no, - // validator: declarationConfigValidator, - // extractor: declarationConfigExtractor, - // defaultValue: () => Declaration(), - // extractedResult: (dynamic result) { - // _structDecl = result as Declaration; - // }, - // ), - // [strings.unions]: Specification( - // requirement: Requirement.no, - // validator: declarationConfigValidator, - // extractor: declarationConfigExtractor, - // defaultValue: () => Declaration(), - // extractedResult: (dynamic result) { - // _unionDecl = result as Declaration; - // }, - // ), - // [strings.enums]: Specification( - // requirement: Requirement.no, - // validator: declarationConfigValidator, - // extractor: declarationConfigExtractor, - // defaultValue: () => Declaration(), - // extractedResult: (dynamic result) { - // _enumClassDecl = result as Declaration; - // }, - // ), - // [strings.unnamedEnums]: Specification( - // requirement: Requirement.no, - // validator: declarationConfigValidator, - // extractor: declarationConfigExtractor, - // defaultValue: () => Declaration(), - // extractedResult: (dynamic result) => - // _unnamedEnumConstants = result as Declaration, - // ), - // [strings.globals]: Specification( - // requirement: Requirement.no, - // validator: declarationConfigValidator, - // extractor: declarationConfigExtractor, - // defaultValue: () => Declaration(), - // extractedResult: (dynamic result) { - // _globals = result as Declaration; - // }, - // ), - // [strings.macros]: Specification( - // requirement: Requirement.no, - // validator: declarationConfigValidator, - // extractor: declarationConfigExtractor, - // defaultValue: () => Declaration(), - // extractedResult: (dynamic result) { - // _macroDecl = result as Declaration; - // }, - // ), - // [strings.typedefs]: Specification( - // requirement: Requirement.no, - // validator: declarationConfigValidator, - // extractor: declarationConfigExtractor, - // defaultValue: () => Declaration(), - // extractedResult: (dynamic result) { - // _typedefs = result as Declaration; - // }, - // ), - // [strings.objcInterfaces]: Specification( - // requirement: Requirement.no, - // validator: declarationConfigValidator, - // extractor: declarationConfigExtractor, - // defaultValue: () => Declaration(), - // extractedResult: (dynamic result) { - // _objcInterfaces = result as Declaration; - // }, - // ), - // [strings.objcInterfaces, strings.objcModule]: - // Specification>( - // requirement: Requirement.no, - // validator: stringStringMapValidator, - // extractor: stringStringMapExtractor, - // defaultValue: () => {}, - // extractedResult: (dynamic result) => _objcModulePrefixer = - // ObjCModulePrefixer(result as Map), - // ), - // [strings.libraryImports]: Specification>( - // validator: libraryImportsValidator, - // extractor: libraryImportsExtractor, - // defaultValue: () => {}, - // extractedResult: (dynamic result) { - // _libraryImports = result as Map; - // }, - // ), - // [strings.import, strings.symbolFilesImport]: - // Specification>( - // validator: symbolFileImportValidator, - // extractor: (value) => symbolFileImportExtractor( - // value, _libraryImports, filename, packageConfig), - // defaultValue: () => {}, - // extractedResult: (dynamic result) { - // _usrTypeMappings = result as Map; - // }, - // ), - // [strings.typeMap, strings.typeMapTypedefs]: - // Specification>>( - // validator: typeMapValidator, - // extractor: typeMapExtractor, - // defaultValue: () => >{}, - // extractedResult: (dynamic result) { - // _typedefTypeMappings = makeImportTypeMapping( - // result as Map>, _libraryImports); - // }, - // ), - // [strings.typeMap, strings.typeMapStructs]: - // Specification>>( - // validator: typeMapValidator, - // extractor: typeMapExtractor, - // defaultValue: () => >{}, - // extractedResult: (dynamic result) { - // _structTypeMappings = makeImportTypeMapping( - // result as Map>, _libraryImports); - // }, - // ), - // [strings.typeMap, strings.typeMapUnions]: - // Specification>>( - // validator: typeMapValidator, - // extractor: typeMapExtractor, - // defaultValue: () => >{}, - // extractedResult: (dynamic result) { - // _unionTypeMappings = makeImportTypeMapping( - // result as Map>, _libraryImports); - // }, - // ), - // [strings.typeMap, strings.typeMapNativeTypes]: - // Specification>>( - // validator: typeMapValidator, - // extractor: typeMapExtractor, - // defaultValue: () => >{}, - // extractedResult: (dynamic result) { - // _nativeTypeMappings = makeImportTypeMapping( - // result as Map>, _libraryImports); - // }, - // ), - // [strings.functions, strings.varArgFunctions]: - // Specification>>( - // requirement: Requirement.no, - // validator: varArgFunctionConfigValidator, - // extractor: varArgFunctionConfigExtractor, - // defaultValue: () => >{}, - // extractedResult: (dynamic result) { - // _varArgFunctions = makeVarArgFunctionsMapping( - // result as Map>, _libraryImports); - // }, - // ), - // [strings.excludeAllByDefault]: Specification( - // requirement: Requirement.no, - // validator: booleanValidator, - // extractor: booleanExtractor, - // defaultValue: () => false, - // extractedResult: (dynamic result) => - // _excludeAllByDefault = result as bool, - // ), - // [strings.sort]: Specification( - // requirement: Requirement.no, - // validator: booleanValidator, - // extractor: booleanExtractor, - // defaultValue: () => false, - // extractedResult: (dynamic result) => _sort = result as bool, - // ), - // [strings.useSupportedTypedefs]: Specification( - // requirement: Requirement.no, - // validator: booleanValidator, - // extractor: booleanExtractor, - // defaultValue: () => true, - // extractedResult: (dynamic result) => - // _useSupportedTypedefs = result as bool, - // ), - // [strings.comments]: Specification( - // requirement: Requirement.no, - // validator: commentValidator, - // extractor: commentExtractor, - // defaultValue: () => CommentType.def(), - // extractedResult: (dynamic result) => - // _commentType = result as CommentType, - // ), - // [strings.structs, strings.dependencyOnly]: - // Specification( - // requirement: Requirement.no, - // validator: dependencyOnlyValidator, - // extractor: dependencyOnlyExtractor, - // defaultValue: () => CompoundDependencies.full, - // extractedResult: (dynamic result) => - // _structDependencies = result as CompoundDependencies, - // ), - // [strings.unions, strings.dependencyOnly]: - // Specification( - // requirement: Requirement.no, - // validator: dependencyOnlyValidator, - // extractor: dependencyOnlyExtractor, - // defaultValue: () => CompoundDependencies.full, - // extractedResult: (dynamic result) => - // _unionDependencies = result as CompoundDependencies, - // ), - // [strings.structs, strings.structPack]: - // Specification( - // requirement: Requirement.no, - // validator: structPackingOverrideValidator, - // extractor: structPackingOverrideExtractor, - // defaultValue: () => StructPackingOverride(), - // extractedResult: (dynamic result) => - // _structPackingOverride = result as StructPackingOverride, - // ), - // [strings.name]: Specification( - // requirement: Requirement.prefer, - // validator: dartClassNameValidator, - // extractor: stringExtractor, - // defaultValue: () => 'NativeLibrary', - // extractedResult: (dynamic result) => _wrapperName = result as String, - // ), - // [strings.description]: Specification( - // requirement: Requirement.prefer, - // validator: nonEmptyStringValidator, - // extractor: stringExtractor, - // defaultValue: () => null, - // extractedResult: (dynamic result) => - // _wrapperDocComment = result as String?, - // ), - // [strings.preamble]: Specification( - // requirement: Requirement.no, - // validator: nonEmptyStringValidator, - // extractor: stringExtractor, - // extractedResult: (dynamic result) => _preamble = result as String?, - // ), - // [strings.useDartHandle]: Specification( - // requirement: Requirement.no, - // validator: booleanValidator, - // extractor: booleanExtractor, - // defaultValue: () => true, - // extractedResult: (dynamic result) => _useDartHandle = result as bool, - // ), - // [strings.functions, strings.exposeFunctionTypedefs]: - // Specification( - // requirement: Requirement.no, - // validator: exposeFunctionTypeValidator, - // extractor: exposeFunctionTypeExtractor, - // defaultValue: () => Includer.excludeByDefault(), - // extractedResult: (dynamic result) => - // _exposeFunctionTypedefs = result as Includer, - // ), - // [strings.functions, strings.leafFunctions]: Specification( - // requirement: Requirement.no, - // validator: leafFunctionValidator, - // extractor: leafFunctionExtractor, - // defaultValue: () => Includer.excludeByDefault(), - // extractedResult: (dynamic result) => - // _leafFunctions = result as Includer, - // ), - // [strings.ffiNative]: Specification( - // requirement: Requirement.no, - // validator: ffiNativeValidator, - // extractor: ffiNativeExtractor, - // defaultValue: () => FfiNativeConfig(enabled: false), - // extractedResult: (dynamic result) => - // _ffiNativeConfig = result as FfiNativeConfig, - // ) - // }; - // } - Schema _getRootSchema() { return FixedMapSchema( requiredKeys: [strings.output, strings.headers], keys: { strings.llvmPath: ListSchema( childSchema: StringSchema(), - transform: (node) => llvmPathExtractor(YamlList.wrap(node.value)), + transform: (node) => llvmPathExtractor(node.value), defaultValue: (node) => findDylibAtDefaultLocations(), result: (node) => _libclangDylib = node.value as String, ), @@ -609,7 +249,7 @@ class Config { ) ], transform: (node) => - outputExtractor(node.rawValue, filename, packageConfig), + outputExtractor(node.value, filename, packageConfig), result: (node) { _output = (node.value as OutputConfig).output; _symbolFile = (node.value as OutputConfig).symbolFile; @@ -617,8 +257,16 @@ class Config { ), strings.language: EnumSchema( allowedValues: {strings.langC, strings.langObjC}, - transform: (node) => - (node.value == strings.langObjC) ? Language.objc : Language.c, + transform: (node) { + if ((node.value == strings.langObjC)) { + _logger.severe( + 'Objective C support is EXPERIMENTAL. The API may change ' + 'in a breaking way without notice.'); + return Language.objc; + } else { + return Language.c; + } + }, defaultValue: (node) => Language.c, result: (node) => _language = node.value as Language, ), @@ -630,7 +278,7 @@ class Config { strings.includeDirectives: ListSchema(childSchema: StringSchema()), }, - transform: (node) => headersExtractor(node.rawValue, filename), + transform: (node) => headersExtractor(node.value, filename), result: (node) => _headers = node.value as Headers, ), strings.compilerOpts: OneOfSchema( @@ -638,7 +286,7 @@ class Config { StringSchema(), ListSchema(childSchema: StringSchema()) ], - transform: (node) => compilerOptsExtractor(node.rawValue), + transform: (node) => compilerOptsExtractor(node.value), defaultValue: (node) => [], result: (node) => _compilerOpts = node.value as List, ), @@ -646,20 +294,25 @@ class Config { keys: { strings.macos: FixedMapSchema( keys: { - strings.includeCStdLib: BoolSchema(), + strings.includeCStdLib: BoolSchema( + defaultValue: (node) => true, + ), }, ) }, - transform: (node) => compilerOptsAutoExtractor(node.rawValue), - defaultValue: (node) => CompilerOptsAuto(), + transform: (node) => CompilerOptsAuto( + macIncludeStdLib: + (node.value)[strings.macos][strings.includeCStdLib] as bool, + ), result: (node) => _compilerOpts .addAll((node.value as CompilerOptsAuto).extractCompilerOpts()), ), + // TODO: needs custom validation like libraryImportsValidator strings.libraryImports: DynamicMapSchema( keyValueSchemas: [ (keyRegexp: ".*", valueSchema: StringSchema()), ], - transform: (node) => libraryImportsExtractor(node.rawValue), + transform: (node) => libraryImportsExtractor(node.value.cast()), defaultValue: (node) => {}, result: (node) => _libraryImports = (node.value) as Map, @@ -697,7 +350,7 @@ class Config { ) ], defaultValue: (node) => >{}, - transform: (node) => varArgFunctionConfigExtractor(node.rawValue), + transform: (node) => varArgFunctionConfigExtractor(node.value), result: (node) { _varArgFunctions = makeVarArgFunctionsMapping( node.value as Map>, @@ -731,8 +384,7 @@ class Config { ), ) ], - transform: (node) => - structPackingOverrideExtractor(node.rawValue), + transform: (node) => structPackingOverrideExtractor(node.value), defaultValue: (node) => StructPackingOverride(), result: (node) => _structPackingOverride = node.value as StructPackingOverride, @@ -825,7 +477,7 @@ class Config { strings.symbolFilesImport: ListSchema( childSchema: StringSchema(), transform: (node) => symbolFileImportExtractor( - node.rawValue, _libraryImports, filename, packageConfig), + node.value, _libraryImports, filename, packageConfig), defaultValue: (node) => {}, result: (node) => _usrTypeMappings = node.value as Map, @@ -906,6 +558,7 @@ class Config { ), strings.name: StringSchema( defaultValue: (node) { + // TODO: replace dartClassNameValidator _logger.warning( "Prefer adding Key '${node.pathString}' to your config."); return 'NativeLibrary'; @@ -913,6 +566,7 @@ class Config { result: (node) => _wrapperName = node.value as String, ), strings.description: StringSchema( + // TODO: replace nonEmptyStringValidator defaultValue: (node) { _logger.warning( "Prefer adding Key '${node.pathString}' to your config."); @@ -937,7 +591,7 @@ class Config { }, ) ], - transform: (node) => ffiNativeExtractor(node.rawValue), + transform: (node) => ffiNativeExtractor(node.value), defaultValue: (node) => FfiNativeConfig(enabled: false), result: (node) => _ffiNativeConfig = (node.value) as FfiNativeConfig, ), @@ -1029,7 +683,7 @@ class Config { ) ], defaultValue: (node) => >{}, - transform: (node) => typeMapExtractor(node.rawValue), + transform: (node) => typeMapExtractor(node.value), ); } diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart index 09387475..feb5e5d8 100644 --- a/lib/src/config_provider/spec_utils.dart +++ b/lib/src/config_provider/spec_utils.dart @@ -114,12 +114,8 @@ void _warnUnknownKeysInMap(Map allowedKeyMap, } } -bool booleanExtractor(dynamic value) => value as bool; - -bool booleanValidator(List name, dynamic value) => - checkType(name, value); - -Map libraryImportsExtractor(dynamic yamlConfig) { +Map libraryImportsExtractor( + Map yamlConfig) { final resultMap = {}; final typeMap = yamlConfig as YamlMap?; if (typeMap != null) { @@ -169,18 +165,14 @@ YamlMap loadSymbolFile(String symbolFilePath, String? configFileName, } Map symbolFileImportExtractor( - dynamic yamlConfig, + List yamlConfig, Map libraryImports, String? configFileName, PackageConfig? packageConfig) { final resultMap = {}; - for (final item in (yamlConfig as YamlList)) { + for (final item in yamlConfig) { String symbolFilePath; - if (item is String) { - symbolFilePath = item; - } else { - symbolFilePath = item[strings.symbolFile] as String; - } + symbolFilePath = item; final symbolFile = loadSymbolFile(symbolFilePath, configFileName, packageConfig); final formatVersion = symbolFile[strings.formatVersion] as String; @@ -210,44 +202,13 @@ Map symbolFileImportExtractor( return resultMap; } -bool symbolFileImportValidator(List name, dynamic yamlConfig) { - if (!checkType(name, yamlConfig)) { - return false; - } - var result = true; - (yamlConfig as YamlList).asMap().forEach((idx, value) { - if (value is YamlMap) { - if (!value.keys.contains(strings.symbolFile)) { - result = false; - _logger - .severe('Key $name -> $idx -> ${strings.symbolFile} is required.'); - } - for (final key in value.keys) { - if (key == strings.symbolFile) { - if (!checkType( - [...name, idx.toString(), key as String], value[key])) { - result = false; - } - } else { - result = false; - _logger.severe('Unknown key : $name -> $idx -> $key.'); - } - } - } else if (value is! String) { - result = false; - _logger.severe('Expected $name -> $idx should be a String or Map.'); - } - }); - return result; -} - -Map> typeMapExtractor(dynamic yamlConfig) { +Map> typeMapExtractor(Map? yamlConfig) { // Key - type_name, Value - [lib, cType, dartType]. final resultMap = >{}; - final typeMap = yamlConfig as YamlMap?; + final typeMap = yamlConfig; if (typeMap != null) { for (final typeName in typeMap.keys) { - final typeConfigItem = typeMap[typeName] as YamlMap; + final typeConfigItem = typeMap[typeName] as Map; resultMap[typeName as String] = [ typeConfigItem[strings.lib] as String, typeConfigItem[strings.cType] as String, @@ -258,57 +219,6 @@ Map> typeMapExtractor(dynamic yamlConfig) { return resultMap; } -bool typeMapValidator(List name, dynamic yamlConfig) { - if (!checkType(name, yamlConfig)) { - return false; - } - var result = true; - for (final key in (yamlConfig as YamlMap).keys) { - if (!checkType([...name, key as String], yamlConfig[key])) { - return false; - } - final lib = (yamlConfig[key] as YamlMap).containsKey(strings.lib); - if (!lib) { - _logger.severe("Key '${strings.lib}' in $name -> $key is required."); - result = false; - } - final cType = (yamlConfig[key] as YamlMap).containsKey(strings.cType); - if (!cType) { - _logger.severe("Key '${strings.cType}' in $name -> $key is required."); - result = false; - } - final dartType = (yamlConfig[key] as YamlMap).containsKey(strings.dartType); - if (!dartType) { - _logger.severe("Key '${strings.dartType}' in $name -> $key is required."); - result = false; - } - } - return result; -} - -Map stringStringMapExtractor(dynamic yamlConfig) { - final resultMap = {}; - final inputMap = yamlConfig as YamlMap?; - if (inputMap != null) { - for (final key in inputMap.keys) { - resultMap[key as String] = inputMap[key] as String; - } - } - return resultMap; -} - -bool stringStringMapValidator(List name, dynamic yamlConfig) { - if (!checkType(name, yamlConfig)) { - return false; - } - for (final key in (yamlConfig as YamlMap).keys) { - if (!checkType([...name, key as String], yamlConfig[key])) { - return false; - } - } - return true; -} - Map makeImportTypeMapping( Map> rawTypeMappings, Map libraryImportsMap) { @@ -446,7 +356,7 @@ List compilerOptsExtractor(dynamic value) { } final list = []; - for (final el in (value as YamlList)) { + for (final el in (value as List)) { if (el is String) { list.addAll(compilerOptsToList(el)); } @@ -454,63 +364,14 @@ List compilerOptsExtractor(dynamic value) { return list; } -bool compilerOptsValidator(List name, dynamic value) { - if (value is String || value is YamlList) { - return true; - } else { - _logger.severe('Expected $name to be a String or List of String.'); - return false; - } -} - -CompilerOptsAuto compilerOptsAutoExtractor(dynamic value) { - return CompilerOptsAuto( - macIncludeStdLib: getKeyValueFromYaml( - [strings.macos, strings.includeCStdLib], - value as YamlMap, - ) as bool?, - ); -} - -bool compilerOptsAutoValidator(List name, dynamic value) { - var result = true; - - if (!checkType(name, value)) { - return false; - } - - for (final oskey in (value as YamlMap).keys) { - if (oskey == strings.macos) { - if (!checkType([...name, oskey as String], value[oskey])) { - return false; - } - - for (final inckey in (value[oskey] as YamlMap).keys) { - if (inckey == strings.includeCStdLib) { - if (!checkType( - [...name, oskey, inckey as String], value[oskey][inckey])) { - result = false; - } - } else { - _logger.severe("Unknown key '$inckey' in '$name -> $oskey."); - result = false; - } - } - } else { - _logger.severe("Unknown key '$oskey' in '$name'."); - result = false; - } - } - return result; -} - -Headers headersExtractor(dynamic yamlConfig, String? configFilename) { +Headers headersExtractor( + Map> yamlConfig, String? configFilename) { final entryPoints = []; final includeGlobs = []; - for (final key in (yamlConfig as YamlMap).keys) { + for (final key in yamlConfig.keys) { if (key == strings.entryPoints) { - for (final h in (yamlConfig[key] as YamlList)) { - final headerGlob = _normalizePath(h as String, configFilename); + for (final h in (yamlConfig[key]!)) { + final headerGlob = _normalizePath(h, configFilename); // Add file directly to header if it's not a Glob but a File. if (File(headerGlob).existsSync()) { final osSpecificPath = headerGlob; @@ -528,8 +389,8 @@ Headers headersExtractor(dynamic yamlConfig, String? configFilename) { } } if (key == strings.includeDirectives) { - for (final h in (yamlConfig[key] as YamlList)) { - final headerGlob = h as String; + for (final h in yamlConfig[key]!) { + final headerGlob = h; final fixedGlob = _normalizePath(headerGlob, configFilename); includeGlobs.add(quiver.Glob(fixedGlob)); } @@ -543,28 +404,6 @@ Headers headersExtractor(dynamic yamlConfig, String? configFilename) { ); } -bool headersValidator(List name, dynamic value) { - if (!checkType(name, value)) { - return false; - } - if (!(value as YamlMap).containsKey(strings.entryPoints)) { - _logger.severe("Required '$name -> ${strings.entryPoints}'."); - return false; - } else { - for (final key in value.keys) { - if (key == strings.entryPoints || key == strings.includeDirectives) { - if (!checkType([...name, key as String], value[key])) { - return false; - } - } else { - _logger.severe("Unknown key '$key' in '$name'."); - return false; - } - } - return true; - } -} - /// Returns location of dynamic library by searching default locations. Logs /// error and throws an Exception if not found. String findDylibAtDefaultLocations() { @@ -640,10 +479,9 @@ String? findLibclangDylib(String parentFolder) { } } -String llvmPathExtractor(dynamic value) { +String llvmPathExtractor(List value) { // Extract libclang's dylib from user specified paths. - for (final path in (value as YamlList)) { - if (path is! String) continue; + for (final path in value) { final dylibPath = findLibclangDylib(p.join(path, strings.dynamicLibParentName)); if (dylibPath != null) { @@ -672,19 +510,12 @@ String llvmPathExtractor(dynamic value) { } } -bool llvmPathValidator(List name, dynamic value) { - if (!checkType(name, value)) { - return false; - } - return true; -} - OutputConfig outputExtractor( dynamic value, String? configFilename, PackageConfig? packageConfig) { if (value is String) { return OutputConfig(_normalizePath(value, configFilename), null); } - value = value as YamlMap; + value = value as Map; return OutputConfig( _normalizePath((value)[strings.bindings] as String, configFilename), value.containsKey(strings.symbolFile) @@ -694,33 +525,6 @@ OutputConfig outputExtractor( ); } -bool outputValidator(List name, dynamic value) { - if (value is String) { - return true; - } else if (value is YamlMap) { - final keys = value.keys; - var result = true; - for (final key in keys) { - if (key == strings.bindings) { - if (!checkType([...name, key as String], value[key])) { - result = false; - } - } else if (key == strings.symbolFile) { - result = symbolFileOutputValidator( - [...name, strings.symbolFile], value[key]); - } else { - result = false; - _logger.severe("Unknown key '$key' in '$name'."); - } - } - return result; - } else { - _logger.severe( - "Expected value of key '${name.join(' -> ')}' to be a String or Map."); - return false; - } -} - SymbolFile symbolFileOutputExtractor( dynamic value, String? configFilename, PackageConfig? packageConfig) { value = value as YamlMap; @@ -740,58 +544,6 @@ SymbolFile symbolFileOutputExtractor( return SymbolFile(importPath, output); } -bool symbolFileOutputValidator(List name, dynamic value) { - if (!checkType(name, value)) { - return false; - } - if (!(value as YamlMap).containsKey(strings.output)) { - _logger.severe("Required '$name -> ${strings.output}'."); - return false; - } - if (!(value).containsKey(strings.importPath)) { - _logger.severe("Required '$name -> ${strings.importPath}'."); - return false; - } - for (final key in value.keys) { - if (key == strings.output || key == strings.importPath) { - if (!checkType([...name, key as String], value[key])) { - return false; - } - } else { - _logger.severe("Unknown key '$key' in '$name'."); - return false; - } - } - return true; -} - -Language languageExtractor(dynamic value) { - if (value == strings.langC) { - return Language.c; - } else if (value == strings.langObjC) { - return Language.objc; - } - return Language.c; -} - -bool languageValidator(List name, dynamic value) { - if (value is String) { - if (value == strings.langC) { - return true; - } - if (value == strings.langObjC) { - _logger.severe('Objective C support is EXPERIMENTAL. The API may change ' - 'in a breaking way without notice.'); - return true; - } - _logger.severe("'$name' must be one of the following - " - "{${strings.langC}, ${strings.langObjC}}"); - return false; - } - _logger.severe("Expected value of key '$name' to be a String."); - return false; -} - /// Returns true if [str] is not a full name. /// /// E.g `abc` is a full name, `abc.*` is not. @@ -838,17 +590,17 @@ Includer extractIncluderFromYaml(dynamic yamlMap) { } Map> varArgFunctionConfigExtractor( - dynamic yamlMap) { + Map yamlMap) { final result = >{}; - final configMap = (yamlMap as YamlMap); + final configMap = yamlMap; for (final key in configMap.keys) { final List vafuncs = []; - for (final rawVaFunc in (configMap[key] as YamlList)) { - if (rawVaFunc is YamlList) { + for (final rawVaFunc in (configMap[key] as List)) { + if (rawVaFunc is List) { vafuncs.add(RawVarArgFunction(null, rawVaFunc.cast())); - } else if (rawVaFunc is YamlMap) { + } else if (rawVaFunc is Map) { vafuncs.add(RawVarArgFunction(rawVaFunc[strings.postfix] as String?, - (rawVaFunc[strings.types] as YamlList).cast())); + (rawVaFunc[strings.types] as List).cast())); } else { throw Exception("Unexpected type in variadic-argument config."); } @@ -859,63 +611,7 @@ Map> varArgFunctionConfigExtractor( return result; } -bool varArgFunctionConfigValidator(List name, dynamic value) { - if (!checkType(name, value)) { - return false; - } - var result = true; - for (final key in (value as YamlMap).keys) { - final list = value[key as String]; - if (!checkType([...name, key], list)) { - result = false; - continue; - } - (list as YamlList).asMap().forEach((idx, subList) { - if (subList is YamlMap) { - if (!subList.containsKey(strings.types)) { - result = false; - _logger.severe('Missing required key - ${[ - ...name, - key, - idx.toString(), - strings.types - ].join(" -> ")}'); - } - subList.forEach((subkey, subvalue) { - subkey = subkey as String; - if (subkey == strings.postfix) { - if (!checkType( - [...name, key, idx.toString(), subkey], subvalue)) { - result = false; - } - } else if (subkey == strings.types) { - if (!checkType( - [...name, key, idx.toString(), subkey], subvalue)) { - result = false; - } - } else { - result = false; - _logger.severe('Unknown key - ${[ - ...name, - key, - idx.toString(), - subkey - ].join(" -> ")}'); - } - }); - } else if (subList is! YamlList) { - result = false; - _logger.severe('Expected ${[ - ...name, - key, - idx - ].join(" -> ")} to be a List or a Map.'); - } - }); - } - return result; -} - +// TODO: maybe remove yaml dependency Declaration declarationConfigExtractor(dynamic yamlMap) { final renamePatterns = []; final renameFull = {}; @@ -992,98 +688,6 @@ Declaration declarationConfigExtractor(dynamic yamlMap) { ); } -bool declarationConfigValidator(List name, dynamic value) { - var result = true; - if (value is YamlMap) { - for (final key in value.keys) { - if (key == strings.include || key == strings.exclude) { - if (!checkType([...name, key as String], value[key])) { - result = false; - } - } else if (key == strings.rename) { - if (!checkType([...name, key as String], value[key])) { - result = false; - } else { - for (final subkey in (value[key] as YamlMap).keys) { - if (!checkType( - [...name, key, subkey as String], value[key][subkey])) { - result = false; - } - } - } - } else if (key == strings.memberRename) { - if (!checkType([...name, key as String], value[key])) { - result = false; - } else { - for (final declNameKey in (value[key] as YamlMap).keys) { - if (!checkType([...name, key, declNameKey as String], - value[key][declNameKey])) { - result = false; - } else { - for (final memberNameKey - in ((value[key] as YamlMap)[declNameKey] as YamlMap).keys) { - if (!checkType([ - ...name, - key, - declNameKey, - memberNameKey as String, - ], value[key][declNameKey][memberNameKey])) { - result = false; - } - } - } - } - } - } else if (key == strings.symbolAddress) { - if (!checkType([...name, key as String], value[key])) { - result = false; - } else { - for (final subkey in (value[key] as YamlMap).keys) { - if (subkey == strings.include || subkey == strings.exclude) { - if (!checkType( - [...name, key, subkey as String], value[key][subkey])) { - result = false; - } - } else { - _logger.severe("Unknown key '$subkey' in '$name -> $key'."); - result = false; - } - } - } - } - } - } else { - _logger.severe("Expected value '$name' to be a Map."); - result = false; - } - return result; -} - -Includer exposeFunctionTypeExtractor(dynamic value) => - extractIncluderFromYaml(value); - -bool exposeFunctionTypeValidator(List name, dynamic value) { - var result = true; - - if (!checkType(name, value)) { - result = false; - } else { - final mp = value as YamlMap; - for (final key in mp.keys) { - if (key == strings.include || key == strings.exclude) { - if (!checkType([...name, key as String], value[key])) { - result = false; - } - } else { - _logger.severe("Unknown subkey '$key' in '$name'."); - result = false; - } - } - } - - return result; -} - Includer leafFunctionExtractor(dynamic value) => extractIncluderFromYaml(value); bool leafFunctionValidator(List name, dynamic value) { @@ -1124,8 +728,6 @@ SupportedNativeType nativeSupportedType(int value, {bool signed = true}) { } } -String stringExtractor(dynamic value) => value as String; - bool nonEmptyStringValidator(List name, dynamic value) { if (value is String && value.isNotEmpty) { return true; @@ -1146,116 +748,18 @@ bool dartClassNameValidator(List name, dynamic value) { } } -CommentType commentExtractor(dynamic value) { - if (value is bool) { - if (value) { - return CommentType.def(); - } else { - return CommentType.none(); - } - } - final ct = CommentType.def(); - if (value is YamlMap) { - for (final key in value.keys) { - if (key == strings.style) { - if (value[key] == strings.any) { - ct.style = CommentStyle.any; - } else if (value[key] == strings.doxygen) { - ct.style = CommentStyle.doxygen; - } - } else if (key == strings.length) { - if (value[key] == strings.full) { - ct.length = CommentLength.full; - } else if (value[key] == strings.brief) { - ct.length = CommentLength.brief; - } - } - } - } - return ct; -} - -bool commentValidator(List name, dynamic value) { - if (value is bool) { - return true; - } else if (value is YamlMap) { - var result = true; - for (final key in value.keys) { - if (key == strings.style) { - if (value[key] is! String || - !(value[key] == strings.doxygen || value[key] == strings.any)) { - _logger.severe( - "'$name'>'${strings.style}' must be one of the following - {${strings.doxygen}, ${strings.any}}"); - result = false; - } - } else if (key == strings.length) { - if (value[key] is! String || - !(value[key] == strings.brief || value[key] == strings.full)) { - _logger.severe( - "'$name'>'${strings.length}' must be one of the following - {${strings.brief}, ${strings.full}}"); - result = false; - } - } else { - _logger.severe("Unknown key '$key' in '$name'."); - result = false; - } - } - return result; - } else { - _logger.severe("Expected value of key '$name' to be a bool or a Map."); - return false; - } -} - -CompoundDependencies dependencyOnlyExtractor(dynamic value) { - var result = CompoundDependencies.full; - if (value == strings.opaqueCompoundDependencies) { - result = CompoundDependencies.opaque; - } - return result; -} - -bool dependencyOnlyValidator(List name, dynamic value) { - var result = true; - if (value is! String || - !(value == strings.fullCompoundDependencies || - value == strings.opaqueCompoundDependencies)) { - _logger.severe( - "'$name' must be one of the following - {${strings.fullCompoundDependencies}, ${strings.opaqueCompoundDependencies}}"); - result = false; - } - return result; -} - -StructPackingOverride structPackingOverrideExtractor(dynamic value) { +StructPackingOverride structPackingOverrideExtractor( + Map value) { final matcherMap = {}; - for (final key in (value as YamlMap).keys) { + for (final key in value.keys) { matcherMap[RegExp(key as String, dotAll: true)] = strings.packingValuesMap[value[key]]; } return StructPackingOverride(matcherMap: matcherMap); } -bool structPackingOverrideValidator(List name, dynamic value) { - var result = true; - - if (!checkType([...name], value)) { - result = false; - } else { - for (final key in (value as YamlMap).keys) { - if (!(strings.packingValuesMap.keys.contains(value[key]))) { - _logger.severe( - "'$name -> $key' must be one of the following - ${strings.packingValuesMap.keys.toList()}"); - result = false; - } - } - } - - return result; -} - FfiNativeConfig ffiNativeExtractor(dynamic yamlConfig) { - final yamlMap = yamlConfig as YamlMap?; + final yamlMap = yamlConfig as Map?; return FfiNativeConfig( enabled: true, asset: yamlMap?[strings.ffiNativeAsset] as String?, From f948c38e1d3c7b49a3306876b164d43474a10f03 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Mon, 19 Jun 2023 02:53:01 +0530 Subject: [PATCH 21/23] Update config and remove mode unused code --- ffigen.schema.json | 34 +++++++++++++++---------- lib/src/config_provider/config.dart | 8 +++--- lib/src/config_provider/spec_utils.dart | 7 +++-- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/ffigen.schema.json b/ffigen.schema.json index 78e92d83..f4851c41 100644 --- a/ffigen.schema.json +++ b/ffigen.schema.json @@ -114,6 +114,9 @@ "rename": { "$ref": "#/$defs/rename" }, + "member-rename": { + "$ref": "#/$defs/memberRename" + }, "symbol-address": { "$ref": "#/$defs/includeExclude" }, @@ -257,6 +260,9 @@ }, "rename": { "$ref": "#/$defs/rename" + }, + "symbol-address": { + "$ref": "#/$defs/includeExclude" } } }, @@ -422,35 +428,35 @@ "rename": { "type": "object", "patternProperties": { - ".+": { + ".*": { "type": "string" } } }, - "includeExclude": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - } - } - }, "memberRename": { "type": "object", "patternProperties": { - ".+": { + ".*": { "type": "object", "patternProperties": { - ".+": { + ".*": { "type": "string" } } } } }, + "includeExclude": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" + }, + "exclude": { + "$ref": "#/$defs/exclude" + } + } + }, "dependencyOnly": { "enum": [ "full", diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart index 7d7a6216..75235298 100644 --- a/lib/src/config_provider/config.dart +++ b/lib/src/config_provider/config.dart @@ -321,6 +321,7 @@ class Config { keys: { ...includeExcludeProperties(), ...renameProperties(), + ...memberRenameProperties(), strings.symbolAddress: includeExcludeObject(), strings.exposeFunctionTypedefs: includeExcludeObject( defaultValue: (node) => Includer.excludeByDefault(), @@ -435,6 +436,7 @@ class Config { keys: { ...includeExcludeProperties(), ...renameProperties(), + strings.symbolAddress: includeExcludeObject(), }, result: (node) { _globals = declarationConfigExtractor(node.rawValue ?? YamlMap()); @@ -618,7 +620,7 @@ class Config { strings.rename: DynamicMapSchema( schemaDefName: "rename", keyValueSchemas: [ - (keyRegexp: ".+", valueSchema: StringSchema()), + (keyRegexp: ".*", valueSchema: StringSchema()), ], ), }; @@ -630,9 +632,9 @@ class Config { schemaDefName: "memberRename", keyValueSchemas: [ ( - keyRegexp: ".+", + keyRegexp: ".*", valueSchema: DynamicMapSchema( - keyValueSchemas: [(keyRegexp: ".+", valueSchema: StringSchema())], + keyValueSchemas: [(keyRegexp: ".*", valueSchema: StringSchema())], ), ), ], diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart index feb5e5d8..96b2dfe7 100644 --- a/lib/src/config_provider/spec_utils.dart +++ b/lib/src/config_provider/spec_utils.dart @@ -115,12 +115,11 @@ void _warnUnknownKeysInMap(Map allowedKeyMap, } Map libraryImportsExtractor( - Map yamlConfig) { + Map? typeMap) { final resultMap = {}; - final typeMap = yamlConfig as YamlMap?; if (typeMap != null) { for (final typeName in typeMap.keys) { - resultMap[typeName as String] = + resultMap[typeName] = LibraryImport(typeName, typeMap[typeName] as String); } } @@ -527,7 +526,7 @@ OutputConfig outputExtractor( SymbolFile symbolFileOutputExtractor( dynamic value, String? configFilename, PackageConfig? packageConfig) { - value = value as YamlMap; + value = value as Map; var output = value[strings.output] as String; if (Uri.parse(output).scheme != "package") { _logger.warning( From 82bb1ebfbc0abfe59a34bb53fadd533a8f5f7251 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Mon, 19 Jun 2023 03:08:26 +0530 Subject: [PATCH 22/23] Change indent level for ffigen schema --- ffigen.schema.json | 906 +++++++++++++++++++++---------------------- lib/src/strings.dart | 2 +- 2 files changed, 454 insertions(+), 454 deletions(-) diff --git a/ffigen.schema.json b/ffigen.schema.json index f4851c41..fc896c66 100644 --- a/ffigen.schema.json +++ b/ffigen.schema.json @@ -1,499 +1,499 @@ { - "$id": "https://json.schemastore.org/ffigen", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "llvm-path": { - "type": "array", - "items": { - "type": "string" - } - }, - "output": { - "$oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "bindings": { - "type": "string" - }, - "symbol-file": { - "type": "object", - "properties": { - "output": { - "type": "string" - }, - "import-path": { - "type": "string" - } - }, - "required": [ - "output", - "import-path" - ] - } - }, - "required": [ - "bindings" - ] - } - ] - }, - "language": { - "enum": [ - "c", - "objc" - ] - }, - "headers": { - "type": "object", - "properties": { - "entry-points": { - "type": "array", - "items": { - "type": "string" - } - }, - "include-directives": { - "type": "array", - "items": { - "type": "string" - } - } + "$id": "https://json.schemastore.org/ffigen", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "llvm-path": { + "type": "array", + "items": { + "type": "string" + } + }, + "output": { + "$oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "bindings": { + "type": "string" }, - "required": [ - "entry-points" - ] - }, - "compiler-opts": { - "$oneOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] - }, - "compiler-opts-automatic": { - "type": "object", - "properties": { - "macos": { - "type": "object", - "properties": { - "include-c-standard-library": { - "type": "boolean" - } - } + "symbol-file": { + "type": "object", + "properties": { + "output": { + "type": "string" + }, + "import-path": { + "type": "string" } + }, + "required": [ + "output", + "import-path" + ] } + }, + "required": [ + "bindings" + ] + } + ] + }, + "language": { + "enum": [ + "c", + "objc" + ] + }, + "headers": { + "type": "object", + "properties": { + "entry-points": { + "type": "array", + "items": { + "type": "string" + } }, - "library-imports": { - "type": "object", - "patternProperties": { - ".*": { - "type": "string" - } + "include-directives": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "entry-points" + ] + }, + "compiler-opts": { + "$oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "compiler-opts-automatic": { + "type": "object", + "properties": { + "macos": { + "type": "object", + "properties": { + "include-c-standard-library": { + "type": "boolean" } + } + } + } + }, + "library-imports": { + "type": "object", + "patternProperties": { + ".*": { + "type": "string" + } + } + }, + "functions": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "functions": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - }, - "rename": { - "$ref": "#/$defs/rename" - }, - "member-rename": { - "$ref": "#/$defs/memberRename" - }, - "symbol-address": { - "$ref": "#/$defs/includeExclude" - }, - "expose-typedefs": { - "$ref": "#/$defs/includeExclude" - }, - "leaf": { - "$ref": "#/$defs/includeExclude" - }, - "variadic-arguments": { - "type": "object", - "patternProperties": { - ".*": { - "type": "array", - "items": { - "$oneOf": [ - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "object", - "properties": { - "types": { - "type": "array", - "items": { - "type": "string" - } - }, - "postfix": { - "type": "string" - } - }, - "required": [ - "types" - ] - } - ] - } - } - } - } - } + "exclude": { + "$ref": "#/$defs/exclude" }, - "structs": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - }, - "rename": { - "$ref": "#/$defs/rename" - }, - "member-rename": { - "$ref": "#/$defs/memberRename" - }, - "dependency-only": { - "$ref": "#/$defs/dependencyOnly" - }, - "pack": { + "rename": { + "$ref": "#/$defs/rename" + }, + "member-rename": { + "$ref": "#/$defs/memberRename" + }, + "symbol-address": { + "$ref": "#/$defs/includeExclude" + }, + "expose-typedefs": { + "$ref": "#/$defs/includeExclude" + }, + "leaf": { + "$ref": "#/$defs/includeExclude" + }, + "variadic-arguments": { + "type": "object", + "patternProperties": { + ".*": { + "type": "array", + "items": { + "$oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { "type": "object", - "patternProperties": { - ".*": { - "enum": [ - "none", - 1, - 2, - 4, - 8, - 16 - ] + "properties": { + "types": { + "type": "array", + "items": { + "type": "string" } - } - } + }, + "postfix": { + "type": "string" + } + }, + "required": [ + "types" + ] + } + ] + } } + } + } + } + }, + "structs": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "unions": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - }, - "rename": { - "$ref": "#/$defs/rename" - }, - "member-rename": { - "$ref": "#/$defs/memberRename" - }, - "dependency-only": { - "$ref": "#/$defs/dependencyOnly" - } - } + "exclude": { + "$ref": "#/$defs/exclude" }, - "enums": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - }, - "rename": { - "$ref": "#/$defs/rename" - }, - "member-rename": { - "$ref": "#/$defs/memberRename" - } + "rename": { + "$ref": "#/$defs/rename" + }, + "member-rename": { + "$ref": "#/$defs/memberRename" + }, + "dependency-only": { + "$ref": "#/$defs/dependencyOnly" + }, + "pack": { + "type": "object", + "patternProperties": { + ".*": { + "enum": [ + "none", + 1, + 2, + 4, + 8, + 16 + ] } + } + } + } + }, + "unions": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "unnamed-enums": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - }, - "rename": { - "$ref": "#/$defs/rename" - } - } + "exclude": { + "$ref": "#/$defs/exclude" }, - "globals": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - }, - "rename": { - "$ref": "#/$defs/rename" - }, - "symbol-address": { - "$ref": "#/$defs/includeExclude" - } - } + "rename": { + "$ref": "#/$defs/rename" }, - "macros": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - }, - "rename": { - "$ref": "#/$defs/rename" - } - } + "member-rename": { + "$ref": "#/$defs/memberRename" }, - "typedefs": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - }, - "rename": { - "$ref": "#/$defs/rename" - } - } + "dependency-only": { + "$ref": "#/$defs/dependencyOnly" + } + } + }, + "enums": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "objc-interfaces": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - }, - "rename": { - "$ref": "#/$defs/rename" - }, - "member-rename": { - "$ref": "#/$defs/memberRename" - }, - "module": { - "$ref": "#/$defs/objcInterfaceModule" - } - } + "exclude": { + "$ref": "#/$defs/exclude" }, - "import": { - "type": "object", - "properties": { - "symbol-files": { - "type": "array", - "items": { - "type": "string" - } - } - } + "rename": { + "$ref": "#/$defs/rename" }, - "type-map": { - "type": "object", - "properties": { - "typedefs": { - "$ref": "#/$defs/mappedTypes" - }, - "structs": { - "$ref": "#/$defs/mappedTypes" - }, - "unions": { - "$ref": "#/$defs/mappedTypes" - }, - "native-types": { - "$ref": "#/$defs/mappedTypes" - } - } + "member-rename": { + "$ref": "#/$defs/memberRename" + } + } + }, + "unnamed-enums": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "exclude-all-by-default": { - "type": "boolean" + "exclude": { + "$ref": "#/$defs/exclude" }, - "sort": { - "type": "boolean" + "rename": { + "$ref": "#/$defs/rename" + } + } + }, + "globals": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "use-supported-typedefs": { - "type": "boolean" + "exclude": { + "$ref": "#/$defs/exclude" }, - "comments": { - "$oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "style": { - "enum": [ - "doxygen", - "any" - ] - }, - "length": { - "enum": [ - "brief", - "full" - ] - } - } - } - ] + "rename": { + "$ref": "#/$defs/rename" }, - "name": { - "type": "string" + "symbol-address": { + "$ref": "#/$defs/includeExclude" + } + } + }, + "macros": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "description": { - "type": "string" + "exclude": { + "$ref": "#/$defs/exclude" }, - "preamble": { - "type": "string" + "rename": { + "$ref": "#/$defs/rename" + } + } + }, + "typedefs": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "use-dart-handle": { - "type": "boolean" + "exclude": { + "$ref": "#/$defs/exclude" }, - "ffi-native": { - "$oneOf": [ - { - "enum": [ - null - ] - }, - { - "type": "object", - "properties": { - "asset": { - "type": "string" - } - }, - "required": [ - "asset" - ] - } - ] + "rename": { + "$ref": "#/$defs/rename" } + } }, - "required": [ - "output", - "headers" - ], - "$defs": { + "objc-interfaces": { + "type": "object", + "properties": { "include": { - "type": "array", - "items": { - "type": "string" - } + "$ref": "#/$defs/include" }, "exclude": { - "type": "array", - "items": { - "type": "string" - } + "$ref": "#/$defs/exclude" }, "rename": { - "type": "object", - "patternProperties": { - ".*": { - "type": "string" - } - } + "$ref": "#/$defs/rename" }, - "memberRename": { - "type": "object", - "patternProperties": { - ".*": { - "type": "object", - "patternProperties": { - ".*": { - "type": "string" - } - } - } - } + "member-rename": { + "$ref": "#/$defs/memberRename" }, - "includeExclude": { - "type": "object", - "properties": { - "include": { - "$ref": "#/$defs/include" - }, - "exclude": { - "$ref": "#/$defs/exclude" - } - } + "module": { + "$ref": "#/$defs/objcInterfaceModule" + } + } + }, + "import": { + "type": "object", + "properties": { + "symbol-files": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "type-map": { + "type": "object", + "properties": { + "typedefs": { + "$ref": "#/$defs/mappedTypes" }, - "dependencyOnly": { - "enum": [ - "full", - "opaque" - ] - }, - "objcInterfaceModule": { - "type": "object", - "patternProperties": { - ".*": { - "type": "string" - } + "structs": { + "$ref": "#/$defs/mappedTypes" + }, + "unions": { + "$ref": "#/$defs/mappedTypes" + }, + "native-types": { + "$ref": "#/$defs/mappedTypes" + } + } + }, + "exclude-all-by-default": { + "type": "boolean" + }, + "sort": { + "type": "boolean" + }, + "use-supported-typedefs": { + "type": "boolean" + }, + "comments": { + "$oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "style": { + "enum": [ + "doxygen", + "any" + ] + }, + "length": { + "enum": [ + "brief", + "full" + ] + } + } + } + ] + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "preamble": { + "type": "string" + }, + "use-dart-handle": { + "type": "boolean" + }, + "ffi-native": { + "$oneOf": [ + { + "enum": [ + null + ] + }, + { + "type": "object", + "properties": { + "asset": { + "type": "string" } + }, + "required": [ + "asset" + ] + } + ] + } + }, + "required": [ + "output", + "headers" + ], + "$defs": { + "include": { + "type": "array", + "items": { + "type": "string" + } + }, + "exclude": { + "type": "array", + "items": { + "type": "string" + } + }, + "rename": { + "type": "object", + "patternProperties": { + ".*": { + "type": "string" + } + } + }, + "memberRename": { + "type": "object", + "patternProperties": { + ".*": { + "type": "object", + "patternProperties": { + ".*": { + "type": "string" + } + } + } + } + }, + "includeExclude": { + "type": "object", + "properties": { + "include": { + "$ref": "#/$defs/include" }, - "mappedTypes": { - "type": "object", - "patternProperties": { - ".*": { - "type": "object", - "properties": { - "lib": { - "type": "string" - }, - "c-type": { - "type": "string" - }, - "dart-type": { - "type": "string" - } - }, - "required": [ - "lib", - "c-type", - "dart-type" - ] - } + "exclude": { + "$ref": "#/$defs/exclude" + } + } + }, + "dependencyOnly": { + "enum": [ + "full", + "opaque" + ] + }, + "objcInterfaceModule": { + "type": "object", + "patternProperties": { + ".*": { + "type": "string" + } + } + }, + "mappedTypes": { + "type": "object", + "patternProperties": { + ".*": { + "type": "object", + "properties": { + "lib": { + "type": "string" + }, + "c-type": { + "type": "string" + }, + "dart-type": { + "type": "string" } + }, + "required": [ + "lib", + "c-type", + "dart-type" + ] } + } } + } } \ No newline at end of file diff --git a/lib/src/strings.dart b/lib/src/strings.dart index 8d4b4cb9..7613289a 100644 --- a/lib/src/strings.dart +++ b/lib/src/strings.dart @@ -278,6 +278,6 @@ String get tmpDir { return _tmpDir!.path; } -const ffigenJsonSchemaIndent = ' '; +const ffigenJsonSchemaIndent = ' '; const ffigenJsonSchemaId = "https://json.schemastore.org/ffigen"; const ffigenJsonSchemaFileName = "ffigen.schema.json"; From cdf956e3e98d28f1cb5a51c1579aeeb044964b79 Mon Sep 17 00:00:00 2001 From: Prerak Mann Date: Mon, 19 Jun 2023 03:22:13 +0530 Subject: [PATCH 23/23] Handle carriage return on windows --- tool/generate_json_schema.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tool/generate_json_schema.dart b/tool/generate_json_schema.dart index 41bb398e..9a9c2c9c 100644 --- a/tool/generate_json_schema.dart +++ b/tool/generate_json_schema.dart @@ -14,9 +14,12 @@ import 'package:ffigen/src/strings.dart' as strings; void main() async { final actualJsonSchema = - JsonEncoder.withIndent(strings.ffigenJsonSchemaIndent).convert( - Config.getsRootSchema().generateJsonSchema(strings.ffigenJsonSchemaId), - ); + JsonEncoder.withIndent(strings.ffigenJsonSchemaIndent) + .convert( + Config.getsRootSchema() + .generateJsonSchema(strings.ffigenJsonSchemaId), + ) + .replaceAll("\r\n", "\n"); final file = File(strings.ffigenJsonSchemaFileName); if (!await file.exists()) {