build icon indicating copy to clipboard operation
build copied to clipboard

Automatically `part` or `import` generated files

Open davidmorgan opened this issue 5 months ago • 9 comments

Needs a language change :)

davidmorgan avatar Jul 11 '25 14:07 davidmorgan

Has been asked for before, and rejected. Not saying not to try, you may have better arguments and ideas, but it's worth checking what have been tried so far (it's mostly "allow importing *.dart or directories", but a few are more ambituous):

  • https://github.com/dart-lang/language/issues/1424
  • https://github.com/dart-lang/language/issues/1958
  • https://github.com/dart-lang/language/issues/1969
  • https://github.com/dart-lang/language/issues/2287
  • https://github.com/dart-lang/language/issues/1709
  • https://github.com/dart-lang/language/issues/3915
  • https://github.com/dart-lang/sdk/issues/60016
  • https://github.com/dart-lang/sdk/issues/60347

lrhn avatar Jul 11 '25 14:07 lrhn

A few reasons to support getting rid of part somehow:

  • Java, C#, Python and other languages don't have this declaration.
  • Writing this declaration in every file is a bad development experience.

Wdestroier avatar Jul 11 '25 14:07 Wdestroier

@lrhn Thanks! Indeed, not an easy one :)

It might be helpful to consider this in combination with https://github.com/dart-lang/build/issues/4085.

If there is a convenient way to hide most generated source, it doesn't matter how many we have, and maybe we just always generate one that pulls in all the others for you.

// hand-written foo.dart
part `foo.generated_parts.dart`; <-- the tools add this line for you if it's needed, and remove it if it isn't
// foo.generated_parts.dart, generated outside your source tree, as are the others below
part `foo.built_value.dart`;
part `foo.freezed.dart`;
part `foo.json_serializable.dart`

We can do other "auto part" features there, too. We can't auto import things for you though. Maybe that's fine, probably all generators end up writing enhanced parts and none need to be imports after that?

We could also consider if we can do any better if all the generated source ends up in one file, i.e. a source archive. Source archive with manifest? Hmmmmmmmm. Probably not.

davidmorgan avatar Jul 11 '25 15:07 davidmorgan

Given that we know the part files are generated by a builder, we could introduce an intermediate part file that groups and describes the source-generated parts.

For example, imagine this syntax in the user’s source file:

// imports section

allow generated parts;

@Bar()
class Foo extends _$Foo {}

Here, allow generated parts; would act as syntactic sugar for something like part 'my_file.sdk.dart';. That intermediate file would then provide a condensed list of all generated part files along with metadata about them:

my_file.sdk.dart:

part of 'my_file.dart';

// generated by package:bar, builder BarBuilder
part 'my_file.g.dart';

my_file.g.dart:

part of 'my_file.sdk.dart';

class _$Foo {}

The idea is that cmd+click on allow generated parts; in an IDE would navigate to the generated summary file (my_file.sdk.dart), while hovering could show a popup with details about which builders produced which parts.

jodinathan avatar Jul 11 '25 15:07 jodinathan

@davidmorgan I think so.

The arguments provided in the issue I opened (#195), when I proposed that only the augmented file should have to annotate the augmented library, were related to the cost of having to scan for files and check their relations, or something like that, which is something solved by having both part and part of (or, in the context of augmentations, import <augmentation> and library augment <augmented>).

If all generated files were bundled in a structured way, dealt by the tooling itself, we wouldn't have this problem, as we would always know where the generated files were.

I'm not sure if this would required a change in the language or only in the tooling.

mateusfccp avatar Jul 11 '25 15:07 mateusfccp

Another direction we could go with this would be to do #4002, provide a workflow for builders to modify your checked-in source.

If builders can modify source in a low friction way, they can just add the part statement(s) for you as soon as they are needed. We need to be careful not to step on manual edits, but I think there can be a mode where edits from builders are pretty much immediately applied.

#4002 comes with a lot of other interesting use cases, but adding part statements is a nice one to start with since it applies to a lot of builders :)

davidmorgan avatar Jul 14 '25 07:07 davidmorgan

Maybe marking every import and part required from a builder in the source through the builder like: build import 'xx'; and build part 'xx':

If those imports are no longer used because the builder is no longer used, the IDE marks them as unused. and the build part can be removed if every builder has his own dedicated file, so the tooling knows that a specific part can be removed because the builder is no longer registered.

YukiAttano avatar Oct 18 '25 17:10 YukiAttano

How about an annotation like @autoBuildParts, which indicates that the builder can modify the file with the annotation and add the part line if needed?

IMHO, I don’t think it would be a good idea to introduce a specific language keyword or syntax just for the build package.

When it comes to used or unused imports and parts, the analyzer already handles that and can provide an auto-fix for each case.

gmpassos avatar Oct 18 '25 18:10 gmpassos

Marking them in some way makes sense; I agree we could do it without a language feature.

Planning on doing something from the build_runner side with no language features needed as part of https://github.com/dart-lang/build/issues/4155 :)

davidmorgan avatar Oct 20 '25 08:10 davidmorgan