Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow specifying multiple sources and files for sources #165

Merged
merged 5 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions .github/workflows/dotnetcore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,24 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup .NET Core
- name: Setup .NET 8
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Validate generated css files
run: |
test -s Samples/AspNetCore.SassCompiler.Sample31/wwwroot/css/site_sass.css
test -s Samples/AspNetCore.SassCompiler.BlazorSample/Components/Pages/Counter.razor.css
test -s Samples/AspNetCore.SassCompiler.BlazorSample/obj/Release/net8.0/scopedcss/Components/Pages/Counter.razor.rz.scp.css
test -s Samples/AspNetCore.SassCompiler.BlazorWasmSample/Pages/Counter.razor.css
test -s Samples/AspNetCore.SassCompiler.BlazorWasmSample/obj/Release/net8.0/scopedcss/Pages/Counter.razor.rz.scp.css
test -s Samples/AspNetCore.SassCompiler.RazorClassLibrary/Component1.razor.css
test -s Samples/AspNetCore.SassCompiler.RazorClassLibrary/obj/Release/net6.0/scopedcss/Component1.razor.rz.scp.css
test -s Samples/AspNetCore.SassCompiler.Sample/wwwroot/css/site_sass.css
test -s Samples/AspNetCore.SassCompiler.BlazorSample/Pages/Counter.razor.css
test -s Samples/AspNetCore.SassCompiler.BlazorSample/obj/Release/net6.0/scopedcss/Pages/Counter.razor.rz.scp.css
test -s Samples/AspNetCore.SassCompiler.Sample/wwwroot/lib/css/lib.min.css

publish:
runs-on: ubuntu-latest
Expand All @@ -42,10 +46,10 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup .NET Core
- name: Setup .NET 8
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x
- name: Publish NuGet
id: publish_nuget
uses: alirezanet/[email protected]
Expand Down
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Samples/*/wwwroot/css/site_sass.css
Samples/*/wwwroot/css/site_sass.css.map
Samples/*/wwwroot/**/*.css
Samples/**/*.razor.css
Samples/**/*.css.map

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand All @@ -11,6 +12,7 @@

<ItemGroup>
<Compile Include="..\AspNetCore.SassCompiler\SassCompilerOptions.cs" />
<Compile Include="..\AspNetCore.SassCompiler\SassCompilerCompilationOptions.cs" />
</ItemGroup>

</Project>
110 changes: 63 additions & 47 deletions AspNetCore.SassCompiler.Tasks/CompileSass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
Expand Down Expand Up @@ -46,8 +47,7 @@ public override bool Execute()

var generatedFiles = new List<ITaskItem>();

generatedFiles.AddRange(GenerateSourceTarget(options));
generatedFiles.AddRange(GenerateScopedCss(options));
generatedFiles.AddRange(GenerateCss(options));

GeneratedFiles = generatedFiles.ToArray();

Expand All @@ -62,9 +62,24 @@ private SassCompilerOptions GetSassCompilerOptions()

var options = new SassCompilerOptions();

BindCompilation(options, configuration);
BindConfiguration(options, configuration);

if (configuration.TryGetValue("Configurations", out var value) && value is IDictionary<string, object> configOverrides)
if (configuration.TryGetValue("Compilations", out var value) && value is IList<object> compilations)
{
options.Compilations ??= new List<SassCompilerCompilationOptions>();

foreach (var compilationConfiguration in compilations.OfType<IDictionary<string, object>>())
{
var compilationOptions = new SassCompilerCompilationOptions();
BindCompilation(compilationOptions, compilationConfiguration);

if (!string.IsNullOrEmpty(compilationOptions.Source) && !string.IsNullOrEmpty(compilationOptions.Target))
options.Compilations.Add(compilationOptions);
}
}

