From b8312ace669096af4d26ba40ab3c894557f0b5b8 Mon Sep 17 00:00:00 2001 From: Bernardo Belchior Date: Mon, 27 Jun 2022 19:09:34 +0100 Subject: [PATCH 1/8] chore: upgrade `scrollable_positioned_list`, `provider` and `rows_lint` --- CHANGELOG.md | 6 +++++ example/pubspec.lock | 26 +++++++++---------- .../windows/flutter/generated_plugins.cmake | 8 ++++++ pubspec.yaml | 8 +++--- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6073234..0a0d62b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.2.0 + +* Upgrade `scrollable_positioned_list` to 0.3.2 +* Upgrade `provider` to 6.0.3 +* Upgrade `rows_lint` to 0.1.1 + ## 0.1.0 * Initial release. diff --git a/example/pubspec.lock b/example/pubspec.lock index 3529304..79c9de1 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" crypto: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" ffi: dependency: transitive description: @@ -120,14 +120,14 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3" + version: "0.6.4" json_data_explorer: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.0.1" + version: "0.2.0" matcher: dependency: transitive description: @@ -141,7 +141,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" meta: dependency: transitive description: @@ -162,7 +162,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" path_provider: dependency: transitive description: @@ -239,7 +239,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "6.0.2" + version: "6.0.3" rows_lint: dependency: "direct dev" description: @@ -253,7 +253,7 @@ packages: name: scrollable_positioned_list url: "https://pub.dartlang.org" source: hosted - version: "0.2.3" + version: "0.3.2" sky_engine: dependency: transitive description: flutter @@ -265,7 +265,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -300,7 +300,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" + version: "0.4.9" typed_data: dependency: transitive description: @@ -370,7 +370,7 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" win32: dependency: transitive description: @@ -386,5 +386,5 @@ packages: source: hosted version: "0.2.0+1" sdks: - dart: ">=2.15.0 <3.0.0" - flutter: ">=2.10.0" + dart: ">=2.17.0-0 <3.0.0" + flutter: ">=2.12.0" diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake index 411af46..88b22e5 100644 --- a/example/windows/flutter/generated_plugins.cmake +++ b/example/windows/flutter/generated_plugins.cmake @@ -6,6 +6,9 @@ list(APPEND FLUTTER_PLUGIN_LIST url_launcher_windows ) +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) @@ -14,3 +17,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST}) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/pubspec.yaml b/pubspec.yaml index 8d979a8..cf1d3d4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: json_data_explorer description: A highly customizable widget to render and interact with JSON objects. -version: 0.1.0 +version: 0.2.0 repository: https://github.com/rows/json_data_explorer homepage: https://github.com/rows/json_data_explorer issue_tracker: https://github.com/rows/json_data_explorer/issues @@ -12,13 +12,13 @@ environment: dependencies: flutter: sdk: flutter - scrollable_positioned_list: ^0.2.3 - provider: ^6.0.2 + scrollable_positioned_list: ^0.3.2 + provider: ^6.0.3 dev_dependencies: flutter_test: sdk: flutter - rows_lint: 0.1.0 + rows_lint: ^0.1.1 mocktail: ^0.3.0 golden_toolkit: ^0.13.0 From 2486759866a6631e3cf9422f118861d335708ecb Mon Sep 17 00:00:00 2001 From: Klondike Dragon Date: Tue, 6 Jun 2023 21:48:52 -0600 Subject: [PATCH 2/8] Bump package and example dependencies --- CHANGELOG.md | 5 + .../Flutter/GeneratedPluginRegistrant.swift | 2 +- example/pubspec.lock | 261 ++++++++++-------- example/pubspec.yaml | 4 +- pubspec.yaml | 4 +- 5 files changed, 158 insertions(+), 118 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a0d62b..f4e9448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.3.0 + +* Upgrade `golden_toolkit` to 0.15.0 +* Upgrade example dependencies + ## 0.2.0 * Upgrade `scrollable_positioned_list` to 0.3.2 diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 4618f38..a1cdfd0 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,7 +5,7 @@ import FlutterMacOS import Foundation -import path_provider_macos +import path_provider_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { diff --git a/example/pubspec.lock b/example/pubspec.lock index 79c9de1..1f94d79 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,79 +5,82 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.10.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + url: "https://pub.dev" source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "1.2.1" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.3" effective_dart: dependency: transitive description: name: effective_dart - url: "https://pub.dartlang.org" + sha256: "6a69783c808344084b65667e87ff600823531e95810a8a15882cb542fe22de80" + url: "https://pub.dev" source: hosted version: "1.3.2" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.1" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "2.0.2" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.1.4" flutter: dependency: "direct main" description: flutter @@ -97,163 +100,177 @@ packages: dependency: "direct main" description: name: google_fonts - url: "https://pub.dartlang.org" + sha256: "6b6f10f0ce3c42f6552d1c70d2c28d764cf22bb487f50f66cca31dcd5194f4d6" + url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "4.0.4" http: dependency: "direct main" description: name: http - url: "https://pub.dartlang.org" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" source: hosted - version: "0.13.4" + version: "0.13.6" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.2" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" json_data_explorer: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.2.0" + version: "0.3.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.13" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + url: "https://pub.dev" source: hosted - version: "0.1.4" + version: "0.2.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.8.0" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" source: hosted version: "1.0.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.8.2" path_provider: dependency: transitive description: name: path_provider - url: "https://pub.dartlang.org" + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.0.15" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + url: "https://pub.dev" source: hosted - version: "2.0.12" - path_provider_ios: + version: "2.0.27" + path_provider_foundation: dependency: transitive description: - name: path_provider_ios - url: "https://pub.dartlang.org" + name: path_provider_foundation + sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" + url: "https://pub.dev" source: hosted - version: "2.0.8" + version: "2.2.3" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.5" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.11" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.6" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.7" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" source: hosted version: "4.2.4" provider: dependency: transitive description: name: provider - url: "https://pub.dartlang.org" + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" source: hosted - version: "6.0.3" + version: "6.0.5" rows_lint: dependency: "direct dev" description: name: rows_lint - url: "https://pub.dartlang.org" + sha256: "772b3e0759a62282365c16ea3e51e2bab5823b916f6ae6f4bfe2012e28028afc" + url: "https://pub.dev" source: hosted - version: "0.1.0" + version: "0.1.1" scrollable_positioned_list: dependency: transitive description: name: scrollable_positioned_list - url: "https://pub.dartlang.org" + sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287" + url: "https://pub.dev" source: hosted - version: "0.3.2" + version: "0.3.8" sky_engine: dependency: transitive description: flutter @@ -263,128 +280,146 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.9.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + url: "https://pub.dev" source: hosted - version: "0.4.9" + version: "0.4.16" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.2" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 + url: "https://pub.dev" source: hosted - version: "6.0.20" + version: "6.1.11" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + sha256: eed4e6a1164aa9794409325c3b707ff424d4d1c2a785e7db67f8bbda00e36e51 + url: "https://pub.dev" source: hosted - version: "6.0.15" + version: "6.0.35" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + url: "https://pub.dev" source: hosted - version: "6.0.15" + version: "6.1.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.5" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" + url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab" + url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.0.17" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "4.1.4" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + url: "https://pub.dev" source: hosted - version: "0.2.0+1" + version: "1.0.0" sdks: - dart: ">=2.17.0-0 <3.0.0" - flutter: ">=2.12.0" + dart: ">=2.19.0 <3.0.0" + flutter: ">=3.3.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 59b8d1c..fd0bd61 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -13,13 +13,13 @@ dependencies: path: ../ http: ^0.13.4 - google_fonts: ^2.3.1 + google_fonts: ^4.0.4 url_launcher: ^6.0.20 dev_dependencies: flutter_test: sdk: flutter - rows_lint: 0.1.0 + rows_lint: ^0.1.1 flutter: uses-material-design: true diff --git a/pubspec.yaml b/pubspec.yaml index cf1d3d4..864d4a9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: json_data_explorer description: A highly customizable widget to render and interact with JSON objects. -version: 0.2.0 +version: 0.3.0 repository: https://github.com/rows/json_data_explorer homepage: https://github.com/rows/json_data_explorer issue_tracker: https://github.com/rows/json_data_explorer/issues @@ -20,7 +20,7 @@ dev_dependencies: sdk: flutter rows_lint: ^0.1.1 mocktail: ^0.3.0 - golden_toolkit: ^0.13.0 + golden_toolkit: ^0.15.0 flutter: uses-material-design: true \ No newline at end of file From 0ae660e69f538319dad7f377111980eae22984b9 Mon Sep 17 00:00:00 2001 From: Klondike Dragon Date: Tue, 6 Jun 2023 22:15:30 -0600 Subject: [PATCH 3/8] Enhance `valueStyleBuilder` * Take node as additional argument * Return value PropertyOverrides can optionally take `onLongPress` and `cursor`, and `style` is now optional --- CHANGELOG.md | 3 +++ README.md | 4 ++-- example/lib/main.dart | 5 ++++- lib/src/json_data_explorer.dart | 24 ++++++++++++++++++------ test/golden/json_data_explorer_test.dart | 2 +- 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4e9448..310f99d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## 0.3.0 +* BREAKING: `valueStyleBuilder` now takes node in addition to value +* `style` in `PropertyOverrides` is now optional +* `PropertyOverrides` can optionally specify `onLongPress` and a mouse `cursor` * Upgrade `golden_toolkit` to 0.15.0 * Upgrade example dependencies diff --git a/README.md b/README.md index 2d8f6a2..fa2bb1a 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ An example is adding interaction to values that contains links: ```dart JsonDataExplorer( nodes: state.displayNodes, - valueStyleBuilder: (value, style) { + valueStyleBuilder: (node, value, style) { final isUrl = _valueIsUrl(value); return PropertyOverrides( style: isUrl @@ -203,7 +203,7 @@ value types: ```dart JsonDataExplorer( nodes: state.displayNodes, - valueStyleBuilder: (value, style) { + valueStyleBuilder: (node, value, style) { if (value is num) { return PropertyOverrides( style: style.copyWith( diff --git a/example/lib/main.dart b/example/lib/main.dart index e40319f..f84e7a2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -258,7 +258,7 @@ class _DataExplorerPageState extends State { /// Dynamically changes the property value style and /// interaction when an URL is detected. - valueStyleBuilder: (dynamic value, style) { + valueStyleBuilder: (node, dynamic value, style) { final isUrl = _valueIsUrl(value); return PropertyOverrides( style: isUrl @@ -267,6 +267,9 @@ class _DataExplorerPageState extends State { ) : style, onTap: isUrl ? () => _launchUrl(value as String) : null, + onLongPress: () { + print('onLongPress: ${node.key}: $value'); + }, ); }, diff --git a/lib/src/json_data_explorer.dart b/lib/src/json_data_explorer.dart index 9620861..d5bfddc 100644 --- a/lib/src/json_data_explorer.dart +++ b/lib/src/json_data_explorer.dart @@ -23,16 +23,24 @@ typedef Formatter = String Function(dynamic value); /// See also: /// * [PropertyStyle] typedef StyleBuilder = PropertyOverrides Function( + NodeViewModelState node, dynamic value, TextStyle style, ); /// Holds information about a property value style and interaction. class PropertyOverrides { - final TextStyle style; + final TextStyle? style; final VoidCallback? onTap; - - const PropertyOverrides({required this.style, this.onTap}); + final VoidCallback? onLongPress; + final MouseCursor? cursor; + + const PropertyOverrides({ + this.style, + this.onTap, + this.onLongPress, + this.cursor, + }); } /// A widget to display a list of Json nodes. @@ -263,15 +271,18 @@ class JsonAttribute extends StatelessWidget { final valueStyle = valueStyleBuilder != null ? valueStyleBuilder!.call( + node, node.value, theme.valueTextStyle, ) - : PropertyOverrides(style: theme.valueTextStyle); + : const PropertyOverrides(); final hasInteraction = node.isRoot || valueStyle.onTap != null; return MouseRegion( - cursor: hasInteraction ? SystemMouseCursors.click : MouseCursor.defer, + cursor: valueStyle.cursor != null + ? valueStyle.cursor! + : (hasInteraction ? SystemMouseCursors.click : MouseCursor.defer), onEnter: (event) { node.highlight(); node.focus(); @@ -291,6 +302,7 @@ class JsonAttribute extends StatelessWidget { } } : null, + onLongPress: valueStyle.onLongPress, child: AnimatedBuilder( animation: node, @@ -341,7 +353,7 @@ class JsonAttribute extends StatelessWidget { node: node, searchTerm: searchTerm, valueFormatter: valueFormatter, - style: valueStyle.style, + style: valueStyle.style ?? theme.valueTextStyle, searchHighlightStyle: theme.valueSearchHighlightTextStyle, focusedSearchHighlightStyle: diff --git a/test/golden/json_data_explorer_test.dart b/test/golden/json_data_explorer_test.dart index 6f8d2d3..32fec58 100644 --- a/test/golden/json_data_explorer_test.dart +++ b/test/golden/json_data_explorer_test.dart @@ -122,7 +122,7 @@ void main() { ..addScenario( 'Value style builder', buildWidget( - valueStyleBuilder: (dynamic value, style) { + valueStyleBuilder: (node, dynamic value, style) { final isInt = int.tryParse(value.toString()); return PropertyOverrides( style: isInt != null From 12b24868221d9c1689195a176732bb6fa007fc46 Mon Sep 17 00:00:00 2001 From: Klondike Dragon Date: Wed, 7 Jun 2023 23:29:49 -0600 Subject: [PATCH 4/8] Add support for onSecondaryTap as well --- CHANGELOG.md | 2 +- example/lib/main.dart | 3 +++ lib/src/json_data_explorer.dart | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 310f99d..6c0aa8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ * BREAKING: `valueStyleBuilder` now takes node in addition to value * `style` in `PropertyOverrides` is now optional -* `PropertyOverrides` can optionally specify `onLongPress` and a mouse `cursor` +* `PropertyOverrides` can optionally specify `onSecondaryTap`, `onLongPress` and a mouse `cursor` * Upgrade `golden_toolkit` to 0.15.0 * Upgrade example dependencies diff --git a/example/lib/main.dart b/example/lib/main.dart index f84e7a2..7363143 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -267,6 +267,9 @@ class _DataExplorerPageState extends State { ) : style, onTap: isUrl ? () => _launchUrl(value as String) : null, + onSecondaryTap: () { + print('onSecondaryTap: ${node.key}: $value'); + }, onLongPress: () { print('onLongPress: ${node.key}: $value'); }, diff --git a/lib/src/json_data_explorer.dart b/lib/src/json_data_explorer.dart index d5bfddc..90d510c 100644 --- a/lib/src/json_data_explorer.dart +++ b/lib/src/json_data_explorer.dart @@ -32,12 +32,14 @@ typedef StyleBuilder = PropertyOverrides Function( class PropertyOverrides { final TextStyle? style; final VoidCallback? onTap; + final VoidCallback? onSecondaryTap; final VoidCallback? onLongPress; final MouseCursor? cursor; const PropertyOverrides({ this.style, this.onTap, + this.onSecondaryTap, this.onLongPress, this.cursor, }); @@ -303,6 +305,7 @@ class JsonAttribute extends StatelessWidget { } : null, onLongPress: valueStyle.onLongPress, + onSecondaryTap: valueStyle.onSecondaryTap, child: AnimatedBuilder( animation: node, From 18aff3c5b1f99e12ef954cefcfdbfe03ff8a25fa Mon Sep 17 00:00:00 2001 From: Klondike Dragon Date: Sat, 24 Jun 2023 21:20:07 -0600 Subject: [PATCH 5/8] Fix highlighting for regex patterns The search term is a regex, but highlighting assumed simple substring matching. This is now fixed. --- lib/src/data_explorer_store.dart | 23 ++++++++++------ lib/src/json_data_explorer.dart | 46 +++++++++++++++++++------------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/lib/src/data_explorer_store.dart b/lib/src/data_explorer_store.dart index 795473d..f07e664 100644 --- a/lib/src/data_explorer_store.dart +++ b/lib/src/data_explorer_store.dart @@ -655,7 +655,7 @@ class DataExplorerStore extends ChangeNotifier { void _doSearch() { for (final node in _allNodes) { - final matchesIndexes = _getSearchTermMatchesIndexes(node.key); + final matchesIndexes = getSearchTermMatchesIndexes(node.key); for (final matchIndex in matchesIndexes) { _searchResults.add( @@ -669,7 +669,7 @@ class DataExplorerStore extends ChangeNotifier { if (!node.isRoot) { final matchesIndexes = - _getSearchTermMatchesIndexes(node.value.toString()); + getSearchTermMatchesIndexes(node.value.toString()); for (final matchIndex in matchesIndexes) { _searchResults.add( @@ -686,14 +686,21 @@ class DataExplorerStore extends ChangeNotifier { notifyListeners(); } - /// Finds all occurences of [searchTerm] in [victim] and retrieves all their + /// Finds all occurrences of [regexp] in [victim] and retrieves all their /// indexes. - Iterable _getSearchTermMatchesIndexes(String victim) { - final pattern = RegExp(searchTerm, caseSensitive: false); - - final matches = pattern.allMatches(victim).map((match) => match.start); + static Iterable getIndexesOfMatches( + String regexp, + String victim, { + bool caseSensitive = false, + }) { + final pattern = RegExp(regexp, caseSensitive: caseSensitive); + return pattern.allMatches(victim); + } - return matches; + /// Finds all occurences of [searchTerm] in [victim] and retrieves all their + /// indexes. + Iterable getSearchTermMatchesIndexes(String victim) { + return getIndexesOfMatches(searchTerm, victim).map((match) => match.start); } /// Expands all the parent nodes of each [SearchResult.node] in diff --git a/lib/src/json_data_explorer.dart b/lib/src/json_data_explorer.dart index 90d510c..9c7c495 100644 --- a/lib/src/json_data_explorer.dart +++ b/lib/src/json_data_explorer.dart @@ -470,9 +470,9 @@ class _RootNodeWidget extends StatelessWidget { final focusedSearchMatchIndex = context.select(_getFocusedSearchMatchIndex); - return _HighlightedText( + return HighlightedText( text: text, - highlightedText: searchTerm, + highlightedRegExp: searchTerm, style: attributeKeyStyle, primaryMatchStyle: theme.focusedKeySearchNodeHighlightTextStyle, secondaryMatchStyle: theme.keySearchHighlightTextStyle, @@ -533,9 +533,9 @@ class _PropertyNodeWidget extends StatelessWidget { final focusedSearchMatchIndex = context.select(_getFocusedSearchMatchIndex); - return _HighlightedText( + return HighlightedText( text: text, - highlightedText: searchTerm, + highlightedRegExp: searchTerm, style: style, primaryMatchStyle: focusedSearchHighlightStyle, secondaryMatchStyle: searchHighlightStyle, @@ -614,11 +614,12 @@ class _Indentation extends StatelessWidget { } } -/// Highlights found occurrences of [highlightedText] with [highlightedStyle] +/// Highlights found occurrences of [highlightedRegExp] with [highlightedStyle] /// in [text]. -class _HighlightedText extends StatelessWidget { +class HighlightedText extends StatelessWidget { final String text; - final String highlightedText; + final String highlightedRegExp; + final bool caseSensitive; // The default style when the text or part of it is not highlighted. final TextStyle style; @@ -632,10 +633,11 @@ class _HighlightedText extends StatelessWidget { // The index of the focused search match. final int? focusedSearchMatchIndex; - const _HighlightedText({ + const HighlightedText({ Key? key, required this.text, - required this.highlightedText, + required this.highlightedRegExp, + this.caseSensitive = false, required this.style, required this.primaryMatchStyle, required this.secondaryMatchStyle, @@ -644,19 +646,18 @@ class _HighlightedText extends StatelessWidget { @override Widget build(BuildContext context) { - final lowerCaseText = text.toLowerCase(); - final lowerCaseQuery = highlightedText.toLowerCase(); - - if (highlightedText.isEmpty || !lowerCaseText.contains(lowerCaseQuery)) { + final matchingIndexes = highlightedRegExp.isEmpty + ? const Iterable.empty() + : DataExplorerStore.getIndexesOfMatches(highlightedRegExp, text); + if (matchingIndexes.isEmpty) { return Text(text, style: style); } final spans = []; var start = 0; - while (true) { - var index = lowerCaseText.indexOf(lowerCaseQuery, start); - index = index >= 0 ? index : text.length; + for (final m in matchingIndexes) { + final index = m.start; if (start != index) { spans.add( @@ -673,13 +674,22 @@ class _HighlightedText extends StatelessWidget { spans.add( TextSpan( - text: text.substring(index, index + highlightedText.length), + text: text.substring(index, m.end), style: index == focusedSearchMatchIndex ? primaryMatchStyle : secondaryMatchStyle, ), ); - start = index + highlightedText.length; + start = m.end; + } + + if (start != text.length) { + spans.add( + TextSpan( + text: text.substring(start), + style: style, + ), + ); } return Text.rich( From 4a1916d332be06d256f3d7e5373ccc191735cba9 Mon Sep 17 00:00:00 2001 From: Klondike Dragon Date: Mon, 26 Jun 2023 17:30:50 -0600 Subject: [PATCH 6/8] Option to highlight only groups in search regex New theme property highlightOnlyRegExpGroups that when true will cause only the matching groups of the search term regexp to be highlighted, rather than the whole expression. This is only an approximation right now, since dart regexp does not give the position of each matching group. Defaults to old behavior. --- lib/src/data_explorer_theme.dart | 12 ++++++++ lib/src/json_data_explorer.dart | 48 ++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/src/data_explorer_theme.dart b/lib/src/data_explorer_theme.dart index b874318..95defcc 100644 --- a/lib/src/data_explorer_theme.dart +++ b/lib/src/data_explorer_theme.dart @@ -31,6 +31,12 @@ class DataExplorerTheme { /// If not set falls back to [valueSearchHighlightTextStyle]. final TextStyle focusedValueSearchHighlightTextStyle; + /// Whether or not to highlight only matched groups in the search term regex. + /// This is limited right now to highlighting all substrings that match any + /// of the matching groups, rather than the exact groups, as dart does not + /// yet support providing positions of matched regexp groups. + final bool highlightOnlyRegExpGroups; + /// Indentation lines color. final Color indentationLineColor; @@ -54,6 +60,7 @@ class DataExplorerTheme { TextStyle? valueSearchHighlightTextStyle, TextStyle? focusedKeySearchHighlightTextStyle, TextStyle? focusedValueSearchHighlightTextStyle, + this.highlightOnlyRegExpGroups = false, this.indentationLineColor = Colors.grey, this.highlightColor, this.indentationPadding = 8.0, @@ -88,6 +95,7 @@ class DataExplorerTheme { required this.valueSearchHighlightTextStyle, required this.focusedKeySearchNodeHighlightTextStyle, required this.focusedValueSearchHighlightTextStyle, + required this.highlightOnlyRegExpGroups, required this.indentationLineColor, required this.highlightColor, required this.indentationPadding, @@ -134,6 +142,7 @@ class DataExplorerTheme { fontWeight: FontWeight.bold, backgroundColor: Colors.lightGreen, ), + highlightOnlyRegExpGroups: false, indentationLineColor: Colors.grey, highlightColor: Colors.black12, indentationPadding: 8.0, @@ -148,6 +157,7 @@ class DataExplorerTheme { TextStyle? valueSearchHighlightTextStyle, TextStyle? focusedKeySearchNodeHighlightTextStyle, TextStyle? focusedValueSearchHighlightTextStyle, + bool? highlightOnlyRegExpGroups, Color? indentationLineColor, Color? highlightColor, double? indentationPadding, @@ -172,6 +182,8 @@ class DataExplorerTheme { focusedValueSearchHighlightTextStyle: focusedValueSearchHighlightTextStyle ?? this.focusedValueSearchHighlightTextStyle, + highlightOnlyRegExpGroups: + highlightOnlyRegExpGroups ?? this.highlightOnlyRegExpGroups, ); @override diff --git a/lib/src/json_data_explorer.dart b/lib/src/json_data_explorer.dart index 9c7c495..7cba81a 100644 --- a/lib/src/json_data_explorer.dart +++ b/lib/src/json_data_explorer.dart @@ -361,6 +361,8 @@ class JsonAttribute extends StatelessWidget { theme.valueSearchHighlightTextStyle, focusedSearchHighlightStyle: theme.focusedValueSearchHighlightTextStyle, + highlightOnlyRegExpGroups: + theme.highlightOnlyRegExpGroups, ), ), ), @@ -477,6 +479,7 @@ class _RootNodeWidget extends StatelessWidget { primaryMatchStyle: theme.focusedKeySearchNodeHighlightTextStyle, secondaryMatchStyle: theme.keySearchHighlightTextStyle, focusedSearchMatchIndex: focusedSearchMatchIndex, + highlightOnlyRegExpGroups: theme.highlightOnlyRegExpGroups, ); } } @@ -489,6 +492,7 @@ class _PropertyNodeWidget extends StatelessWidget { final TextStyle style; final TextStyle searchHighlightStyle; final TextStyle focusedSearchHighlightStyle; + final bool highlightOnlyRegExpGroups; const _PropertyNodeWidget({ Key? key, @@ -498,6 +502,7 @@ class _PropertyNodeWidget extends StatelessWidget { required this.style, required this.searchHighlightStyle, required this.focusedSearchHighlightStyle, + required this.highlightOnlyRegExpGroups, }) : super(key: key); /// Gets the index of the focused search match. @@ -540,6 +545,7 @@ class _PropertyNodeWidget extends StatelessWidget { primaryMatchStyle: focusedSearchHighlightStyle, secondaryMatchStyle: searchHighlightStyle, focusedSearchMatchIndex: focusedSearchMatchIndex, + highlightOnlyRegExpGroups: highlightOnlyRegExpGroups, ); } } @@ -620,6 +626,7 @@ class HighlightedText extends StatelessWidget { final String text; final String highlightedRegExp; final bool caseSensitive; + final bool highlightOnlyRegExpGroups; // The default style when the text or part of it is not highlighted. final TextStyle style; @@ -638,6 +645,7 @@ class HighlightedText extends StatelessWidget { required this.text, required this.highlightedRegExp, this.caseSensitive = false, + this.highlightOnlyRegExpGroups = false, required this.style, required this.primaryMatchStyle, required this.secondaryMatchStyle, @@ -646,20 +654,54 @@ class HighlightedText extends StatelessWidget { @override Widget build(BuildContext context) { - final matchingIndexes = highlightedRegExp.isEmpty + var matchingIndexes = highlightedRegExp.isEmpty ? const Iterable.empty() - : DataExplorerStore.getIndexesOfMatches(highlightedRegExp, text); + : DataExplorerStore.getIndexesOfMatches( + highlightedRegExp, + text, + caseSensitive: caseSensitive, + ); if (matchingIndexes.isEmpty) { return Text(text, style: style); } + // It seems that positions of matching groups are not available for now + // (see https://github.com/dart-lang/sdk/issues/45486). We have to thus + // take a more complex approach if we only want to highlight group contents + // by first finding all matches, and then getting all of the group contents, + // and finding all matches anywhere in the string that could match these + // group contents. This will highlight potentially a lot more than just + // the actual group matches, but is an approximation we'll have to live with + // until the above dart:core enhancement is finished. + if (highlightOnlyRegExpGroups) { + final allGroups = {}; + for (final m in matchingIndexes) { + final groups = m + .groups(List.generate(m.groupCount, (index) => index + 1)) + .map((s) => s ?? '') + .where((s) => s.isNotEmpty); + allGroups.addAll(groups); + } + // for highlighting purposes, any substring that matches a known + // group match should get highlighted. place longer groups first so + // we always greedy match match longer expressions first. + final sortedGroups = allGroups.toList() + ..sort((a, b) => b.length.compareTo(a.length)); + final newRegExp = sortedGroups.map(RegExp.escape).join('|'); + matchingIndexes = DataExplorerStore.getIndexesOfMatches( + newRegExp, + text, + caseSensitive: caseSensitive, + ); + } + final spans = []; var start = 0; for (final m in matchingIndexes) { final index = m.start; - if (start != index) { + if (start < index) { spans.add( TextSpan( text: text.substring(start, index), From 4354f47f3cb0cd3d2b433ec802d092c38e864d8c Mon Sep 17 00:00:00 2001 From: Klondike Dragon Date: Thu, 31 Aug 2023 18:12:51 -0600 Subject: [PATCH 7/8] BREAKING: Formatter callbacks also take node arg --- CHANGELOG.md | 1 + README.md | 2 +- example/lib/main.dart | 2 +- lib/src/json_data_explorer.dart | 13 +++++++------ test/golden/json_data_explorer_test.dart | 6 +++--- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c0aa8e..fcf785e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## 0.3.0 +* BREAKING: formatters such as `valueFormatter` now takes node in addition to value * BREAKING: `valueStyleBuilder` now takes node in addition to value * `style` in `PropertyOverrides` is now optional * `PropertyOverrides` can optionally specify `onSecondaryTap`, `onLongPress` and a mouse `cursor` diff --git a/README.md b/README.md index fa2bb1a..f0d63cd 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ can be changed with a formatter: ```dart JsonDataExplorer( nodes: state.displayNodes, - propertyNameFormatter: (name) => '$name ->', + propertyNameFormatter: (node, name) => '$name ->', ) ``` diff --git a/example/lib/main.dart b/example/lib/main.dart index 7363143..09c66c2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -254,7 +254,7 @@ class _DataExplorerPageState extends State { : const SizedBox(), /// Creates a custom format for classes and array names. - rootNameFormatter: (dynamic name) => '$name', + rootNameFormatter: (dynamic node, dynamic name) => '$name', /// Dynamically changes the property value style and /// interaction when an URL is detected. diff --git a/lib/src/json_data_explorer.dart b/lib/src/json_data_explorer.dart index 7cba81a..657ac31 100644 --- a/lib/src/json_data_explorer.dart +++ b/lib/src/json_data_explorer.dart @@ -12,9 +12,9 @@ typedef NodeBuilder = Widget Function( NodeViewModelState node, ); -/// Signature for a function that takes a generic value and converts it to a -/// string. -typedef Formatter = String Function(dynamic value); +/// Signature for a function that takes a generic value (associated with a +/// given node in the model) and converts it to a string. +typedef Formatter = String Function(NodeViewModelState node, dynamic value); /// Signature for a function that takes a generic value and the current theme /// property value style and returns a [StyleBuilder] that allows the style @@ -431,9 +431,9 @@ class _RootNodeWidget extends StatelessWidget { String _keyName() { if (node.isRoot) { - return rootNameFormatter?.call(node.key) ?? '${node.key}:'; + return rootNameFormatter?.call(node, node.key) ?? '${node.key}:'; } - return propertyNameFormatter?.call(node.key) ?? '${node.key}:'; + return propertyNameFormatter?.call(node, node.key) ?? '${node.key}:'; } /// Gets the index of the focused search match. @@ -529,7 +529,8 @@ class _PropertyNodeWidget extends StatelessWidget { (store) => store.searchResults.isNotEmpty, ); - final text = valueFormatter?.call(node.value) ?? node.value.toString(); + final text = + valueFormatter?.call(node, node.value) ?? node.value.toString(); if (!showHighlightedText) { return Text(text, style: style); diff --git a/test/golden/json_data_explorer_test.dart b/test/golden/json_data_explorer_test.dart index 32fec58..f4fa0f7 100644 --- a/test/golden/json_data_explorer_test.dart +++ b/test/golden/json_data_explorer_test.dart @@ -114,9 +114,9 @@ void main() { ..addScenario( 'Name formatters', buildWidget( - rootNameFormatter: (dynamic name) => '$name', - propertyNameFormatter: (dynamic name) => '$name =', - valueFormatter: (dynamic value) => '"$value"', + rootNameFormatter: (dynamic node, dynamic name) => '$name', + propertyNameFormatter: (dynamic node, dynamic name) => '$name =', + valueFormatter: (dynamic node, dynamic value) => '"$value"', ), ) ..addScenario( From 6b0dd0ae49d58b12126ea33b96b4d2e0c3e3be04 Mon Sep 17 00:00:00 2001 From: Klondike Dragon Date: Thu, 31 Aug 2023 23:42:29 -0600 Subject: [PATCH 8/8] Add ability to map new node values in store build --- lib/src/data_explorer_store.dart | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/src/data_explorer_store.dart b/lib/src/data_explorer_store.dart index f07e664..43ad0cd 100644 --- a/lib/src/data_explorer_store.dart +++ b/lib/src/data_explorer_store.dart @@ -630,9 +630,26 @@ class DataExplorerStore extends ChangeNotifier { /// initially only upper root nodes will be in the list. /// /// [notifyListeners] is called to notify all registered listeners. - Future buildNodes(dynamic jsonObject, {bool areAllCollapsed = false}) async { + /// [mapScalarNodeValue] can optionally change scalar values to be a different + /// value after construction of the nodes and before they are in the store. + Future buildNodes( + dynamic jsonObject, { + bool areAllCollapsed = false, + dynamic Function(NodeViewModelState node)? mapScalarNodeValue, + }) async { final builtNodes = buildViewModelNodes(jsonObject); final flatList = flatten(builtNodes); + if (mapScalarNodeValue != null) { + for (final n in flatList) { + if ((n.value is! Map) && (n.value is! List)) { + final dynamic newValue = mapScalarNodeValue(n); + if ((newValue is Map) || (newValue is List)) { + throw ArgumentError('mapScalarNodeValue must return a scalar'); + } + n.value = newValue; + } + } + } _allNodes = UnmodifiableListView(flatList); _displayNodes = List.from(flatList);