Can toJson() functionality be included as well?
It's fantastic to have an official package on Pub for parsing and extracting data from a pubspec.
There is, however, one thing, I'm wondering - would it be bad for createToJson to be true for the models contained in this package?
I'm working on updating the Angel CLI, which uses the old package:pubspec to persist changes to the project files (namely, adding dependencies the user is missing), to pubspec_parse, and if there were some way to just get a toJson method on the PubSpec.
I'll gladly send a PR, but is there is a specific reason this functionality isn't present already? I imagine there's probably a reason I didn't think about.
Hey @thosakwe
I think I avoided toJson because the pubspec is yaml – and the json output wouldn't necessarily round-trip the shape of the source.
There is quite a bit of special handling of dependencies, for instance.
If you want to take a shot, I'd accept a PR, though!
@kevmoo could I work on this issue?
@kevmoo could I work on this issue?
Sure! Just make sure you put in plenty of tests. I want to see that at round trips cleanly, etc.
Is this being worked on? (cc: @AliAkberAakash , @kevmoo )
Hey @alestiago I completely forgot about this, No it's not being worked on from my side. If you want we can work on this together.
@AliAkberAakash I don't have the bandwidth right now to work on this feature. If I ever have some spare I'll let you know. If you're no longer working on this I recommend asking to get unassigned.
I think I avoided
toJsonbecause the pubspec is yaml – and the json output wouldn't necessarily round-trip the shape of the source.
So I know in general that YAML is a superset of JSON, but Is there any sort of valid Pubspec that can't be represented by JSON, though? I threw this together pretty quickly -- is something like this a good starting point for a PR?
Pubspec.toJson()
import "package:pubspec_parse/pubspec_parse.dart";
import "package:pub_semver/pub_semver.dart";
extension <K, V> on Map<K, V> {
Iterable<(K, V)> get records sync* {
for (final entry in entries) {
yield (entry.key, entry.value);
}
}
}
typedef Json = Map<String, dynamic>;
extension on Dependency {
Json toJson() => switch (this) {
SdkDependency(:final sdk, :final version) => {
"sdk": sdk,
"version": version.toString(),
},
HostedDependency(:final hosted, :final version) => {
if (hosted != null) "hosted": hosted.url.toString(),
"version": version.toString(),
},
GitDependency(:final url, :final ref, :final path) => {
"git": {
"url": url.toString(),
if (path != null) "ref": ref,
if (path != null) "path": path,
},
},
PathDependency(:final path) => {
"path": path.replaceAll(r'\', '/'),
},
};
}
extension on Pubspec {
Json toJson() => {
"name": name,
"environment": {
for (final (sdk, version) in environment.records)
sdk: version.toString(),
},
if (resolution != null) "resolution": resolution,
if (workspace != null) "workspace": workspace,
"dependencies": {
for (final (name, dependency) in dependencies.records)
name: dependency.toJson(),
},
// ...
};
}
That converts this
final pubspec = Pubspec("workspace",
environment: {"sdk": Version.parse("3.6.0")},
dependencies: {
"http": HostedDependency(
version: VersionRange(min: Version.parse("1.2.0"), max: Version.parse("2.0.0")),
hosted: HostedDetails(null, Uri.parse('https://pub.dev')),
),
"pub_cache_server": PathDependency(r"D:\dart\packages\pub_cache_server"),
"flutter": SdkDependency("flutter"),
"pubspec_parse": GitDependency(
Uri.parse('https://github.com/Levi-Lesches/dart-lang-tools'),
ref: 'pubspec-workspaces-1814',
path: 'pkgs/pubspec_parse',
),
},
);
into this
{
"name": "workspace",
"environment": {
"sdk": "3.6.0"
},
"dependencies": {
"http": {
"hosted": "https://pub.dev",
"version": ">1.2.0 <2.0.0"
},
"pub_cache_server": {
"path": "D:/dart/packages/pub_cache_server"
},
"flutter": {
"sdk": "flutter",
"version": "any"
},
"pubspec_parse": {
"git": {
"url": "https://github.com/Levi-Lesches/dart-lang-tools",
"ref": "pubspec-workspaces-1814",
"path": "pkgs/pubspec_parse"
}
}
}
}
Then, saving that to a file pubspec.yaml and running dart pub get in that directory works just fine:
dart pub get output
Resolving dependencies...
Downloading packages...
+ args 2.6.0
+ async 2.12.0
+ characters 1.3.0 (1.4.0 available)
+ checked_yaml 2.0.3
+ collection 1.19.0 (1.19.1 available)
+ flutter 0.0.0 from sdk flutter
+ http 1.2.2
+ http_methods 1.1.1
+ http_parser 4.1.2
+ json_annotation 4.9.0
+ material_color_utilities 0.11.1 (0.12.0 available)
+ meta 1.15.0 (1.16.0 available)
+ path 1.9.1
+ pub_cache_server 1.0.1 from path D:\dart\packages\pub_cache_server
+ pub_semver 2.1.5
+ pubspec_parse 1.5.0-wip from git https://github.com/Levi-Lesches/dart-lang-tools at d7f79e in pkgs/pubspec_parse
+ shelf 1.4.2
+ shelf_router 1.1.4
+ sky_engine 0.0.0 from sdk flutter
+ source_span 1.10.1
+ stack_trace 1.12.1
+ stream_channel 2.1.3
+ string_scanner 1.4.1
+ tar 2.0.0
+ term_glyph 1.2.2
+ typed_data 1.4.0
+ vector_math 2.1.4
+ web 1.1.0
+ yaml 3.1.3
Changed 29 dependencies!
4 packages have newer versions incompatible with dependency constraints.
Try `dart pub outdated` for more information.
It may not look like an "idiomatic" Pubspec, but in the meantime, a .toJson() would be valuable for automatically constructing and testing Pubspecs. My use case is that I'm trying to expand the test suite for package:dependency_validator and I would like to construct Pubspec objects and write them to files instead of hand-crafting multi-line strings. In terms of tests, I'm thinking just generating a bunch of Pubspec() objects and testing that Pubspec.fromJson(pubspec.toJson()) == pubspec) (which would also mean adding some notion of equality as well)
Adding the above toJson() method really helped clean up my tests. See workspace_test.dart and the checkWorkspace() for an example.