if (configuration.TryGetValue("Configurations", out value) && value is IDictionary<string, object> configOverrides)
{
if (!string.IsNullOrEmpty(Configuration) && configOverrides.TryGetValue(Configuration, out value) && value is IDictionary<string, object> overrides)
{
Expand Down Expand Up @@ -162,13 +177,9 @@ private IDictionary<string, object> ReadConfigFile()
return new Dictionary<string, object>();
}

private void BindConfiguration(SassCompilerOptions options, IDictionary<string, object> configuration)
private static void BindConfiguration(SassCompilerOptions options, IDictionary<string, object> configuration)
{
object value;
if (configuration.TryGetValue("SourceFolder", out value) && value is string sourceFolder)
options.SourceFolder = sourceFolder;
if (configuration.TryGetValue("TargetFolder", out value) && value is string targetFolder)
options.TargetFolder = targetFolder;
if (configuration.TryGetValue("Arguments", out value) && value is string arguments)
options.Arguments = arguments;
if (configuration.TryGetValue("GenerateScopedCss", out value) && value is bool generateScopedCss)
Expand All @@ -179,72 +190,75 @@ private void BindConfiguration(SassCompilerOptions options, IDictionary<string,
options.IncludePaths = includePaths.OfType<string>().ToArray();
}

private IEnumerable<ITaskItem> GenerateSourceTarget(SassCompilerOptions options)
private static void BindCompilation(SassCompilerCompilationOptions options, IDictionary<string, object> configuration)
{
if (Directory.Exists(options.SourceFolder))
{
var arguments =
$"{Snapshot} {options.Arguments} {options.GetLoadPathArguments()} {options.SourceFolder}:{options.TargetFolder} --update";

var (success, output, error) = GenerateCss(arguments);
object value;
if (configuration.TryGetValue("Source", out value) && value is string source)
options.Source = source;
else if (configuration.TryGetValue("SourceFolder", out value) && value is string sourceFolder)
options.Source = sourceFolder;
if (configuration.TryGetValue("Target", out value) && value is string target)
options.Target = target;
else if (configuration.TryGetValue("TargetFolder", out value) && value is string targetFolder)
options.Target = targetFolder;
if (configuration.TryGetValue("Optional", out value) && value is bool optional)
options.Optional = optional;
}

if (!success)
{
Log.LogError($"Error running sass compiler: {error}.");
yield break;
}
private IEnumerable<ITaskItem> GenerateCss(SassCompilerOptions options)
{
var rootFolder = Directory.GetCurrentDirectory();

var processArguments = new StringBuilder();
processArguments.Append(Snapshot);
processArguments.AppendFormat(" {0}", options.Arguments);

if (!string.IsNullOrWhiteSpace(error))
if (options.IncludePaths?.Length > 0)
{
foreach (var includePath in options.IncludePaths)
{
Log.LogWarning(error);
processArguments.AppendFormat(" --load-path={0}", includePath);
}
}

var matches = _compiledFilesRe.Matches(output);
var hasSources = false;
foreach (var compilation in options.GetAllCompilations())
{
var fullSource = Path.GetFullPath(Path.Combine(rootFolder, compilation.Source));
var fullTarget = Path.GetFullPath(Path.Combine(rootFolder, compilation.Target));

foreach (Match match in matches)
if (!Directory.Exists(fullSource) && !File.Exists(fullSource))
{
var cssFile = match.Groups[2].Value;
if (compilation.Optional == false)
Log.LogError($"Could not compile sass for source {options.Source}, because it does not exist.");

var generatedFile = new TaskItem(cssFile);
yield return generatedFile;
continue;
}

hasSources = true;
processArguments.AppendFormat(" \"{0}\":\"{1}\"", fullSource, fullTarget);
}
else if (options.SourceFolder != SassCompilerOptions.DefaultSourceFolder)
{
Log.LogError($"Sass source folder {options.SourceFolder} does not exist.");
}
}

private IEnumerable<ITaskItem> GenerateScopedCss(SassCompilerOptions options)
{
if (!options.GenerateScopedCss)
if (!hasSources)
yield break;

var directories = new HashSet<string>();
foreach (var dir in options.ScopedCssFolders)
{
if (Directory.Exists(dir))
directories.Add(dir);
}
processArguments.Append(" --update");

if (directories.Count == 0)
yield break;
var arguments = processArguments.ToString();

var arguments = $"{Snapshot} {options.Arguments} {options.GetLoadPathArguments()} {string.Join(" ", directories)} --update";

var (success, output, error) = GenerateCss(arguments);

if (!success)
{
Log.LogError($"Error running sass compiler: {error}.");
Log.LogError($"Error running sass compiler: {error.Trim()}");
yield break;
}

if (!string.IsNullOrWhiteSpace(error))
{
Log.LogWarning(error);
}

var matches = _compiledFilesRe.Matches(output);

foreach (Match match in matches)
Expand All @@ -269,6 +283,8 @@ private IEnumerable<ITaskItem> GenerateScopedCss(SassCompilerOptions options)
RedirectStandardError = true,
};

Log.LogMessage(MessageImportance.Normal, $"Compiling sass: {Command} {arguments}");

string error = null;
compiler.ErrorDataReceived += (sender, e) =>
{
Expand Down
7 changes: 0 additions & 7 deletions AspNetCore.SassCompiler.sln
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCore.SassCompiler.Bla
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCore.SassCompiler.Tasks", "AspNetCore.SassCompiler.Tasks\AspNetCore.SassCompiler.Tasks.csproj", "{D94EC0A7-0717-402C-A596-707F02194E73}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCore.SassCompiler.Sample31", "Samples\AspNetCore.SassCompiler.Sample31\AspNetCore.SassCompiler.Sample31.csproj", "{9D76B3AF-E3B8-40EF-BBCE-2A0A5330A4CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCore.SassCompiler.BlazorWasmSample", "Samples\AspNetCore.SassCompiler.BlazorWasmSample\AspNetCore.SassCompiler.BlazorWasmSample.csproj", "{FE213E40-A6F6-47A2-B477-89CA8B2AB54D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCore.SassCompiler.RazorClassLibrary", "Samples\AspNetCore.SassCompiler.RazorClassLibrary\AspNetCore.SassCompiler.RazorClassLibrary.csproj", "{B318D98D-B145-4ACF-8B48-D601FB5C91E4}"
Expand All @@ -44,10 +42,6 @@ Global
{D94EC0A7-0717-402C-A596-707F02194E73}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D94EC0A7-0717-402C-A596-707F02194E73}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D94EC0A7-0717-402C-A596-707F02194E73}.Release|Any CPU.Build.0 = Release|Any CPU
{9D76B3AF-E3B8-40EF-BBCE-2A0A5330A4CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D76B3AF-E3B8-40EF-BBCE-2A0A5330A4CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D76B3AF-E3B8-40EF-BBCE-2A0A5330A4CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D76B3AF-E3B8-40EF-BBCE-2A0A5330A4CD}.Release|Any CPU.Build.0 = Release|Any CPU
{FE213E40-A6F6-47A2-B477-89CA8B2AB54D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE213E40-A6F6-47A2-B477-89CA8B2AB54D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE213E40-A6F6-47A2-B477-89CA8B2AB54D}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -66,7 +60,6 @@ Global
GlobalSection(NestedProjects) = preSolution
{0C3BCE5E-F28F-409C-8681-1C5E4AF34ABA} = {737BF497-41CA-48B1-8958-6FC3D5A6A2C6}
{71BB1B42-AE01-43FB-9BCE-00B83745780B} = {737BF497-41CA-48B1-8958-6FC3D5A6A2C6}
{9D76B3AF-E3B8-40EF-BBCE-2A0A5330A4CD} = {737BF497-41CA-48B1-8958-6FC3D5A6A2C6}
{FE213E40-A6F6-47A2-B477-89CA8B2AB54D} = {737BF497-41CA-48B1-8958-6FC3D5A6A2C6}
{B318D98D-B145-4ACF-8B48-D601FB5C91E4} = {737BF497-41CA-48B1-8958-6FC3D5A6A2C6}
EndGlobalSection
Expand Down
7 changes: 3 additions & 4 deletions AspNetCore.SassCompiler/AspNetCore.SassCompiler.csproj
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
<TargetFramework>net6.0</TargetFramework>
<PackageId>AspNetCore.SassCompiler</PackageId>
<Version>1.69.7</Version>
<Authors>koenvzeijl,sleeuwen,Michaelvs97</Authors>
<Description>Sass Compiler Library for .NET Core 3.1/5.x/6.x. without node</Description>
<PackageDescription>Sass Compiler Library for .NET Core 3.1/5.x/6.x. without node, using dart-sass as a compiler</PackageDescription>
<Description>Sass Compiler Library for .NET 6 and above. without node</Description>
<PackageDescription>Sass Compiler Library for .NET 6 and above. without node, using dart-sass as a compiler</PackageDescription>
<PackageTags>sass;scss;aspnetcore;dart-sass;compiler;watch;blazor;</PackageTags>
<RepositoryUrl>https://github.com/koenvzeijl/AspNetCore.SassCompiler</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Title>AspNetCore.SassCompiler</Title>
<LangVersion>8.0</LangVersion>
<PackageIcon>logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
Expand Down
21 changes: 21 additions & 0 deletions AspNetCore.SassCompiler/SassCompilerCompilationOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace AspNetCore.SassCompiler
{
internal class SassCompilerCompilationOptions
{
private string _source;
public string Source
{
get => _source;
set => _source = value?.Replace('\\', '/');
}

private string _target;
public string Target
{
get => _target;
set => _target = value?.Replace('\\', '/');
}

public bool? Optional { get; set; }
}
}
33 changes: 22 additions & 11 deletions AspNetCore.SassCompiler/SassCompilerHostedService.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -37,7 +37,7 @@
if (File.Exists(Path.Join(Environment.CurrentDirectory, "sasscompiler.json")))
{
var contents = File.ReadAllText(Path.Join(Environment.CurrentDirectory, "sasscompiler.json"));
options = JsonSerializer.Deserialize<SassCompilerOptions>(contents, new JsonSerializerOptions

Check warning on line 40 in AspNetCore.SassCompiler/SassCompilerHostedService.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

Check warning on line 40 in AspNetCore.SassCompiler/SassCompilerHostedService.cs

View workflow job for this annotation

GitHub Actions / build (windows-latest)

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

Check warning on line 40 in AspNetCore.SassCompiler/SassCompilerHostedService.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

Check warning on line 40 in AspNetCore.SassCompiler/SassCompilerHostedService.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

Check warning on line 40 in AspNetCore.SassCompiler/SassCompilerHostedService.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

Check warning on line 40 in AspNetCore.SassCompiler/SassCompilerHostedService.cs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest)

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.
{
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
Expand Down Expand Up @@ -159,23 +159,34 @@
if (command.Filename == null)
return null;

var directories = new HashSet<string>();
directories.Add($"\"{Path.Join(rootFolder, _options.SourceFolder)}\":\"{Path.Join(rootFolder, _options.TargetFolder)}\"");
if (_options.GenerateScopedCss)
var processArguments = new StringBuilder();
processArguments.Append(command.Snapshot);
processArguments.Append(" --error-css");
processArguments.Append(" --watch");
processArguments.AppendFormat(" {0}", _options.Arguments);

if (_options.IncludePaths?.Length > 0)
{
foreach (var dir in _options.ScopedCssFolders)
foreach (var includePath in _options.IncludePaths)
{
if (dir == _options.SourceFolder)
continue;

if (Directory.Exists(Path.Join(rootFolder, dir)))
directories.Add($"\"{Path.Join(rootFolder, dir)}\":\"{Path.Join(rootFolder, dir)}\"");
processArguments.AppendFormat(" --load-path={0}", includePath);
}
}

foreach (var compilation in _options.GetAllCompilations())
{
var fullSource = Path.GetFullPath(Path.Combine(rootFolder, compilation.Source));
var fullTarget = Path.GetFullPath(Path.Combine(rootFolder, compilation.Target));

if (!Directory.Exists(fullSource) && !File.Exists(fullSource))
continue;

processArguments.AppendFormat(" \"{0}\":\"{1}\"", fullSource, fullTarget);
}

var process = new Process();
process.StartInfo.FileName = command.Filename;
process.StartInfo.Arguments = $"{command.Snapshot} --error-css --watch {_options.Arguments} {_options.GetLoadPathArguments()} {string.Join(" ", directories)}";
process.StartInfo.Arguments = processArguments.ToString();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
Expand Down
Loading