Skip to content

Add #:item directive support#53712

Open
stevefan1999-personal wants to merge 2 commits intodotnet:mainfrom
stevefan1999-personal:feat-item-directive
Open

Add #:item directive support#53712
stevefan1999-personal wants to merge 2 commits intodotnet:mainfrom
stevefan1999-personal:feat-item-directive

Conversation

@stevefan1999-personal
Copy link
Copy Markdown

Fixes #49820 and #52319

Copilot AI review requested due to automatic review settings April 6, 2026 12:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for a new #:item file-level directive in file-based apps (dotnet run file.cs) so users can inject arbitrary MSBuild items (e.g., EmbeddedResource, Protobuf) into the generated project, and updates conversion/docs/tests accordingly.

Changes:

  • Introduces parsing and project-file emission for #:item <ItemType> <Include> directives (with optional quoting for the include).
  • Evaluates #:item includes to full paths during virtual project evaluation and disables runfile caching when item directives are present.
  • Extends dotnet project convert and test suite/documentation to recognize and emit #:item.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/dotnet.Tests/CommandTests/Run/RunFileTests_Directives.cs Adds end-to-end and API-level tests validating #:item behavior (embedded resource scenario).
test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs Adds conversion tests for #:item and updates directive validation coverage.
src/Microsoft.DotNet.ProjectTools/VirtualProjectBuilder.cs Evaluates #:item includes to full paths and emits items into generated project files.
src/Cli/Microsoft.DotNet.FileBasedPrograms/InternalAPI.Unshipped.txt Records the newly added CSharpDirective.Item internal API surface.
src/Cli/Microsoft.DotNet.FileBasedPrograms/FileLevelDirectiveHelpers.cs Adds directive parsing support and relaxes quote blocking specifically for #:item.
src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs Prevents caching/reuse when #:item directives are present.
src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs Adjusts conversion to relativize item includes for output projects.
documentation/general/dotnet-run-file.md Documents #:item syntax and behavior.


if (includeText.Length == 0)
{
context.ReportError(string.Format(FileBasedProgramsResources.InvalidDirectiveName, context.DirectiveKind, " "));
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For #:item, when the item type is present but the include is missing (#:item Foo), this reports InvalidDirectiveName, whose message suggests an optional value. Since #:item requires an include, this error is misleading for this specific case; consider reporting a dedicated “missing include/value” error (similar to PropertyDirectiveMissingParts) so the user gets actionable guidance.

Suggested change
context.ReportError(string.Format(FileBasedProgramsResources.InvalidDirectiveName, context.DirectiveKind, " "));
context.ReportError($"The '{context.DirectiveKind}' directive requires both an item type and an include value.");

Copilot uses AI. Check for mistakes.
Comment on lines +640 to +641
if (includeText.Length >= 2 && includeText[0] == '"' && includeText[^1] == '"')
{
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#:item accepts quoted includes, but currently any unbalanced quote (e.g., #:item Protobuf "foo.proto or foo".proto) will be treated as a literal quote in the include and silently flow into MSBuild. This makes it easy to produce surprising item includes; consider validating that if includeText contains a double-quote then it must be properly wrapped (or otherwise report an error) rather than partially stripping/accepting it.

Suggested change
if (includeText.Length >= 2 && includeText[0] == '"' && includeText[^1] == '"')
{
if (includeText.Contains('"'))
{
if (includeText.Length < 2 || includeText[0] != '"' || includeText[^1] != '"' || includeText[1..^1].Contains('"'))
{
context.ReportError(string.Format(FileBasedProgramsResources.InvalidDirectiveName, context.DirectiveKind, " "));
return null;
}

Copilot uses AI. Check for mistakes.
Comment on lines +303 to +309
if (directive is CSharpDirective.Item item &&
Path.IsPathFullyQualified(item.Include))
{
item = item.WithInclude(Path.GetRelativePath(relativeTo: targetDirectory, path: item.Include));
result.Add(item);
continue;
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UpdateDirectives rewrites #:item includes to be relative to targetDirectory, which implies the referenced file will exist in the converted output. However, FindIncludedItems() only copies items whose item types come from the include-mapping (Compile/EmbeddedResource/None/Content by default); any #:item using a custom item type (e.g., Protobuf) won’t be copied, so the converted project will reference a missing file. Consider extending the conversion copy list to include file paths referenced by CSharpDirective.Item directives (or enumerating all project items that are files), so conversion reliably produces a buildable project for arbitrary item types.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dotnet run file.cs #: directive for ItemGroup

2 participants