From 78054ee2a72ca453cc2364427f864aca68dfae78 Mon Sep 17 00:00:00 2001 From: "Dylan R. E. Moonfire" Date: Tue, 7 Sep 2021 00:15:45 -0500 Subject: [PATCH] feat: initial release --- .editorconfig | 122 + .envrc | 1 + .gitignore | 13 + .gitlab-ci.yml | 51 + .husky/commit-msg | 4 + .tool-versions | 3 + LICENSE.txt | 21 + Nitride.sln | 264 + Nitride.sln.DotSettings | 3 + Nitride.sln.Dotsettings | 1370 ++ NuGet.Config | 7 + README.md | 4 + commitlint.config.js | 3 + package-lock.json | 12304 ++++++++++++++++ package.json | 21 + release.config.js | 20 + src/Directory.Build.props | 14 + src/Nitride.Calendar/CreateCalender.cs | 104 + src/Nitride.Calendar/IsCalendar.cs | 10 + src/Nitride.Calendar/Nitride.Calendar.csproj | 37 + .../NitrideCalendarBuilderExtensions.cs | 16 + src/Nitride.Calendar/NitrideCalendarModule.cs | 6 + src/Nitride.Feeds/CreateAtomFeeds.cs | 123 + src/Nitride.Feeds/HasFeed.cs | 15 + src/Nitride.Feeds/IsFeed.cs | 14 + src/Nitride.Feeds/Nitride.Feeds.csproj | 36 + .../NitrideFeedsBuilderExtensions.cs | 16 + src/Nitride.Feeds/NitrideFeedsModule.cs | 6 + src/Nitride.Feeds/Structure/AtomAuthor.cs | 41 + src/Nitride.Feeds/Structure/AtomCategory.cs | 57 + src/Nitride.Feeds/Structure/AtomEntry.cs | 121 + src/Nitride.Feeds/Structure/AtomFeed.cs | 104 + src/Nitride.Feeds/Structure/AtomHelper.cs | 29 + src/Nitride.Feeds/Structure/XmlConstants.cs | 22 + src/Nitride.Gemtext/IsGemtext.cs | 11 + src/Nitride.Gemtext/Nitride.Gemtext.csproj | 27 + .../NitrideGemtextBuilderExtensions.cs | 14 + src/Nitride.Gemtext/NitrideGemtextModule.cs | 6 + .../CodeAnalysisExtensions.cs | 159 + src/Nitride.Generators/MessageCode.cs | 10 + .../Nitride.Generators.csproj | 19 + .../WithPropertySourceGenerator.cs | 209 + .../ApplyContentHandlebarsTemplate.cs | 74 + .../ApplyStyleHandlebarsTemplate.cs | 88 + .../HandlebarsTemplateCache.cs | 70 + .../HasHandlebarsTemplate.cs | 11 + src/Nitride.Handlebars/IdentifyHandlebars.cs | 32 + .../Nitride.Handlebars.csproj | 36 + .../NitrideHandlebarsBuilderExtensions.cs | 14 + .../NitrideHandlebarsModule.cs | 22 + src/Nitride.Handlebars/README.md | 26 + src/Nitride.Html/HtmlEntitiesToUnicode.cs | 31 + src/Nitride.Html/IsHtml.cs | 10 + src/Nitride.Html/Nitride.Html.csproj | 31 + .../NitrideHtmlBuilderExtensions.cs | 14 + src/Nitride.Html/NitrideHtmlModule.cs | 6 + src/Nitride.IO.Tests/AddPathPrefixTests.cs | 48 + src/Nitride.IO.Tests/MoveToIndexPathsTests.cs | 80 + src/Nitride.IO.Tests/Nitride.IO.Tests.csproj | 29 + src/Nitride.IO.Tests/NitrideIOTestsBase.cs | 21 + src/Nitride.IO.Tests/ReadFilesTests.cs | 97 + src/Nitride.IO.Tests/RemovePathPrefixTests.cs | 50 + src/Nitride.IO.Tests/WriteFilesTest.cs | 63 + .../Contents/FileEntryBinaryContent.cs | 35 + .../Contents/FileEntryTextContent.cs | 38 + src/Nitride.IO/Contents/ReadFiles.cs | 89 + src/Nitride.IO/Contents/WriteFiles.cs | 220 + src/Nitride.IO/Directories/ClearDirectory.cs | 82 + src/Nitride.IO/FileSystemOperation.cs | 14 + src/Nitride.IO/Nitride.IO.csproj | 37 + src/Nitride.IO/NitrideIOBuilderExtensions.cs | 14 + src/Nitride.IO/NitrideIOModule.cs | 6 + src/Nitride.IO/Paths/AddPathPrefix.cs | 48 + src/Nitride.IO/Paths/ChangePathExtension.cs | 50 + src/Nitride.IO/Paths/MoveToIndexPaths.cs | 86 + src/Nitride.IO/Paths/RemovePathPrefix.cs | 58 + src/Nitride.IO/Paths/ReplacePaths.cs | 59 + src/Nitride.IO/Paths/UPathExtensions.cs | 41 + src/Nitride.IO/README.md | 31 + src/Nitride.Javascript/InstallYarn.cs | 110 + .../Nitride.Javascript.csproj | 33 + .../NitrideJavascriptBuilderExtensions.cs | 14 + .../NitrideJavascriptModule.cs | 6 + src/Nitride.Javascript/RunWebpack.cs | 115 + src/Nitride.Javascript/YarnHelper.cs | 34 + src/Nitride.Markdown/IdentifyMarkdown.cs | 83 + src/Nitride.Markdown/IsMarkdown.cs | 10 + src/Nitride.Markdown/MarkdownOperationBase.cs | 48 + src/Nitride.Markdown/MarkdownToGemtext.cs | 40 + src/Nitride.Markdown/MarkdownToHtml.cs | 40 + .../MarkdownToOperationBaseExtension.cs | 22 + src/Nitride.Markdown/Nitride.Markdown.csproj | 37 + .../NitrideMarkdownBuilderExtensions.cs | 14 + src/Nitride.Markdown/NitrideMarkdownModule.cs | 6 + src/Nitride.Slugs/ISlugProvider.cs | 15 + src/Nitride.Slugs/Nitride.Slugs.csproj | 31 + .../NitrideSlugsBuilderExtensions.cs | 28 + src/Nitride.Slugs/NitrideSlugsModule.cs | 8 + src/Nitride.Slugs/SimpleSlugProvider.cs | 78 + .../UnicodeNormalizingSlugProvider.cs | 58 + src/Nitride.Temporal/CanExpire.cs | 10 + .../DatePipelineCommandOption.cs | 69 + .../ExpiresPipelineCommandOption.cs | 75 + .../FilterOutExpiredInstants.cs | 44 + .../FilterOutFutureInstants.cs | 30 + src/Nitride.Temporal/Nitride.Temporal.csproj | 40 + src/Nitride.Temporal/NitrideClock.cs | 144 + .../NitrideTemporalBuilderExtensions.cs | 105 + src/Nitride.Temporal/NitrideTemporalModule.cs | 15 + src/Nitride.Temporal/README.md | 42 + .../SetInstantFromComponent.cs | 88 + src/Nitride.Temporal/SetInstantFromPath.cs | 61 + src/Nitride.Tests/EntityContentTests.cs | 75 + src/Nitride.Tests/Nitride.Tests.csproj | 30 + src/Nitride.Tests/NitrideTestsBase.cs | 63 + .../Nitride.Yaml.Tests.csproj | 29 + .../ParseYamlHeaderTests.cs | 114 + src/Nitride.Yaml/Nitride.Yaml.csproj | 33 + .../NitrideYamlBuilderExtensions.cs | 14 + src/Nitride.Yaml/NitrideYamlModule.cs | 15 + src/Nitride.Yaml/ParseYamlHeader.cs | 163 + src/Nitride/Commands/BuildCommand.cs | 56 + .../Commands/IPipelineCommandOption.cs | 23 + src/Nitride/Commands/ITopLevelCommand.cs | 12 + src/Nitride/ContainerBuiltHandler.cs | 7 + .../Contents/ByteArrayBinaryContent.cs | 26 + .../Contents/EntityBinaryContentExtensions.cs | 47 + .../Contents/EntityContentExtensions.cs | 65 + .../Contents/EntityTextContentExtensions.cs | 53 + src/Nitride/Contents/FileBinaryContent.cs | 44 + src/Nitride/Contents/FileTextContent.cs | 47 + src/Nitride/Contents/IBinaryContent.cs | 19 + .../Contents/IBinaryContentConvertable.cs | 15 + src/Nitride/Contents/IContent.cs | 12 + src/Nitride/Contents/ITextContent.cs | 19 + .../Contents/ITextContentConvertable.cs | 15 + src/Nitride/Contents/README.md | 186 + src/Nitride/Contents/StringTextContent.cs | 37 + src/Nitride/Contents/TextContentExtensions.cs | 22 + src/Nitride/Entities/CreateIndexEntities.cs | 181 + .../Entities/LinkPreviousNextHandler.cs | 9 + src/Nitride/Entities/LinkSerialEntities.cs | 42 + src/Nitride/Entities/README.md | 188 + src/Nitride/ExpressionHelper.cs | 69 + src/Nitride/INitrideOperation.cs | 15 + src/Nitride/Nitride.csproj | 40 + src/Nitride/NitrideBuilder.cs | 196 + src/Nitride/NitrideLoggingBuilder.cs | 81 + src/Nitride/NitrideModule.cs | 29 + src/Nitride/NitrideModuleBase.cs | 76 + src/Nitride/NitrideOperationBase.cs | 38 + src/Nitride/NitrideOperationBaseExtensions.cs | 21 + src/Nitride/NitrideOperationExtensions.cs | 25 + src/Nitride/NitrideService.cs | 120 + src/Nitride/Pipelines/IPipeline.cs | 28 + src/Nitride/Pipelines/PipelineBase.cs | 41 + src/Nitride/Pipelines/PipelineManager.cs | 184 + src/Nitride/Pipelines/PipelineRunner.cs | 376 + src/Nitride/Pipelines/PipelineRunnerState.cs | 72 + src/Nitride/Pipelines/README.md | 191 + src/Nitride/ROADMAP.md | 9 + .../Registration/NoRegistrationAttribute.cs | 9 + .../Registration/SingletonAttribute.cs | 9 + src/Nitride/WithPropertiesAttribute.cs | 14 + 164 files changed, 22055 insertions(+) create mode 100644 .editorconfig create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100755 .husky/commit-msg create mode 100644 .tool-versions create mode 100644 LICENSE.txt create mode 100644 Nitride.sln create mode 100644 Nitride.sln.DotSettings create mode 100644 Nitride.sln.Dotsettings create mode 100644 NuGet.Config create mode 100644 README.md create mode 100644 commitlint.config.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 release.config.js create mode 100644 src/Directory.Build.props create mode 100644 src/Nitride.Calendar/CreateCalender.cs create mode 100644 src/Nitride.Calendar/IsCalendar.cs create mode 100644 src/Nitride.Calendar/Nitride.Calendar.csproj create mode 100644 src/Nitride.Calendar/NitrideCalendarBuilderExtensions.cs create mode 100644 src/Nitride.Calendar/NitrideCalendarModule.cs create mode 100644 src/Nitride.Feeds/CreateAtomFeeds.cs create mode 100644 src/Nitride.Feeds/HasFeed.cs create mode 100644 src/Nitride.Feeds/IsFeed.cs create mode 100644 src/Nitride.Feeds/Nitride.Feeds.csproj create mode 100644 src/Nitride.Feeds/NitrideFeedsBuilderExtensions.cs create mode 100644 src/Nitride.Feeds/NitrideFeedsModule.cs create mode 100644 src/Nitride.Feeds/Structure/AtomAuthor.cs create mode 100644 src/Nitride.Feeds/Structure/AtomCategory.cs create mode 100644 src/Nitride.Feeds/Structure/AtomEntry.cs create mode 100644 src/Nitride.Feeds/Structure/AtomFeed.cs create mode 100644 src/Nitride.Feeds/Structure/AtomHelper.cs create mode 100644 src/Nitride.Feeds/Structure/XmlConstants.cs create mode 100644 src/Nitride.Gemtext/IsGemtext.cs create mode 100644 src/Nitride.Gemtext/Nitride.Gemtext.csproj create mode 100644 src/Nitride.Gemtext/NitrideGemtextBuilderExtensions.cs create mode 100644 src/Nitride.Gemtext/NitrideGemtextModule.cs create mode 100644 src/Nitride.Generators/CodeAnalysisExtensions.cs create mode 100644 src/Nitride.Generators/MessageCode.cs create mode 100644 src/Nitride.Generators/Nitride.Generators.csproj create mode 100644 src/Nitride.Generators/WithPropertySourceGenerator.cs create mode 100644 src/Nitride.Handlebars/ApplyContentHandlebarsTemplate.cs create mode 100644 src/Nitride.Handlebars/ApplyStyleHandlebarsTemplate.cs create mode 100644 src/Nitride.Handlebars/HandlebarsTemplateCache.cs create mode 100644 src/Nitride.Handlebars/HasHandlebarsTemplate.cs create mode 100644 src/Nitride.Handlebars/IdentifyHandlebars.cs create mode 100644 src/Nitride.Handlebars/Nitride.Handlebars.csproj create mode 100644 src/Nitride.Handlebars/NitrideHandlebarsBuilderExtensions.cs create mode 100644 src/Nitride.Handlebars/NitrideHandlebarsModule.cs create mode 100644 src/Nitride.Handlebars/README.md create mode 100644 src/Nitride.Html/HtmlEntitiesToUnicode.cs create mode 100644 src/Nitride.Html/IsHtml.cs create mode 100644 src/Nitride.Html/Nitride.Html.csproj create mode 100644 src/Nitride.Html/NitrideHtmlBuilderExtensions.cs create mode 100644 src/Nitride.Html/NitrideHtmlModule.cs create mode 100644 src/Nitride.IO.Tests/AddPathPrefixTests.cs create mode 100644 src/Nitride.IO.Tests/MoveToIndexPathsTests.cs create mode 100644 src/Nitride.IO.Tests/Nitride.IO.Tests.csproj create mode 100644 src/Nitride.IO.Tests/NitrideIOTestsBase.cs create mode 100644 src/Nitride.IO.Tests/ReadFilesTests.cs create mode 100644 src/Nitride.IO.Tests/RemovePathPrefixTests.cs create mode 100644 src/Nitride.IO.Tests/WriteFilesTest.cs create mode 100644 src/Nitride.IO/Contents/FileEntryBinaryContent.cs create mode 100644 src/Nitride.IO/Contents/FileEntryTextContent.cs create mode 100644 src/Nitride.IO/Contents/ReadFiles.cs create mode 100644 src/Nitride.IO/Contents/WriteFiles.cs create mode 100644 src/Nitride.IO/Directories/ClearDirectory.cs create mode 100644 src/Nitride.IO/FileSystemOperation.cs create mode 100644 src/Nitride.IO/Nitride.IO.csproj create mode 100644 src/Nitride.IO/NitrideIOBuilderExtensions.cs create mode 100644 src/Nitride.IO/NitrideIOModule.cs create mode 100644 src/Nitride.IO/Paths/AddPathPrefix.cs create mode 100644 src/Nitride.IO/Paths/ChangePathExtension.cs create mode 100644 src/Nitride.IO/Paths/MoveToIndexPaths.cs create mode 100644 src/Nitride.IO/Paths/RemovePathPrefix.cs create mode 100644 src/Nitride.IO/Paths/ReplacePaths.cs create mode 100644 src/Nitride.IO/Paths/UPathExtensions.cs create mode 100644 src/Nitride.IO/README.md create mode 100644 src/Nitride.Javascript/InstallYarn.cs create mode 100644 src/Nitride.Javascript/Nitride.Javascript.csproj create mode 100644 src/Nitride.Javascript/NitrideJavascriptBuilderExtensions.cs create mode 100644 src/Nitride.Javascript/NitrideJavascriptModule.cs create mode 100644 src/Nitride.Javascript/RunWebpack.cs create mode 100644 src/Nitride.Javascript/YarnHelper.cs create mode 100644 src/Nitride.Markdown/IdentifyMarkdown.cs create mode 100644 src/Nitride.Markdown/IsMarkdown.cs create mode 100644 src/Nitride.Markdown/MarkdownOperationBase.cs create mode 100644 src/Nitride.Markdown/MarkdownToGemtext.cs create mode 100644 src/Nitride.Markdown/MarkdownToHtml.cs create mode 100644 src/Nitride.Markdown/MarkdownToOperationBaseExtension.cs create mode 100644 src/Nitride.Markdown/Nitride.Markdown.csproj create mode 100644 src/Nitride.Markdown/NitrideMarkdownBuilderExtensions.cs create mode 100644 src/Nitride.Markdown/NitrideMarkdownModule.cs create mode 100644 src/Nitride.Slugs/ISlugProvider.cs create mode 100644 src/Nitride.Slugs/Nitride.Slugs.csproj create mode 100644 src/Nitride.Slugs/NitrideSlugsBuilderExtensions.cs create mode 100644 src/Nitride.Slugs/NitrideSlugsModule.cs create mode 100644 src/Nitride.Slugs/SimpleSlugProvider.cs create mode 100644 src/Nitride.Slugs/UnicodeNormalizingSlugProvider.cs create mode 100644 src/Nitride.Temporal/CanExpire.cs create mode 100644 src/Nitride.Temporal/DatePipelineCommandOption.cs create mode 100644 src/Nitride.Temporal/ExpiresPipelineCommandOption.cs create mode 100644 src/Nitride.Temporal/FilterOutExpiredInstants.cs create mode 100644 src/Nitride.Temporal/FilterOutFutureInstants.cs create mode 100644 src/Nitride.Temporal/Nitride.Temporal.csproj create mode 100644 src/Nitride.Temporal/NitrideClock.cs create mode 100644 src/Nitride.Temporal/NitrideTemporalBuilderExtensions.cs create mode 100644 src/Nitride.Temporal/NitrideTemporalModule.cs create mode 100644 src/Nitride.Temporal/README.md create mode 100644 src/Nitride.Temporal/SetInstantFromComponent.cs create mode 100644 src/Nitride.Temporal/SetInstantFromPath.cs create mode 100644 src/Nitride.Tests/EntityContentTests.cs create mode 100644 src/Nitride.Tests/Nitride.Tests.csproj create mode 100644 src/Nitride.Tests/NitrideTestsBase.cs create mode 100644 src/Nitride.Yaml.Tests/Nitride.Yaml.Tests.csproj create mode 100644 src/Nitride.Yaml.Tests/ParseYamlHeaderTests.cs create mode 100644 src/Nitride.Yaml/Nitride.Yaml.csproj create mode 100644 src/Nitride.Yaml/NitrideYamlBuilderExtensions.cs create mode 100644 src/Nitride.Yaml/NitrideYamlModule.cs create mode 100644 src/Nitride.Yaml/ParseYamlHeader.cs create mode 100644 src/Nitride/Commands/BuildCommand.cs create mode 100644 src/Nitride/Commands/IPipelineCommandOption.cs create mode 100644 src/Nitride/Commands/ITopLevelCommand.cs create mode 100644 src/Nitride/ContainerBuiltHandler.cs create mode 100644 src/Nitride/Contents/ByteArrayBinaryContent.cs create mode 100644 src/Nitride/Contents/EntityBinaryContentExtensions.cs create mode 100644 src/Nitride/Contents/EntityContentExtensions.cs create mode 100644 src/Nitride/Contents/EntityTextContentExtensions.cs create mode 100644 src/Nitride/Contents/FileBinaryContent.cs create mode 100644 src/Nitride/Contents/FileTextContent.cs create mode 100644 src/Nitride/Contents/IBinaryContent.cs create mode 100644 src/Nitride/Contents/IBinaryContentConvertable.cs create mode 100644 src/Nitride/Contents/IContent.cs create mode 100644 src/Nitride/Contents/ITextContent.cs create mode 100644 src/Nitride/Contents/ITextContentConvertable.cs create mode 100644 src/Nitride/Contents/README.md create mode 100644 src/Nitride/Contents/StringTextContent.cs create mode 100644 src/Nitride/Contents/TextContentExtensions.cs create mode 100644 src/Nitride/Entities/CreateIndexEntities.cs create mode 100644 src/Nitride/Entities/LinkPreviousNextHandler.cs create mode 100644 src/Nitride/Entities/LinkSerialEntities.cs create mode 100644 src/Nitride/Entities/README.md create mode 100644 src/Nitride/ExpressionHelper.cs create mode 100644 src/Nitride/INitrideOperation.cs create mode 100644 src/Nitride/Nitride.csproj create mode 100644 src/Nitride/NitrideBuilder.cs create mode 100644 src/Nitride/NitrideLoggingBuilder.cs create mode 100644 src/Nitride/NitrideModule.cs create mode 100644 src/Nitride/NitrideModuleBase.cs create mode 100644 src/Nitride/NitrideOperationBase.cs create mode 100644 src/Nitride/NitrideOperationBaseExtensions.cs create mode 100644 src/Nitride/NitrideOperationExtensions.cs create mode 100644 src/Nitride/NitrideService.cs create mode 100644 src/Nitride/Pipelines/IPipeline.cs create mode 100644 src/Nitride/Pipelines/PipelineBase.cs create mode 100644 src/Nitride/Pipelines/PipelineManager.cs create mode 100644 src/Nitride/Pipelines/PipelineRunner.cs create mode 100644 src/Nitride/Pipelines/PipelineRunnerState.cs create mode 100644 src/Nitride/Pipelines/README.md create mode 100644 src/Nitride/ROADMAP.md create mode 100644 src/Nitride/Registration/NoRegistrationAttribute.cs create mode 100644 src/Nitride/Registration/SingletonAttribute.cs create mode 100644 src/Nitride/WithPropertiesAttribute.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..fc1b7bd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,122 @@ +# EditorConfig is awesome: https://EditorConfig.org + +root = true + +[*] +charset=utf-8 +end_of_line = lf +insert_final_newline=true +indent_style=space +indent_size=4 + +# Microsoft .NET properties +csharp_new_line_before_members_in_object_initializers=false +csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion +csharp_space_after_cast=false +csharp_style_var_elsewhere=false:hint +csharp_style_var_for_built_in_types=false:hint +csharp_style_var_when_type_is_apparent=true:hint +csharp_preserve_single_line_statements=false +csharp_preserve_single_line_blocks=true +dotnet_style_predefined_type_for_locals_parameters_members=true:hint +dotnet_style_predefined_type_for_member_access=true:hint +dotnet_style_qualification_for_event=true:hint +dotnet_style_qualification_for_field=true:hint +dotnet_style_qualification_for_method=true:hint +dotnet_style_qualification_for_property=true:hint +dotnet_style_require_accessibility_modifiers=for_non_interface_members:hint + +# ReSharper properties +resharper_alignment_tab_fill_style=optimal_fill +resharper_apply_on_completion=true +resharper_blank_lines_after_control_transfer_statements=1 +resharper_blank_lines_around_single_line_auto_property=1 +resharper_blank_lines_around_single_line_property=1 +resharper_blank_lines_before_single_line_comment=1 +resharper_blank_lines_between_using_groups=1 +resharper_braces_for_for=required +resharper_braces_for_foreach=required +resharper_braces_for_ifelse=required +resharper_braces_for_while=required +resharper_can_use_global_alias=false +resharper_csharp_blank_lines_around_single_line_field=1 +resharper_csharp_blank_lines_around_single_line_invocable=1 +resharper_csharp_indent_style=tab +resharper_csharp_insert_final_newline=true +resharper_csharp_keep_blank_lines_in_code=1 +resharper_csharp_keep_blank_lines_in_declarations=1 +resharper_csharp_new_line_before_while=true +resharper_csharp_use_indent_from_vs=false +resharper_csharp_wrap_arguments_style=chop_if_long +resharper_csharp_wrap_extends_list_style=chop_if_long +resharper_csharp_wrap_parameters_style=chop_if_long +resharper_css_insert_final_newline=false +resharper_enforce_line_ending_style=true +resharper_html_insert_final_newline=false +resharper_indent_nested_fixed_stmt=true +resharper_js_indent_style=tab +resharper_js_insert_final_newline=true +resharper_js_keep_blank_lines_in_code=1 +resharper_js_stick_comment=false +resharper_js_use_indent_from_vs=false +resharper_js_wrap_before_binary_opsign=true +resharper_js_wrap_chained_method_calls=chop_if_long +resharper_keep_blank_lines_between_declarations=1 +resharper_min_blank_lines_after_imports=1 +resharper_place_attribute_on_same_line=False +resharper_place_constructor_initializer_on_same_line=false +resharper_place_type_constraints_on_same_line=false +resharper_protobuf_insert_final_newline=false +resharper_qualified_using_at_nested_scope=true +resharper_resx_insert_final_newline=false +resharper_space_within_single_line_array_initializer_braces=true +resharper_use_indents_from_main_language_in_file=false +resharper_vb_insert_final_newline=false +resharper_wrap_after_declaration_lpar=true +resharper_wrap_after_invocation_lpar=true +resharper_wrap_before_extends_colon=true +resharper_wrap_before_first_type_parameter_constraint=true +resharper_wrap_before_type_parameter_langle=true +resharper_xmldoc_indent_child_elements=ZeroIndent +resharper_xmldoc_indent_text=ZeroIndent +resharper_xmldoc_insert_final_newline=false +resharper_xml_insert_final_newline=false + +# ReSharper inspection severities +resharper_check_namespace_highlighting=none +resharper_convert_to_auto_property_highlighting=none +resharper_localizable_element_highlighting=none +resharper_redundant_comma_in_attribute_list_highlighting=none +resharper_redundant_comma_in_enum_declaration_highlighting=none +resharper_redundant_comma_in_initializer_highlighting=none +resharper_string_compare_to_is_culture_specific_highlighting=none +resharper_string_index_of_is_culture_specific_1_highlighting=none +resharper_use_null_propagation_highlighting=none +resharper_use_object_or_collection_initializer_highlighting=hint +resharper_use_string_interpolation_highlighting=hint + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style=space +indent_size=2 +tab_width=2 + +[*.{cs,js,json,jsx,proto,resjson,ts,tsx}] +indent_style=space +indent_size=space +tab_width=4 + +[*.{asax,ascx,aspx,cshtml,css,htm,html,master,razor,skin,vb,xaml,xamlx,xoml}] +indent_style=space +indent_size=4 +tab_width=4 + +[*.{appxmanifest,build,config,csproj,dbml,discomap,dtd,jsproj,lsproj,njsproj,nuspec,proj,props,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}] +indent_style=space +indent_size=2 +tab_width=2 + +[*.proto] +indent_style=space +indent_size=2 +tab_width=2 diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..a63eb96 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use asdf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..50364fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +launchSettings.json + +*~ +*.user +Directory.Build.props + +obj/ +[Bb]in/ +.vs/ +.vscode/ +.idea/ +_ReSharper.Caches/ +node_modules/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..1d4e850 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,51 @@ +stages: + - build + +default: + before_script: + - curl -sL https://deb.nodesource.com/setup_15.x | bash - + - apt-get install -y nodejs + +build: + image: mcr.microsoft.com/dotnet/sdk:5.0 + stage: build + script: + # Set up the environment. + - npx npm install --ci + - npx commitlint-gitlab-ci -x @commitlint/config-conventional + + # Build and test everything. + - dotnet restore + - dotnet build + #- 'dotnet test --test-adapter-path:. --logger:"junit;LogFilePath=../artifacts/{assembly}-test-result.xml;MethodFormat=Default;FailureBodyFormat=Verbose" --collect:"XPlat Code Coverage"' + + # Summarize the output for Gitlab CI reporting. + #- dotnet new tool-manifest + #- dotnet tool install dotnet-reportgenerator-globaltool + #- dotnet tool run reportgenerator -reports:src/*/TestResults/*/coverage.cobertura.xml -targetdir:./coverage "-reporttypes:Cobertura;TextSummary" + #- grep "Line coverage" coverage/Summary.txt + + # Perform the release. + - npx semantic-release + + rules: + - if: '$CI_COMMIT_TITLE =~ /^chore\(release\)/' + when: never + - if: '$CI_COMMIT_TAG' + when: never + - if: '$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH' + when: never + - when: on_success + + artifacts: + when: always + paths: + - ./**/*test-result.xml + - ./coverage/Cobertura.xml + - ./coverage/Summary.* + - ./**/*.nupkg + reports: + junit: + - ./**/*test-result.xml + cobertura: + - ./coverage/Cobertura.xml diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..e8511ea --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx --no-install commitlint --edit $1 diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..f84212e --- /dev/null +++ b/.tool-versions @@ -0,0 +1,3 @@ +dotnet-core 5.0.100 +yarn 1.22.10 +nodejs 15.0.1 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..02b160f --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Moonfire Games + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Nitride.sln b/Nitride.sln new file mode 100644 index 0000000..84a253d --- /dev/null +++ b/Nitride.sln @@ -0,0 +1,264 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{570184FD-ECE4-4EC8-86E1-C1265E17D647}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Calendar", "src\Nitride.Calendar\Nitride.Calendar.csproj", "{D480943C-764D-4A8A-B546-642ED10586BB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Feeds", "src\Nitride.Feeds\Nitride.Feeds.csproj", "{1204DECC-654A-433A-BF82-53F98AB24DCF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Gemtext", "src\Nitride.Gemtext\Nitride.Gemtext.csproj", "{23C7CBF7-9624-457A-8296-C03F75BC9BC6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Generators", "src\Nitride.Generators\Nitride.Generators.csproj", "{4ACB11B7-1EEB-48E7-845A-528770839125}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Handlebars", "src\Nitride.Handlebars\Nitride.Handlebars.csproj", "{56E595A6-7880-416E-B328-93B9617F92A6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Html", "src\Nitride.Html\Nitride.Html.csproj", "{3F9292D3-DA50-4DBA-AE90-E33E462470A1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.IO", "src\Nitride.IO\Nitride.IO.csproj", "{534BF940-25B2-4948-A101-7890CC9C4EA5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.IO.Tests", "src\Nitride.IO.Tests\Nitride.IO.Tests.csproj", "{57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Javascript", "src\Nitride.Javascript\Nitride.Javascript.csproj", "{285A855E-B2FC-4770-AFD9-4CC67AD3C83C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Markdown", "src\Nitride.Markdown\Nitride.Markdown.csproj", "{41FF3823-7008-43B1-AD6A-92437E0600B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride", "src\Nitride\Nitride.csproj", "{757BA115-3465-46C5-ADDB-7B96D6900F33}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Slugs", "src\Nitride.Slugs\Nitride.Slugs.csproj", "{17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Temporal", "src\Nitride.Temporal\Nitride.Temporal.csproj", "{FEFFA469-245E-45A7-A094-3F0E89CEF3A9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Tests", "src\Nitride.Tests\Nitride.Tests.csproj", "{A0EED899-35C7-4C1C-8BBF-F7FD2F281839}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Yaml", "src\Nitride.Yaml\Nitride.Yaml.csproj", "{1A5B4B4D-CF32-4458-8F2C-83A2AE494837}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nitride.Yaml.Tests", "src\Nitride.Yaml.Tests\Nitride.Yaml.Tests.csproj", "{C8CD60C2-2A26-48AE-848D-A71AEE2267C9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D480943C-764D-4A8A-B546-642ED10586BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Debug|x64.ActiveCfg = Debug|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Debug|x64.Build.0 = Debug|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Debug|x86.ActiveCfg = Debug|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Debug|x86.Build.0 = Debug|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Release|Any CPU.Build.0 = Release|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Release|x64.ActiveCfg = Release|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Release|x64.Build.0 = Release|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Release|x86.ActiveCfg = Release|Any CPU + {D480943C-764D-4A8A-B546-642ED10586BB}.Release|x86.Build.0 = Release|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Debug|x64.ActiveCfg = Debug|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Debug|x64.Build.0 = Debug|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Debug|x86.ActiveCfg = Debug|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Debug|x86.Build.0 = Debug|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Release|Any CPU.Build.0 = Release|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Release|x64.ActiveCfg = Release|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Release|x64.Build.0 = Release|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Release|x86.ActiveCfg = Release|Any CPU + {1204DECC-654A-433A-BF82-53F98AB24DCF}.Release|x86.Build.0 = Release|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Debug|x64.ActiveCfg = Debug|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Debug|x64.Build.0 = Debug|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Debug|x86.ActiveCfg = Debug|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Debug|x86.Build.0 = Debug|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Release|Any CPU.Build.0 = Release|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Release|x64.ActiveCfg = Release|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Release|x64.Build.0 = Release|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Release|x86.ActiveCfg = Release|Any CPU + {23C7CBF7-9624-457A-8296-C03F75BC9BC6}.Release|x86.Build.0 = Release|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Debug|x64.ActiveCfg = Debug|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Debug|x64.Build.0 = Debug|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Debug|x86.ActiveCfg = Debug|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Debug|x86.Build.0 = Debug|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Release|Any CPU.Build.0 = Release|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Release|x64.ActiveCfg = Release|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Release|x64.Build.0 = Release|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Release|x86.ActiveCfg = Release|Any CPU + {4ACB11B7-1EEB-48E7-845A-528770839125}.Release|x86.Build.0 = Release|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Debug|x64.ActiveCfg = Debug|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Debug|x64.Build.0 = Debug|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Debug|x86.ActiveCfg = Debug|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Debug|x86.Build.0 = Debug|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Release|Any CPU.Build.0 = Release|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Release|x64.ActiveCfg = Release|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Release|x64.Build.0 = Release|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Release|x86.ActiveCfg = Release|Any CPU + {56E595A6-7880-416E-B328-93B9617F92A6}.Release|x86.Build.0 = Release|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Debug|x64.ActiveCfg = Debug|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Debug|x64.Build.0 = Debug|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Debug|x86.ActiveCfg = Debug|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Debug|x86.Build.0 = Debug|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Release|Any CPU.Build.0 = Release|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Release|x64.ActiveCfg = Release|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Release|x64.Build.0 = Release|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Release|x86.ActiveCfg = Release|Any CPU + {3F9292D3-DA50-4DBA-AE90-E33E462470A1}.Release|x86.Build.0 = Release|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Debug|x64.ActiveCfg = Debug|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Debug|x64.Build.0 = Debug|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Debug|x86.ActiveCfg = Debug|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Debug|x86.Build.0 = Debug|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Release|Any CPU.Build.0 = Release|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Release|x64.ActiveCfg = Release|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Release|x64.Build.0 = Release|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Release|x86.ActiveCfg = Release|Any CPU + {534BF940-25B2-4948-A101-7890CC9C4EA5}.Release|x86.Build.0 = Release|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Debug|x64.ActiveCfg = Debug|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Debug|x64.Build.0 = Debug|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Debug|x86.ActiveCfg = Debug|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Debug|x86.Build.0 = Debug|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Release|Any CPU.Build.0 = Release|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Release|x64.ActiveCfg = Release|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Release|x64.Build.0 = Release|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Release|x86.ActiveCfg = Release|Any CPU + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D}.Release|x86.Build.0 = Release|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Debug|x64.ActiveCfg = Debug|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Debug|x64.Build.0 = Debug|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Debug|x86.ActiveCfg = Debug|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Debug|x86.Build.0 = Debug|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Release|Any CPU.Build.0 = Release|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Release|x64.ActiveCfg = Release|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Release|x64.Build.0 = Release|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Release|x86.ActiveCfg = Release|Any CPU + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C}.Release|x86.Build.0 = Release|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Debug|x64.ActiveCfg = Debug|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Debug|x64.Build.0 = Debug|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Debug|x86.ActiveCfg = Debug|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Debug|x86.Build.0 = Debug|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Release|Any CPU.Build.0 = Release|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Release|x64.ActiveCfg = Release|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Release|x64.Build.0 = Release|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Release|x86.ActiveCfg = Release|Any CPU + {41FF3823-7008-43B1-AD6A-92437E0600B7}.Release|x86.Build.0 = Release|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Debug|x64.ActiveCfg = Debug|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Debug|x64.Build.0 = Debug|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Debug|x86.ActiveCfg = Debug|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Debug|x86.Build.0 = Debug|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Release|Any CPU.Build.0 = Release|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Release|x64.ActiveCfg = Release|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Release|x64.Build.0 = Release|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Release|x86.ActiveCfg = Release|Any CPU + {757BA115-3465-46C5-ADDB-7B96D6900F33}.Release|x86.Build.0 = Release|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Debug|x64.ActiveCfg = Debug|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Debug|x64.Build.0 = Debug|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Debug|x86.ActiveCfg = Debug|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Debug|x86.Build.0 = Debug|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Release|Any CPU.Build.0 = Release|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Release|x64.ActiveCfg = Release|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Release|x64.Build.0 = Release|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Release|x86.ActiveCfg = Release|Any CPU + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5}.Release|x86.Build.0 = Release|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Debug|x64.ActiveCfg = Debug|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Debug|x64.Build.0 = Debug|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Debug|x86.ActiveCfg = Debug|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Debug|x86.Build.0 = Debug|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Release|Any CPU.Build.0 = Release|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Release|x64.ActiveCfg = Release|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Release|x64.Build.0 = Release|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Release|x86.ActiveCfg = Release|Any CPU + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9}.Release|x86.Build.0 = Release|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Debug|x64.ActiveCfg = Debug|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Debug|x64.Build.0 = Debug|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Debug|x86.ActiveCfg = Debug|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Debug|x86.Build.0 = Debug|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Release|Any CPU.Build.0 = Release|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Release|x64.ActiveCfg = Release|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Release|x64.Build.0 = Release|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Release|x86.ActiveCfg = Release|Any CPU + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839}.Release|x86.Build.0 = Release|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Debug|x64.ActiveCfg = Debug|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Debug|x64.Build.0 = Debug|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Debug|x86.ActiveCfg = Debug|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Debug|x86.Build.0 = Debug|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Release|Any CPU.Build.0 = Release|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Release|x64.ActiveCfg = Release|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Release|x64.Build.0 = Release|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Release|x86.ActiveCfg = Release|Any CPU + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837}.Release|x86.Build.0 = Release|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Debug|x64.ActiveCfg = Debug|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Debug|x64.Build.0 = Debug|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Debug|x86.ActiveCfg = Debug|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Debug|x86.Build.0 = Debug|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Release|Any CPU.Build.0 = Release|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Release|x64.ActiveCfg = Release|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Release|x64.Build.0 = Release|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Release|x86.ActiveCfg = Release|Any CPU + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D480943C-764D-4A8A-B546-642ED10586BB} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {1204DECC-654A-433A-BF82-53F98AB24DCF} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {23C7CBF7-9624-457A-8296-C03F75BC9BC6} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {4ACB11B7-1EEB-48E7-845A-528770839125} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {56E595A6-7880-416E-B328-93B9617F92A6} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {3F9292D3-DA50-4DBA-AE90-E33E462470A1} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {534BF940-25B2-4948-A101-7890CC9C4EA5} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {57F4C4C3-A2C9-4D6C-AA51-9A7EC926918D} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {285A855E-B2FC-4770-AFD9-4CC67AD3C83C} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {41FF3823-7008-43B1-AD6A-92437E0600B7} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {757BA115-3465-46C5-ADDB-7B96D6900F33} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {17BF2A03-2C1D-4F75-9C18-B4341FAAF1A5} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {FEFFA469-245E-45A7-A094-3F0E89CEF3A9} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {A0EED899-35C7-4C1C-8BBF-F7FD2F281839} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {1A5B4B4D-CF32-4458-8F2C-83A2AE494837} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + {C8CD60C2-2A26-48AE-848D-A71AEE2267C9} = {570184FD-ECE4-4EC8-86E1-C1265E17D647} + EndGlobalSection +EndGlobal diff --git a/Nitride.sln.DotSettings b/Nitride.sln.DotSettings new file mode 100644 index 0000000..8899e23 --- /dev/null +++ b/Nitride.sln.DotSettings @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file diff --git a/Nitride.sln.Dotsettings b/Nitride.sln.Dotsettings new file mode 100644 index 0000000..06b6404 --- /dev/null +++ b/Nitride.sln.Dotsettings @@ -0,0 +1,1370 @@ + + Inherit + + + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + HINT + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + DoHide + HINT + <?xml version="1.0" encoding="utf-16"?><Profile name="Project"><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_BOTH</BehavourStyle><LocalVariableStyle>IMPLICIT_WHEN_INITIALIZER_HAS_TYPE</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName>Namespaces</RegionName></CSOptimizeUsings><CSUseAutoProperty>True</CSUseAutoProperty><CSArrangeQualifiers>True</CSArrangeQualifiers><CSEnforceVarKeywordUsageSettings>True</CSEnforceVarKeywordUsageSettings><CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="False" AddMissingParentheses="True" ArrangeBraces="False" ArrangeAttributes="True" ArrangeArgumentsStyle="True" ArrangeCodeBodyStyle="True" ArrangeVarStyle="True" /><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSUpdateFileHeader>True</CSUpdateFileHeader><JsReformatCode>True</JsReformatCode><JsFormatDocComments>True</JsFormatDocComments><CSharpFormatDocComments>True</CSharpFormatDocComments><CSReorderTypeMembers>True</CSReorderTypeMembers><JsInsertSemicolon>True</JsInsertSemicolon><HtmlReformatCode>True</HtmlReformatCode></Profile> + <?xml version="1.0" encoding="utf-16"?><Profile name="Remove Redundant Qualifiers"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>False</CSUseAutoProperty><CSMakeFieldReadonly>False</CSMakeFieldReadonly><CSUseVar><BehavourStyle>DISABLED</BehavourStyle><LocalVariableStyle>IMPLICIT_WHEN_INITIALIZER_HAS_TYPE</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSUpdateFileHeader>False</CSUpdateFileHeader><VBOptimizeImports>False</VBOptimizeImports><VBShortenReferences>False</VBShortenReferences><CSOptimizeUsings><OptimizeUsings>False</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName /></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><VBReformatCode>False</VBReformatCode><CSReformatCode>False</CSReformatCode><CSReorderTypeMembers>False</CSReorderTypeMembers></Profile> + Full Cleanup + Project + OPTIMAL_FILL + LF + True + False + True + Required + Required + Required + Required + 15 + OPTIMAL_FILL + False + False + False + False + False + + False + False + False + NEXT_LINE + 1 + 1 + 1 + 1 + 1 + 1 + + + NEXT_LINE + SEPARATE + ALWAYS_ADD + ALWAYS_ADD + ALWAYS_ADD + ALWAYS_ADD + ALWAYS_ADD + ALWAYS_ADD + True + Tab + NEXT_LINE + 1 + 1 + False + True + EXPANDED + NEVER + NEVER + False + False + NEVER + False + False + True + False + True + + False + True + False + False + + True + True + CHOP_IF_LONG + CHOP_IF_LONG + True + True + True + True + CHOP_IF_LONG + CHOP_IF_LONG + CHOP_IF_LONG + 80 + CHOP_IF_LONG + OPTIMAL_FILL + OPTIMAL_FILL + OPTIMAL_FILL + + Tab + True + 1 + 1 + True + 1 + False + False + True + True + True + CHOP_IF_LONG + OPTIMAL_FILL + OPTIMAL_FILL + OPTIMAL_FILL + OPTIMAL_FILL + ZeroIndent + ZeroIndent + 80 + OPTIMAL_FILL + <?xml version="1.0" encoding="utf-16"?> +<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> + <TypePattern DisplayName="StyleCop Layout" RemoveRegions="All"> + <TypePattern.Match> + <Or> + <Kind Is="Class" /> + <Kind Is="Struct" /> + <Kind Is="Interface" /> + </Or> + </TypePattern.Match> + <Entry DisplayName="Constants"> + <Entry.Match> + <Kind Is="Constant" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Static fields"> + <Entry.Match> + <And> + <Kind Is="Field" /> + <Static /> + </And> + </Entry.Match> + <Entry.SortBy> + <Kind Order="Constant Field" /> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Fields"> + <Entry.Match> + <Kind Is="Field" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Constructors and destructors" Priority="200"> + <Entry.Match> + <Or> + <Kind Is="Constructor" /> + <Kind Is="Destructor" /> + </Or> + </Entry.Match> + <Entry.SortBy> + <Static /> + <Kind Order="Constructor Destructor" /> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Delegates"> + <Entry.Match> + <Kind Is="Delegate" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Static /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Public events"> + <Entry.Match> + <And> + <Kind Is="Event" /> + <Access Is="Public" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public" /> + <Static /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Interface events"> + <Entry.Match> + <And> + <Kind Is="Event" /> + <ImplementsInterface /> + </And> + </Entry.Match> + <Entry.SortBy> + <ImplementsInterface Immediate="True" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Other events"> + <Entry.Match> + <Kind Is="Event" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Static /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Enums"> + <Entry.Match> + <Kind Is="Enum" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Interfaces"> + <Entry.Match> + <Kind Is="Interface" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Public properties"> + <Entry.Match> + <And> + <Kind Is="Property" /> + <Access Is="Public" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public" /> + <Static /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Interface properties"> + <Entry.Match> + <And> + <Kind Is="Property" /> + <ImplementsInterface /> + </And> + </Entry.Match> + <Entry.SortBy> + <ImplementsInterface Immediate="True" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Other properties"> + <Entry.Match> + <Kind Is="Property" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Static /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Public indexers" Priority="1000"> + <Entry.Match> + <And> + <Kind Is="Indexer" /> + <Access Is="Public" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public" /> + <Static /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Interface indexers" Priority="1000"> + <Entry.Match> + <And> + <Kind Is="Indexer" /> + <ImplementsInterface /> + </And> + </Entry.Match> + <Entry.SortBy> + <ImplementsInterface Immediate="True" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Other indexers" Priority="1000"> + <Entry.Match> + <Kind Is="Indexer" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Static /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Public methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <Access Is="Public" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public" /> + <Static /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Interface methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <ImplementsInterface /> + </And> + </Entry.Match> + <Entry.SortBy> + <ImplementsInterface Immediate="True" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Other methods"> + <Entry.Match> + <Kind Is="Method" /> + </Entry.Match> + <Entry.SortBy> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Static /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Operators"> + <Entry.Match> + <Kind Is="Operator" /> + </Entry.Match> + </Entry> + <Entry DisplayName="Nested structs" Priority="600"> + <Entry.Match> + <Kind Is="Struct" /> + </Entry.Match> + <Entry.SortBy> + <Static /> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Nested classes" Priority="700"> + <Entry.Match> + <Kind Is="Class" /> + </Entry.Match> + <Entry.SortBy> + <Static /> + <Access Order="Public Internal ProtectedInternal Protected Private" /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="All other members" /> + </TypePattern> +</Patterns> + <?xml version="1.0" encoding="utf-8" ?> + +<!-- +I. Overall + +I.1 Each pattern can have <Match>....</Match> element. For the given type declaration, the pattern with the match, evaluated to 'true' with the largest weight, will be used +I.2 Each pattern consists of the sequence of <Entry>...</Entry> elements. Type member declarations are distributed between entries +I.3 If pattern has RemoveAllRegions="true" attribute, then all regions will be cleared prior to reordering. Otherwise, only auto-generated regions will be cleared +I.4 The contents of each entry is sorted by given keys (First key is primary, next key is secondary, etc). Then the declarations are grouped and en-regioned by given property + +II. Available match operands + +Each operand may have Weight="..." attribute. This weight will be added to the match weight if the operand is evaluated to 'true'. +The default weight is 1 + +II.1 Boolean functions: +II.1.1 <And>....</And> +II.1.2 <Or>....</Or> +II.1.3 <Not>....</Not> + +II.2 Operands +II.2.1 <Kind Is="..."/>. Kinds are: class, struct, interface, enum, delegate, type, constructor, destructor, property, indexer, method, operator, field, constant, event, member +II.2.2 <Name Is="..." [IgnoreCase="true/false"] />. The 'Is' attribute contains regular expression +II.2.3 <HasAttribute CLRName="..." [Inherit="true/false"] />. The 'CLRName' attribute contains regular expression +II.2.4 <Access Is="..."/>. The 'Is' values are: public, protected, internal, protected internal, private +II.2.5 <Static/> +II.2.6 <Abstract/> +II.2.7 <Virtual/> +II.2.8 <Override/> +II.2.9 <Sealed/> +II.2.10 <Readonly/> +II.2.11 <ImplementsInterface CLRName="..."/>. The 'CLRName' attribute contains regular expression +II.2.12 <HandlesEvent /> +--> + +<Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns"> + + <!--Do not reorder COM interfaces--> + <Pattern> + <Match> + <And Weight="100"> + <Kind Is="interface"/> + <HasAttribute CLRName="System.Runtime.InteropServices.InterfaceTypeAttribute"/> + </And> + </Match> + </Pattern> + + <!--Default pattern--> + <Pattern> + + <!--public delegate--> + <Entry> + <Match> + <And Weight="100"> + <Access Is="public"/> + <Kind Is="delegate"/> + </And> + </Match> + <Sort> + <Name/> + </Sort> + <Group Region="Delegates"/> + </Entry> + + <!--public enum--> + <Entry> + <Match> + <And Weight="100"> + <Access Is="public"/> + <Kind Is="enum"/> + </And> + </Match> + <Sort> + <Name/> + </Sort> + <Group> + <Name Region="${Name} enum"/> + </Group> + </Entry> + + <!--fields and constants--> + <Entry> + <Match> + <Or> + <Kind Is="constant"/> + <Kind Is="field"/> + </Or> + </Match> + <Sort> + <Name/> + </Sort> + </Entry> + + <!--Constructors. Place static one first--> + <Entry> + <Match> + <Kind Is="constructor"/> + </Match> + <Sort> + <Static/> + </Sort> + </Entry> + + <!--properties, indexers--> + <Entry> + <Match> + <Or> + <Kind Is="property"/> + <Kind Is="indexer"/> + </Or> + </Match> + <Sort> + <Name/> + </Sort> + </Entry> + + <!--all other members--> + <Entry> + <Sort> + <Name/> + </Sort> + </Entry> + + <!--nested types--> + <Entry> + <Match> + <Kind Is="type"/> + </Match> + <Sort> + <Name/> + </Sort> + <Group> + <Name Region="Nested type: ${Name}"/> + </Group> + </Entry> + </Pattern> + +</Patterns> + + CustomLayout + False + False + True + UseExplicitType + UseVarWhenEvident + UseVarWhenEvident + True + + False + + + ATI + CUSIP + + + + + IO + IP + + + + + PDF + RPC + RPO + XML + On$event$ + exception + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> + + + + + + + + $object$_On$event$ + exception + <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> + <Policy Inspect="True" Prefix="m_" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="m_" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> + <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Private Events"><ElementKinds><Kind Name="EVENT" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="m_" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private, Protected, ProtectedInternal, Internal" Description="Dual rules for readonly/constants"><ElementKinds><Kind Name="READONLY_FIELD" /><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB"><ExtraRule Prefix="m_" Suffix="" Style="AaBb" /></Policy></Policy> + <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Public" Description="Dual rules for public fields"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="AA_BB" /></Policy></Policy> + <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Public" Description="Dual rules for public fields"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="AA_BB" /></Policy></Policy> + <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private, Protected, ProtectedInternal, Internal" Description="Dual rules for readonly/constants"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB"><ExtraRule Prefix="m_" Suffix="" Style="AaBb" /></Policy></Policy> + <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Private Events"><ElementKinds><Kind Name="EVENT" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="m_" Suffix="" Style="AaBb" /></Policy> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + C:\Users\rc04727\AppData\Local\JetBrains\Transient\ReSharperPlatformVs15\v11_ede7cb44\SolutionCaches + LIVE_MONITOR + LIVE_MONITOR + DO_NOTHING + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + DO_NOTHING + LIVE_MONITOR + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + + Always + False + ForWarningsOrErrors + tag + 10 + ( ) + 14 + 15 + #region(WEI) + 4 + 16 + + False + + using + False + 0 + NUnit Test + 1 + Class (WEI) + False + + 2 + 4 + 3 + True + True + Events + Imported 1/13/2012 + Create Thread-Safe Event + True + Event with Synchronous Invoke + True + public event $EventHandler$<$EventArgs$> $EventName$ +{ + add + { + lock(m_EventLock) + { + m_$PrivateEventVariable$Event += value; + } + } + remove + { + lock (m_EventLock) + { + m_$PrivateEventVariable$Event -= value; + } + } +} +$END$ + +private event $EventHandler$<$EventArgs$> m_$PrivateEventVariable$Event; + +/// <summary> +/// Raises the $EventName$ event synchronously. +/// </summary> +/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param> +private void Raise$EventName$($EventArgs$ args) +{ + $EventHandler$<$EventArgs$> handler = m_$PrivateEventVariable$Event; + if (handler != null) + { + handler(this, args); + } +} + + True + 1 + True + 0 + True + 2 + True + capitalize(EventName) + 3 + True + 2.0 + InCSharpTypeMember + True + True + cs + Test + True + NUnit Test + True + True + #region Namespaces + +using System; + +using NUnit.Framework; + +#endregion + +namespace $NameSpace$ +{ + [TestFixture] + public class $TestClass$ + { + #region Public Methods + + #region Test Administration + + [TestFixtureSetUp] + public void TestFixtureSetup() + { + } + + [TestFixtureTearDown] + public void TestFixtureTeardown() + { + } + + [SetUp] + public void Setup() + { + } + + [TearDown] + public void Teardown() + { + } + + #endregion Test Administration + + #region Test Methods + + #endregion Test Methods + + #endregion Public Methods + + #region Private Fields + + #endregion Private Fields + + #region Private Methods + + #endregion Private Methods + } +} + True + 0 + True + 1 + True + InCSharpProjectFile + True + True + IDisposable Implementation for a Base Class + True + IDisposable Base Class + True + #region IDisposable Implementation + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // NOTE: Leave out the finalizer altogether if this class doesn't own + // unmanaged resources itself, but leave the other methods + // exactly as they are. + + ~$ClassName$() + { + Dispose(false); + } + + + protected virtual void Dispose(bool disposing) + { + // Even if we don't have a finalizer, we need to check the disposing argument. + // It might still be false if we're being finalized due to the fact that a derived + // class introduced a finalizer. + + if (disposing) + { + // free managed resources + } + + // free native resources if there are any. + } + +#endregion IDisposable Implementation + + True + 0 + True + 2.0 + InCSharpTypeMember + True + True + Imported 1/13/2012 + WEI Standard + cs + Class + False + WEI Class + True + Class (WEI) + True + #region Namespaces + +using System; + +#endregion Namespaces + +namespace $NAMESPACE$ +{ + + public class $CLASS$ + { + #region Constructors + public $CLASS$() + { + $END$ + } + + #endregion Constructors + + #region Public Properties + #endregion Public Properties + + #region Public Methods + #endregion Public Methods + + #region Private Fields + #endregion Private Fields + + #region Private Methods + #endregion Private Methods + + } + +} + True + getFileNameWithoutExtension() + 0 + True + fileDefaultNamespace() + 1 + True + InCSharpProjectFile + True + True + Imported 1/13/2012 + Methods + Unit Test Method + True + Test Method + True + [Test] +[Category("")] +public void $MethodUnderTest$_$Scenario$_$ExpectedResult$() +{ + // Arrange +$END$ + + // Act + + // Assert +} + True + 2 + True + 0 + True + 1 + True + 2.0 + InCSharpTypeMember + True + True + Imported 1/13/2012 + LLBLGen Templates + Insert a Using(DataAccessAdapter) + True + UDAA + True + using(DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionString.GetString("connString"), true)) +{ + $END$ +} + True + 2.0 + InCSharpStatement + True + True + ( ) + True + True + ($SELECTION$) + True + 2.0 + InCSharpExpression + True + True + Inserts a strongly-type identifier property. + True + 0 + True + getCurrentTime("yyyy_MM_dd_HHmmss") + -1 + 1 + True + True + 2.0 + InCSharpFile + InsertIdProperty + True + /// <inheritdoc /> + public override $Type$Id $Type$Id => new $Type$Id($When$); + + True + True + Imported 1/13/2012 + LLBLGen Templates + Retrieve Collection with a Filter + True + FetchCollection + True + EntityCollection $ResultCollectionName$Collection = new EntityCollection(new $EntityType$EntityFactory()); +using(DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionString.GetString("connString"), true)) +{ +RelationPredicateBucket filterBucket = new RelationPredicateBucket(); +IPredicateExpression predicateExpression = new PredicateExpression(); +predicateExpression.Add(PredicateFactory.CompareValue($EntityType$FieldIndex.$FilterField$, ComparisonOperator.Equal, $FilterValue$)); +filterBucket.PredicateExpression.Add(predicateExpression); + +dataAccessAdapter.FetchEntityCollection($ResultCollectionName$Collection, filterBucket); +} +$END$ + True + 0 + True + complete() + 2 + True + 3 + True + decapitalize(EntityType) + 1 + True + 2.0 + InCSharpStatement + True + True + Inserts a strongly-typed identifier. + True + 0 + False + + + + True + getCurrentTime("yyyy_MM_dd_HHmmss") + -1 + 1 + True + True + 2.0 + InCSharpFile + InsertId + True + new $Type$Id($When$) + True + True + Calls the session server to validate a user + True + ValidateUser + True + SessionServerFactory.GetSessionServer().IsValid(requestorInformation.SessionId); + True + 2.0 + InCSharpStatement + True + True + Imported 1/13/2012 + LLBLGen Templates + Retrieve Single Entity with a Filter + True + FetchEntityWithFilter + True + EntityCollection $CollectionType$Collection = new EntityCollection(new $EntityType$EntityFactory()); +using(DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionString.GetString("connString"), true)) +{ +RelationPredicateBucket filterBucket = new RelationPredicateBucket(); +IPredicateExpression predicateExpression = new PredicateExpression(); +predicateExpression.Add(PredicateFactory.CompareValue($EntityType$FieldIndex.$FilterField$, ComparisonOperator.Equal, $FilterValue$)); +filterBucket.PredicateExpression.Add(predicateExpression); + +dataAccessAdapter.FetchEntityCollection($CollectionType$Collection, filterBucket); +} +$EntityType$Entity $EntityObject$ = null; +if ($CollectionType$Collection.Count > 0) +$EntityObject$ = ($EntityType$Entity)$CollectionType$Collection[0]; +$END$ + True + decapitalize(EntityType) + 1 + True + suggestVariableName() + 4 + True + 0 + True + complete() + 2 + True + 3 + True + 2.0 + InCSharpStatement + True + True + Events + Imported 1/13/2012 + Create a thread-safe event with an asynchronous raise method + True + Event with Asynchronous Invoke + True + public event $EventHandler$<$EventArgs$> $EventName$ +{ + add + { + lock(m_EventLock) + { + m_$PrivateEventVariable$Event += value; + } + } + remove + { + lock (m_EventLock) + { + m_$PrivateEventVariable$Event -= value; + } + } +} +$END$ + +private event $EventHandler$<$EventArgs$> m_$PrivateEventVariable$Event; + +/// <summary> +/// Raises the $EventName$ event Asynchronously. +/// </summary> +/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param> +private void Raise$EventName$Async($EventArgs$ args) +{ + Delegate[] subscribers = null; + lock (m_EventLock) + { + if (m_$PrivateEventVariable$Event != null) + { + subscribers = m_$PrivateEventVariable$Event.GetInvocationList(); + } + } + + if (subscribers != null) + { + foreach ($EventHandler$ subscriber in subscribers) + { + subscriber.BeginInvoke(this, args, null, null); + } + } +} + + True + 1 + True + 0 + True + 2 + True + capitalize(EventName) + 3 + True + 2.0 + InCSharpTypeMember + True + True + Imported 1/13/2012 + LLBLGen Templates + Fetch an entity with a joined relation + True + FetchEntityWithJoin + True + EntityCollection $CollectionType$Collection = new EntityCollection(new $EntityType1$EntityFactory()); +using (DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionString.GetString("connString"), true)) +{ + RelationPredicateBucket filterBucket = new RelationPredicateBucket(); + + // Filter The First Entity on a Field Value + IPredicateExpression predicateExpression = new PredicateExpression(); + predicateExpression.Add(PredicateFactory.CompareValue($EntityType1$FieldIndex.$FilterField1$, ComparisonOperator.Equal, $FilterValue1$)); + filterBucket.PredicateExpression.Add(predicateExpression); + + // Add the Join Relation + filterBucket.Relations.Add($EntityType1$Entity.Relations.$EntityRelationship$); + + // Filter The Second Entity on a Field Value + IPredicateExpression predicateExpression$EntityType2$ = new PredicateExpression(); + predicateExpression$EntityType2$.Add(PredicateFactory.CompareValue($EntityType2$FieldIndex.$FilterField2$, ComparisonOperator.Equal, $FilterValue2$)); + filterBucket.PredicateExpression.Add(predicateExpressionIdentifier); + + // Prefetch Joined Entity + IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.$EntityType1$Entity); + prefetchPath.Add($EntityType1$Entity.PrefetchPath$EntityType2$, 0, predicateExpression$EntityType2$, new $EntityType2$EntityFactory()); + + dataAccessAdapter.FetchEntityCollection($CollectionType$Collection, filterBucket, prefetchPath); +} + +$EntityType1$Entity $EntityObject$; +if ($CollectionType$Collection.Count > 0) +{ + $EntityObject$ = ($EntityType1$Entity)$CollectionType$Collection[0]; + // Use the values in $EntityObject$ and the related entity $EntityType2$ +} + + True + decapitalize(EntityType1) + 0 + True + suggestVariableName() + 8 + True + complete() + 4 + True + 1 + True + 5 + True + complete() + 2 + True + complete() + 6 + True + 3 + True + 7 + True + 2.0 + InCSharpStatement + False + + + + + + + + + + + + + + + + False + + + + + + + + + + + + + + True + True + Imported 1/13/2012 + LLBLGen Templates + Fetch selected columns from single Entity + True + FetchSelectedColumns + True + using(DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionString.GetString("connString"), true)) +{ + ResultsetFields resultsetFields = new ResultsetFields($NUMBEROFFIELDS$); + int fieldIndex = 0; + resultsetFields.DefineField($ENTITY_TYPE$Fields.$FIELD1$, fieldIndex++); + resultsetFields.DefineField($ENTITY_TYPE$Fields.$FIELD2$, fieldIndex++); + // Add more fields as needed. Number of added fields must match parameter in constructor for ResultSetFields + + DataTable resultSet = new DataTable(); + dataAccessAdapter.FetchTypedList(resultsetFields, resultSet, null, $DISTINCT_TRUE_FALSE$); +} +$END$ + + True + 4 + True + 1 + True + 2 + True + 3 + True + 0 + True + 2.0 + InCSharpStatement + True + True + Imported 1/13/2012 + LLBLGen Templates + Retrieve an Entity by its Primary Key + True + FetchEntity + True + $EntityType$Entity $EntityObject$ = new $EntityType$Entity($PrimaryKeyValue$); +bool found; +using(DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionString.GetString("connString"), true)) +{ +found = dataAccessAdapter.FetchEntity($EntityObject$); +} +$END$ + True + suggestVariableName() + 1 + True + 0 + True + 2 + True + 2.0 + InCSharpStatement + True + True + Imported 1/13/2012 + LLBLGen Templates + Delete an entity + True + DeleteEntity + True + $EntityType$Entity $EntityObject$ = new $EntityType$Entity($PrimaryKeyValue$); +bool found; +using(DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionString.GetString("connString"), true)) +{ +found = dataAccessAdapter.DeleteEntity($EntityObject$); +} +$END$ + True + 1 + True + 0 + True + 2 + True + 2.0 + InCSharpStatement + True + True + Imported 1/13/2012 + LLBLGen Templates + Insert an Entity with LLBLGen + True + InsertEntity + True + $EntityType$Entity $EntityObject$ = new $EntityType$Entity(); +//$EntityObject$.fieldName1 = fieldValue1; + +using(DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionString.GetString("connString"), true)) +{ + dataAccessAdapter.SaveEntity($EntityObject$); + // newIdentityKey = $EntityObject$.IdentityKeyField; +} + + True + suggestVariableName() + 1 + True + 0 + True + 2.0 + InCSharpStatement + True + diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..af8eac9 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..f94878b --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +Nitride CIL +=========== + +A static site generator based on the [Gallium ECS](https://gitlab.com/mfgames-cil/gallium-cil/). diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..db74d15 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ["@commitlint/config-conventional"], +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..adf313c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,12304 @@ +{ + "name": "gallium-cil", + "version": "1.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "1.0.1", + "devDependencies": { + "@commitlint/cli": "^13.1.0", + "@commitlint/config-conventional": "^13.1.0", + "@semantic-release/changelog": "^5.0.1", + "@semantic-release/git": "^9.0.0", + "@semantic-release/gitlab": "^6.2.2", + "@semantic-release/npm": "^7.1.3", + "commitlint-gitlab-ci": "^0.0.4", + "husky": "^7.0.2", + "semantic-release": "^17.4.7", + "semantic-release-dotnet": "^1.0.0", + "semantic-release-nuget": "^1.1.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.12.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@commitlint/cli": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/format": "^13.1.0", + "@commitlint/lint": "^13.1.0", + "@commitlint/load": "^13.1.0", + "@commitlint/read": "^13.1.0", + "@commitlint/types": "^13.1.0", + "lodash": "^4.17.19", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-conventionalcommits": "^4.3.1" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/ensure": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^13.1.0", + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "13.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/format": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^13.1.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/format/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^13.1.0", + "semver": "7.3.5" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/is-ignored/node_modules/semver": { + "version": "7.3.5", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@commitlint/lint": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^13.1.0", + "@commitlint/parse": "^13.1.0", + "@commitlint/rules": "^13.1.0", + "@commitlint/types": "^13.1.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/load": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/execute-rule": "^13.0.0", + "@commitlint/resolve-extends": "^13.0.0", + "@commitlint/types": "^13.1.0", + "chalk": "^4.0.0", + "cosmiconfig": "^7.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/load/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@commitlint/message": { + "version": "13.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/parse": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^13.1.0", + "conventional-changelog-angular": "^5.0.11", + "conventional-commits-parser": "^3.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/read": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^13.0.0", + "@commitlint/types": "^13.1.0", + "fs-extra": "^10.0.0", + "git-raw-commits": "^2.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/read/node_modules/fs-extra": { + "version": "10.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "13.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/rules": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^13.1.0", + "@commitlint/message": "^13.0.0", + "@commitlint/to-lines": "^13.0.0", + "@commitlint/types": "^13.1.0", + "execa": "^5.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "13.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/top-level": { + "version": "13.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/top-level/node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@commitlint/top-level/node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@commitlint/types": { + "version": "13.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=v12" + } + }, + "node_modules/@commitlint/types/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-token": { + "version": "2.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.0.0" + } + }, + "node_modules/@octokit/core": { + "version": "3.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.4.12", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.1.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/endpoint": { + "version": "6.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "4.5.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^5.3.0", + "@octokit/types": "^6.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "3.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "2.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.4.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "4.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.1.0", + "deprecation": "^2.3.1" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/request": { + "version": "5.4.12", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.0.0", + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.1", + "once": "^1.4.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/request-error": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^6.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/@octokit/rest": { + "version": "18.0.12", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^3.2.3", + "@octokit/plugin-paginate-rest": "^2.6.2", + "@octokit/plugin-request-log": "^1.0.2", + "@octokit/plugin-rest-endpoint-methods": "4.4.1" + } + }, + "node_modules/@octokit/types": { + "version": "6.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^3.1.1", + "@types/node": ">= 8" + } + }, + "node_modules/@semantic-release/changelog": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^2.1.0", + "aggregate-error": "^3.0.0", + "fs-extra": "^9.0.0", + "lodash": "^4.17.4" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "semantic-release": ">=15.8.0 <18.0.0" + } + }, + "node_modules/@semantic-release/commit-analyzer": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^5.0.0", + "conventional-commits-filter": "^2.0.0", + "conventional-commits-parser": "^3.0.7", + "debug": "^4.0.0", + "import-from": "^3.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "semantic-release": ">=16.0.0 <18.0.0" + } + }, + "node_modules/@semantic-release/error": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@semantic-release/git": { + "version": "9.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^2.1.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "execa": "^4.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.0", + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "semantic-release": ">=16.0.0 <18.0.0" + } + }, + "node_modules/@semantic-release/git/node_modules/execa": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@semantic-release/github": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/rest": "^18.0.0", + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "bottleneck": "^2.18.1", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "fs-extra": "^9.0.0", + "globby": "^11.0.0", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "issue-parser": "^6.0.0", + "lodash": "^4.17.4", + "mime": "^2.4.3", + "p-filter": "^2.0.0", + "p-retry": "^4.0.0", + "url-join": "^4.0.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "semantic-release": ">=16.0.0 <18.0.0" + } + }, + "node_modules/@semantic-release/gitlab": { + "version": "6.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "escape-string-regexp": "^3.0.0", + "form-data": "^3.0.0", + "fs-extra": "^9.0.0", + "globby": "^11.0.0", + "got": "^10.5.2", + "lodash": "^4.17.11", + "parse-path": "^4.0.0", + "url-join": "^4.0.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "semantic-release": ">=15.8.0 <18.0.0" + } + }, + "node_modules/@semantic-release/gitlab/node_modules/escape-string-regexp": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm": { + "version": "7.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "execa": "^5.0.0", + "fs-extra": "^10.0.0", + "lodash": "^4.17.15", + "nerf-dart": "^1.0.0", + "normalize-url": "^6.0.0", + "npm": "^7.0.0", + "rc": "^1.2.8", + "read-pkg": "^5.0.0", + "registry-auth-token": "^4.0.0", + "semver": "^7.1.2", + "tempy": "^1.0.0" + }, + "engines": { + "node": ">=10.19" + }, + "peerDependencies": { + "semantic-release": ">=16.0.0 <18.0.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/fs-extra": { + "version": "10.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@semantic-release/npm/node_modules/semver": { + "version": "7.3.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@semantic-release/release-notes-generator": { + "version": "9.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^5.0.0", + "conventional-changelog-writer": "^4.0.0", + "conventional-commits-filter": "^2.0.0", + "conventional-commits-parser": "^3.0.0", + "debug": "^4.0.0", + "get-stream": "^5.0.0", + "import-from": "^3.0.0", + "into-stream": "^5.0.0", + "lodash": "^4.17.4", + "read-pkg-up": "^7.0.0" + }, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "semantic-release": ">=15.8.0 <18.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/minimist": { + "version": "1.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "14.14.22", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansicolors": { + "version": "0.3.2", + "dev": true, + "license": "MIT" + }, + "node_modules/argv-formatter": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/array-ify": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/before-after-hook": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-lookup": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/keyv": "^3.1.1", + "keyv": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys/node_modules/map-obj": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cardinal": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + }, + "bin": { + "cdl": "bin/cdl.js" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-table": { + "version": "0.3.6", + "dev": true, + "dependencies": { + "colors": "1.0.3" + }, + "engines": { + "node": ">= 0.2.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/clone-response/node_modules/mimic-response": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commitlint-gitlab-ci": { + "version": "0.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/cli": "^13.1.0" + }, + "bin": { + "commitlint-gitlab-ci": "bin/commitlint-gitlab-ci.sh" + } + }, + "node_modules/compare-func": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/conventional-changelog-angular": { + "version": "5.0.12", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "4.5.0", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "compare-func": "^2.0.0", + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.6", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "bin": { + "conventional-changelog-writer": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-changelog-writer/node_modules/readable-stream": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/conventional-changelog-writer/node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/conventional-changelog-writer/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/conventional-changelog-writer/node_modules/through2": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/conventional-commits-filter": { + "version": "2.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-commits-parser": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^2.0.0", + "through2": "^4.0.0", + "trim-off-newlines": "^1.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/conventional-commits-parser/node_modules/readable-stream": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/conventional-commits-parser/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/conventional-commits-parser/node_modules/split2": { + "version": "2.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "through2": "^2.0.2" + } + }, + "node_modules/conventional-commits-parser/node_modules/split2/node_modules/readable-stream": { + "version": "2.3.7", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/conventional-commits-parser/node_modules/split2/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/conventional-commits-parser/node_modules/split2/node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/conventional-commits-parser/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/conventional-commits-parser/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/conventional-commits-parser/node_modules/through2": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dargs": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/decamelize": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/del": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-ci": { + "version": "5.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^4.0.0", + "java-properties": "^1.0.0" + }, + "engines": { + "node": ">=10.13" + } + }, + "node_modules/env-ci/node_modules/execa": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/human-signals": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/fast-glob": { + "version": "3.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fastq": { + "version": "1.10.0", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/filter-obj": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/find-versions": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver-regex": "^3.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-log-parser": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "~0.6.6" + } + }, + "node_modules/git-raw-commits": { + "version": "2.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "dargs": "^7.0.0", + "lodash.template": "^4.0.2", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/git-raw-commits/node_modules/readable-stream": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/git-raw-commits/node_modules/split2": { + "version": "3.2.2", + "dev": true, + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/git-raw-commits/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/git-raw-commits/node_modules/through2": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/glob": { + "version": "7.1.7", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-promise": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/glob": "^7.1.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/ahmadnassri" + }, + "peerDependencies": { + "glob": "^7.1.6" + } + }, + "node_modules/global-dirs": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "10.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^2.0.0", + "@szmarczak/http-timer": "^4.0.0", + "@types/cacheable-request": "^6.0.1", + "cacheable-lookup": "^2.0.0", + "cacheable-request": "^7.0.1", + "decompress-response": "^5.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^5.0.0", + "lowercase-keys": "^2.0.0", + "mimic-response": "^2.1.0", + "p-cancelable": "^2.0.0", + "p-event": "^4.0.0", + "responselike": "^2.0.0", + "to-readable-stream": "^2.0.0", + "type-fest": "^0.10.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/type-fest": { + "version": "0.10.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.6", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hook-std": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.8", + "dev": true, + "license": "ISC" + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/husky": { + "version": "7.0.2", + "dev": true, + "license": "MIT", + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ignore": { + "version": "5.1.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "dev": true, + "license": "ISC" + }, + "node_modules/into-stream": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-ssh": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^1.1.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-text-path": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/issue-parser": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + }, + "engines": { + "node": ">=10.13" + } + }, + "node_modules/java-properties": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/keyv": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.1.6", + "dev": true, + "license": "MIT" + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.capitalize": { + "version": "4.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.template": { + "version": "4.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/map-obj": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/marked": { + "version": "2.1.3", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/marked-terminal": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.1", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "cli-table": "^0.3.1", + "node-emoji": "^1.10.0", + "supports-hyperlinks": "^2.1.0" + }, + "peerDependencies": { + "marked": "^1.0.0 || ^2.0.0" + } + }, + "node_modules/marked-terminal/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/meow": { + "version": "8.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/hosted-git-info": { + "version": "3.0.7", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/normalize-package-data": { + "version": "3.0.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/semver": { + "version": "7.3.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mime": { + "version": "2.5.0", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.49.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.32", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.49.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "dev": true, + "license": "MIT" + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/modify-values": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/nerf-dart": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm": { + "version": "7.22.0", + "bundleDependencies": [ + "@npmcli/arborist", + "@npmcli/ci-detect", + "@npmcli/config", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/run-script", + "abbrev", + "ansicolors", + "ansistyles", + "archy", + "cacache", + "chalk", + "chownr", + "cli-columns", + "cli-table3", + "columnify", + "fastest-levenshtein", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmhook", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minipass", + "minipass-pipeline", + "mkdirp", + "mkdirp-infer-owner", + "ms", + "node-gyp", + "nopt", + "npm-audit-report", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "opener", + "pacote", + "parse-conflict-json", + "qrcode-terminal", + "read", + "read-package-json", + "read-package-json-fast", + "readdir-scoped-modules", + "rimraf", + "semver", + "ssri", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which", + "write-file-atomic", + "@gar/promisify", + "@npmcli/disparity-colors", + "@npmcli/fs", + "@npmcli/git", + "@npmcli/installed-package-contents", + "@npmcli/metavuln-calculator", + "@npmcli/move-file", + "@npmcli/name-from-folder", + "@npmcli/node-gyp", + "@npmcli/promise-spawn", + "@tootallnate/once", + "agent-base", + "agentkeepalive", + "aggregate-error", + "ajv", + "ansi-regex", + "ansi-styles", + "aproba", + "are-we-there-yet", + "asap", + "asn1", + "assert-plus", + "asynckit", + "aws-sign2", + "aws4", + "balanced-match", + "bcrypt-pbkdf", + "bin-links", + "binary-extensions", + "brace-expansion", + "builtins", + "caseless", + "cidr-regex", + "clean-stack", + "clone", + "cmd-shim", + "code-point-at", + "color-convert", + "color-name", + "color-support", + "colors", + "combined-stream", + "common-ancestor-path", + "concat-map", + "console-control-strings", + "core-util-is", + "dashdash", + "debug", + "debuglog", + "defaults", + "delayed-stream", + "delegates", + "depd", + "dezalgo", + "diff", + "ecc-jsbn", + "emoji-regex", + "encoding", + "env-paths", + "err-code", + "extend", + "extsprintf", + "fast-deep-equal", + "fast-json-stable-stringify", + "forever-agent", + "fs-minipass", + "fs.realpath", + "function-bind", + "gauge", + "getpass", + "har-schema", + "har-validator", + "has", + "has-flag", + "has-unicode", + "http-cache-semantics", + "http-proxy-agent", + "http-signature", + "https-proxy-agent", + "humanize-ms", + "iconv-lite", + "ignore-walk", + "imurmurhash", + "indent-string", + "infer-owner", + "inflight", + "inherits", + "ip", + "ip-regex", + "is-core-module", + "is-fullwidth-code-point", + "is-lambda", + "is-typedarray", + "isexe", + "isstream", + "jsbn", + "json-schema", + "json-schema-traverse", + "json-stringify-nice", + "json-stringify-safe", + "jsonparse", + "jsprim", + "just-diff", + "just-diff-apply", + "lru-cache", + "mime-db", + "mime-types", + "minimatch", + "minipass-collect", + "minipass-fetch", + "minipass-flush", + "minipass-json-stream", + "minipass-sized", + "minizlib", + "mute-stream", + "negotiator", + "normalize-package-data", + "npm-bundled", + "npm-install-checks", + "npm-normalize-package-bin", + "npm-packlist", + "number-is-nan", + "oauth-sign", + "object-assign", + "once", + "p-map", + "path-is-absolute", + "performance-now", + "proc-log", + "promise-all-reject-late", + "promise-call-limit", + "promise-inflight", + "promise-retry", + "promzard", + "psl", + "punycode", + "qs", + "read-cmd-shim", + "readable-stream", + "request", + "retry", + "safe-buffer", + "safer-buffer", + "set-blocking", + "signal-exit", + "smart-buffer", + "socks", + "socks-proxy-agent", + "spdx-correct", + "spdx-exceptions", + "spdx-expression-parse", + "spdx-license-ids", + "sshpk", + "string_decoder", + "string-width", + "stringify-package", + "strip-ansi", + "supports-color", + "tunnel-agent", + "tweetnacl", + "typedarray-to-buffer", + "unique-filename", + "unique-slug", + "uri-js", + "util-deprecate", + "uuid", + "validate-npm-package-license", + "verror", + "walk-up-path", + "wcwidth", + "wide-align", + "wrappy", + "yallist" + ], + "dev": true, + "license": "Artistic-2.0", + "workspaces": [ + "docs", + "packages/*" + ], + "dependencies": { + "@npmcli/arborist": "^2.8.3", + "@npmcli/ci-detect": "^1.2.0", + "@npmcli/config": "^2.3.0", + "@npmcli/map-workspaces": "^1.0.4", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^1.8.6", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "archy": "~1.0.0", + "cacache": "^15.3.0", + "chalk": "^4.1.2", + "chownr": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.6.0", + "columnify": "~1.5.4", + "fastest-levenshtein": "^1.0.12", + "glob": "^7.1.7", + "graceful-fs": "^4.2.8", + "hosted-git-info": "^4.0.2", + "ini": "^2.0.0", + "init-package-json": "^2.0.4", + "is-cidr": "^4.0.2", + "json-parse-even-better-errors": "^2.3.1", + "libnpmaccess": "^4.0.2", + "libnpmdiff": "^2.0.4", + "libnpmexec": "^2.0.1", + "libnpmfund": "^1.1.0", + "libnpmhook": "^6.0.2", + "libnpmorg": "^2.0.2", + "libnpmpack": "^2.0.1", + "libnpmpublish": "^4.0.1", + "libnpmsearch": "^3.1.1", + "libnpmteam": "^2.0.3", + "libnpmversion": "^1.2.1", + "make-fetch-happen": "^9.1.0", + "minipass": "^3.1.3", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "ms": "^2.1.2", + "node-gyp": "^7.1.2", + "nopt": "^5.0.0", + "npm-audit-report": "^2.1.5", + "npm-package-arg": "^8.1.5", + "npm-pick-manifest": "^6.1.1", + "npm-profile": "^5.0.3", + "npm-registry-fetch": "^11.0.0", + "npm-user-validate": "^1.0.1", + "npmlog": "^5.0.1", + "opener": "^1.5.2", + "pacote": "^11.3.5", + "parse-conflict-json": "^1.1.1", + "qrcode-terminal": "^0.12.0", + "read": "~1.0.7", + "read-package-json": "^4.1.1", + "read-package-json-fast": "^2.0.3", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "tar": "^6.1.11", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^1.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^2.0.2", + "write-file-atomic": "^3.0.3" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/@gar/promisify": { + "version": "1.1.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "2.8.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/map-workspaces": "^1.0.2", + "@npmcli/metavuln-calculator": "^1.1.0", + "@npmcli/move-file": "^1.1.0", + "@npmcli/name-from-folder": "^1.0.1", + "@npmcli/node-gyp": "^1.0.1", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^1.8.2", + "bin-links": "^2.2.1", + "cacache": "^15.0.3", + "common-ancestor-path": "^1.0.1", + "json-parse-even-better-errors": "^2.3.1", + "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^8.1.5", + "npm-pick-manifest": "^6.1.0", + "npm-registry-fetch": "^11.0.0", + "pacote": "^11.3.5", + "parse-conflict-json": "^1.1.1", + "proc-log": "^1.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^2.0.2", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "treeverse": "^1.0.4", + "walk-up-path": "^1.0.0" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/@npmcli/ci-detect": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "2.3.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ini": "^2.0.0", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "semver": "^7.3.4", + "walk-up-path": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/@npmcli/disparity-colors": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ansi-styles": "^4.3.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "1.0.7", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^1.0.1", + "glob": "^7.1.6", + "minimatch": "^3.0.4", + "read-package-json-fast": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^15.0.5", + "pacote": "^11.1.11", + "semver": "^7.3.2" + } + }, + "node_modules/npm/node_modules/@npmcli/move-file": { + "version": "1.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^2.3.1" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "1.3.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "infer-owner": "^1.0.4" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "1.8.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^7.1.0", + "read-package-json-fast": "^2.0.1" + } + }, + "node_modules/npm/node_modules/@tootallnate/once": { + "version": "1.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/npm/node_modules/agentkeepalive": { + "version": "4.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/npm/node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/npm/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/ansicolors": { + "version": "0.3.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ansistyles": { + "version": "0.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/are-we-there-yet": { + "version": "1.1.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/asap": { + "version": "2.0.6", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/asn1": { + "version": "0.2.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/npm/node_modules/assert-plus": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/aws-sign2": { + "version": "0.7.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/aws4": { + "version": "1.11.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/npm/node_modules/bin-links": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^4.0.1", + "mkdirp": "^1.0.3", + "npm-normalize-package-bin": "^1.0.0", + "read-cmd-shim": "^2.0.0", + "rimraf": "^3.0.0", + "write-file-atomic": "^3.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm/node_modules/builtins": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/cacache": { + "version": "15.3.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/caseless": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "ip-regex": "^4.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/cli-columns": { + "version": "3.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/cli-table3": { + "version": "0.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/npm/node_modules/cli-table3/node_modules/ansi-regex": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cli-table3/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cli-table3/node_modules/strip-ansi": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/clone": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "mkdirp-infer-owner": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/code-point-at": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/npm/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/color-support": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/npm/node_modules/colors": { + "version": "1.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/npm/node_modules/columnify": { + "version": "1.5.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "node_modules/npm/node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/core-util-is": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/dashdash": { + "version": "1.14.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.3.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/debuglog": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/defaults": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/npm/node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/npm/node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/depd": { + "version": "1.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/dezalgo": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/diff": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/ecc-jsbn": { + "version": "0.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/extend": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/extsprintf": { + "version": "1.3.0", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.12", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/forever-agent": { + "version": "0.6.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/function-bind": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/gauge": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1 || ^2.0.0", + "strip-ansi": "^3.0.1 || ^4.0.0", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/getpass": { + "version": "0.1.7", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "7.1.7", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.8", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/har-schema": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/har-validator": { + "version": "5.1.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/has": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/npm/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/http-signature": { + "version": "1.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/humanize-ms": { + "version": "1.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/infer-owner": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/ini": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "2.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "npm-package-arg": "^8.1.2", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ip": { + "version": "1.1.5", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^3.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/is-core-module": { + "version": "2.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/is-lambda": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/is-typedarray": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/isstream": { + "version": "0.1.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/jsbn": { + "version": "0.1.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/json-schema": { + "version": "0.2.3", + "dev": true, + "inBundle": true + }, + "node_modules/npm/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/json-stringify-safe": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/jsprim": { + "version": "1.4.1", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/npm/node_modules/just-diff": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "minipass": "^3.1.1", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "2.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/disparity-colors": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", + "binary-extensions": "^2.2.0", + "diff": "^5.0.0", + "minimatch": "^3.0.4", + "npm-package-arg": "^8.1.4", + "pacote": "^11.3.4", + "tar": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^2.3.0", + "@npmcli/ci-detect": "^1.3.0", + "@npmcli/run-script": "^1.8.4", + "chalk": "^4.1.0", + "mkdirp-infer-owner": "^2.0.0", + "npm-package-arg": "^8.1.2", + "pacote": "^11.3.1", + "proc-log": "^1.0.0", + "read": "^1.0.7", + "read-package-json-fast": "^2.0.2", + "walk-up-path": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^2.5.0" + } + }, + "node_modules/npm/node_modules/libnpmhook": { + "version": "6.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/run-script": "^1.8.3", + "npm-package-arg": "^8.1.0", + "pacote": "^11.2.6" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "normalize-package-data": "^3.0.2", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0", + "semver": "^7.1.3", + "ssri": "^8.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "3.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^11.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "2.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "1.2.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^2.0.7", + "@npmcli/run-script": "^1.8.4", + "json-parse-even-better-errors": "^2.3.1", + "semver": "^7.3.5", + "stringify-package": "^1.0.1" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "9.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/mime-db": { + "version": "1.49.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/mime-types": { + "version": "2.1.32", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.49.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "3.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "1.4.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-json-stream": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/mkdirp-infer-owner": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "infer-owner": "^1.0.4", + "mkdirp": "^1.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "0.0.8", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/negotiator": { + "version": "0.6.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "7.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/aproba": { + "version": "1.2.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/node-gyp/node_modules/gauge": { + "version": "2.7.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/npmlog": { + "version": "4.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/string-width": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/normalize-package-data": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "2.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "1.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "8.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "2.2.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "6.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "5.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^11.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "11.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/npmlog": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/npm/node_modules/npmlog/node_modules/are-we-there-yet": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/number-is-nan": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/oauth-sign": { + "version": "0.9.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/once": { + "version": "1.4.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/opener": { + "version": "1.5.2", + "dev": true, + "inBundle": true, + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "11.3.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^2.1.0", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^11.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "just-diff": "^3.0.1", + "just-diff-apply": "^3.0.0" + } + }, + "node_modules/npm/node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/performance-now": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/proc-log": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-inflight": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "0.3.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "1" + } + }, + "node_modules/npm/node_modules/psl": { + "version": "1.8.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/punycode": { + "version": "2.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/qs": { + "version": "6.5.2", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/npm/node_modules/read": { + "version": "1.0.7", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/read-package-json": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", + "npm-normalize-package-bin": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/read-package-json-fast": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/readable-stream": { + "version": "3.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/npm/node_modules/request": { + "version": "2.88.2", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/npm/node_modules/request/node_modules/tough-cookie": { + "version": "2.5.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/semver": { + "version": "7.3.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.6.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.3.0", + "dev": true, + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.10", + "dev": true, + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/sshpk": { + "version": "1.16.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ssri": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/npm/node_modules/string-width": { + "version": "2.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/stringify-package": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "6.1.11", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/treeverse": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/tunnel-agent": { + "version": "0.6.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/tweetnacl": { + "version": "0.14.5", + "dev": true, + "inBundle": true, + "license": "Unlicense" + }, + "node_modules/npm/node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/npm/node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/uuid": { + "version": "3.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/npm/node_modules/verror": { + "version": "1.10.0", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/wcwidth": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/npm/node_modules/which": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/wide-align": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/npm/node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/object-inspect": { + "version": "1.11.0", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-each-series": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-event": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-timeout": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-filter": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-is-promise": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate/node_modules/p-try": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-reduce": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "^0.12.0", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-path": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-ssh": "^1.3.0", + "protocols": "^1.4.0", + "qs": "^6.9.4", + "query-string": "^6.13.8" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-conf": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/protocols": { + "version": "1.4.8", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/q": { + "version": "1.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.10.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/query-string": { + "version": "6.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/redent": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redeyed": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "esprima": "~4.0.0" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.19.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-global": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "global-dirs": "^0.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/responselike": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.1.10", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.2.4", + "dev": true, + "license": "ISC" + }, + "node_modules/semantic-release": { + "version": "17.4.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/commit-analyzer": "^8.0.0", + "@semantic-release/error": "^2.2.0", + "@semantic-release/github": "^7.0.0", + "@semantic-release/npm": "^7.0.0", + "@semantic-release/release-notes-generator": "^9.0.0", + "aggregate-error": "^3.0.0", + "cosmiconfig": "^7.0.0", + "debug": "^4.0.0", + "env-ci": "^5.0.0", + "execa": "^5.0.0", + "figures": "^3.0.0", + "find-versions": "^4.0.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^2.0.0", + "hosted-git-info": "^4.0.0", + "lodash": "^4.17.21", + "marked": "^2.0.0", + "marked-terminal": "^4.1.1", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "p-reduce": "^2.0.0", + "read-pkg-up": "^7.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "semver-diff": "^3.1.1", + "signale": "^1.2.1", + "yargs": "^16.2.0" + }, + "bin": { + "semantic-release": "bin/semantic-release.js" + }, + "engines": { + "node": ">=10.19" + } + }, + "node_modules/semantic-release-dotnet": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.1.7", + "glob-promise": "^4.2.0", + "xml-js": "^1.6.11" + } + }, + "node_modules/semantic-release-nuget": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semantic-release-nuget/-/semantic-release-nuget-1.1.0.tgz", + "integrity": "sha512-Eaqb39E+dPTgYgHif0/P6cUj7IxZxI9e2BgmfE+NkRlPArpRPa94UZTi8UFMbEKiKg0IaNnAO79yexUPcZnuHA==", + "dev": true + }, + "node_modules/semantic-release/node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/hosted-git-info": { + "version": "4.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semantic-release/node_modules/semver": { + "version": "7.3.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semantic-release/node_modules/yargs": { + "version": "16.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-regex": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "dev": true, + "license": "ISC" + }, + "node_modules/signale": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/signale/node_modules/figures": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-error-forwarder": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.7", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/split": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/split-on-first": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/split2": { + "version": "1.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "through2": "~2.0.0" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-extensions": { + "version": "1.9.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/through": { + "version": "2.3.8", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/to-readable-stream": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/traverse": { + "version": "0.6.6", + "dev": true, + "license": "MIT" + }, + "node_modules/trim-newlines": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/trim-off-newlines": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/type-fest": { + "version": "0.6.0", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/uglify-js": { + "version": "3.12.5", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/xml-js": { + "version": "1.6.11", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "1.10.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@commitlint/cli": { + "version": "13.1.0", + "dev": true, + "requires": { + "@commitlint/format": "^13.1.0", + "@commitlint/lint": "^13.1.0", + "@commitlint/load": "^13.1.0", + "@commitlint/read": "^13.1.0", + "@commitlint/types": "^13.1.0", + "lodash": "^4.17.19", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0", + "yargs": "^17.0.0" + } + }, + "@commitlint/config-conventional": { + "version": "13.1.0", + "dev": true, + "requires": { + "conventional-changelog-conventionalcommits": "^4.3.1" + } + }, + "@commitlint/ensure": { + "version": "13.1.0", + "dev": true, + "requires": { + "@commitlint/types": "^13.1.0", + "lodash": "^4.17.19" + } + }, + "@commitlint/execute-rule": { + "version": "13.0.0", + "dev": true + }, + "@commitlint/format": { + "version": "13.1.0", + "dev": true, + "requires": { + "@commitlint/types": "^13.1.0", + "chalk": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@commitlint/is-ignored": { + "version": "13.1.0", + "dev": true, + "requires": { + "@commitlint/types": "^13.1.0", + "semver": "7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@commitlint/lint": { + "version": "13.1.0", + "dev": true, + "requires": { + "@commitlint/is-ignored": "^13.1.0", + "@commitlint/parse": "^13.1.0", + "@commitlint/rules": "^13.1.0", + "@commitlint/types": "^13.1.0" + } + }, + "@commitlint/load": { + "version": "13.1.0", + "dev": true, + "requires": { + "@commitlint/execute-rule": "^13.0.0", + "@commitlint/resolve-extends": "^13.0.0", + "@commitlint/types": "^13.1.0", + "chalk": "^4.0.0", + "cosmiconfig": "^7.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@commitlint/message": { + "version": "13.0.0", + "dev": true + }, + "@commitlint/parse": { + "version": "13.1.0", + "dev": true, + "requires": { + "@commitlint/types": "^13.1.0", + "conventional-changelog-angular": "^5.0.11", + "conventional-commits-parser": "^3.0.0" + } + }, + "@commitlint/read": { + "version": "13.1.0", + "dev": true, + "requires": { + "@commitlint/top-level": "^13.0.0", + "@commitlint/types": "^13.1.0", + "fs-extra": "^10.0.0", + "git-raw-commits": "^2.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "10.0.0", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@commitlint/resolve-extends": { + "version": "13.0.0", + "dev": true, + "requires": { + "import-fresh": "^3.0.0", + "lodash": "^4.17.19", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0" + } + }, + "@commitlint/rules": { + "version": "13.1.0", + "dev": true, + "requires": { + "@commitlint/ensure": "^13.1.0", + "@commitlint/message": "^13.0.0", + "@commitlint/to-lines": "^13.0.0", + "@commitlint/types": "^13.1.0", + "execa": "^5.0.0" + } + }, + "@commitlint/to-lines": { + "version": "13.0.0", + "dev": true + }, + "@commitlint/top-level": { + "version": "13.0.0", + "dev": true, + "requires": { + "find-up": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "5.0.0", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "dev": true + } + } + }, + "@commitlint/types": { + "version": "13.1.0", + "dev": true, + "requires": { + "chalk": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.4", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.4", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.6", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + } + }, + "@octokit/auth-token": { + "version": "2.4.4", + "dev": true, + "requires": { + "@octokit/types": "^6.0.0" + } + }, + "@octokit/core": { + "version": "3.2.4", + "dev": true, + "requires": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.4.12", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.1.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.10", + "dev": true, + "requires": { + "@octokit/types": "^6.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "4.5.8", + "dev": true, + "requires": { + "@octokit/request": "^5.3.0", + "@octokit/types": "^6.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "3.1.1", + "dev": true + }, + "@octokit/plugin-paginate-rest": { + "version": "2.8.0", + "dev": true, + "requires": { + "@octokit/types": "^6.4.0" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.2", + "dev": true, + "requires": {} + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "4.4.1", + "dev": true, + "requires": { + "@octokit/types": "^6.1.0", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "version": "5.4.12", + "dev": true, + "requires": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.0.0", + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.1", + "once": "^1.4.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/request-error": { + "version": "2.0.4", + "dev": true, + "requires": { + "@octokit/types": "^6.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "18.0.12", + "dev": true, + "requires": { + "@octokit/core": "^3.2.3", + "@octokit/plugin-paginate-rest": "^2.6.2", + "@octokit/plugin-request-log": "^1.0.2", + "@octokit/plugin-rest-endpoint-methods": "4.4.1" + } + }, + "@octokit/types": { + "version": "6.4.2", + "dev": true, + "requires": { + "@octokit/openapi-types": "^3.1.1", + "@types/node": ">= 8" + } + }, + "@semantic-release/changelog": { + "version": "5.0.1", + "dev": true, + "requires": { + "@semantic-release/error": "^2.1.0", + "aggregate-error": "^3.0.0", + "fs-extra": "^9.0.0", + "lodash": "^4.17.4" + } + }, + "@semantic-release/commit-analyzer": { + "version": "8.0.1", + "dev": true, + "requires": { + "conventional-changelog-angular": "^5.0.0", + "conventional-commits-filter": "^2.0.0", + "conventional-commits-parser": "^3.0.7", + "debug": "^4.0.0", + "import-from": "^3.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.2" + } + }, + "@semantic-release/error": { + "version": "2.2.0", + "dev": true + }, + "@semantic-release/git": { + "version": "9.0.0", + "dev": true, + "requires": { + "@semantic-release/error": "^2.1.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "execa": "^4.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.0", + "p-reduce": "^2.0.0" + }, + "dependencies": { + "execa": { + "version": "4.1.0", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + } + } + }, + "@semantic-release/github": { + "version": "7.2.0", + "dev": true, + "requires": { + "@octokit/rest": "^18.0.0", + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "bottleneck": "^2.18.1", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "fs-extra": "^9.0.0", + "globby": "^11.0.0", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "issue-parser": "^6.0.0", + "lodash": "^4.17.4", + "mime": "^2.4.3", + "p-filter": "^2.0.0", + "p-retry": "^4.0.0", + "url-join": "^4.0.0" + } + }, + "@semantic-release/gitlab": { + "version": "6.2.2", + "dev": true, + "requires": { + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "escape-string-regexp": "^3.0.0", + "form-data": "^3.0.0", + "fs-extra": "^9.0.0", + "globby": "^11.0.0", + "got": "^10.5.2", + "lodash": "^4.17.11", + "parse-path": "^4.0.0", + "url-join": "^4.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "3.0.0", + "dev": true + } + } + }, + "@semantic-release/npm": { + "version": "7.1.3", + "dev": true, + "requires": { + "@semantic-release/error": "^2.2.0", + "aggregate-error": "^3.0.0", + "execa": "^5.0.0", + "fs-extra": "^10.0.0", + "lodash": "^4.17.15", + "nerf-dart": "^1.0.0", + "normalize-url": "^6.0.0", + "npm": "^7.0.0", + "rc": "^1.2.8", + "read-pkg": "^5.0.0", + "registry-auth-token": "^4.0.0", + "semver": "^7.1.2", + "tempy": "^1.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "10.0.0", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "semver": { + "version": "7.3.4", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@semantic-release/release-notes-generator": { + "version": "9.0.1", + "dev": true, + "requires": { + "conventional-changelog-angular": "^5.0.0", + "conventional-changelog-writer": "^4.0.0", + "conventional-commits-filter": "^2.0.0", + "conventional-commits-parser": "^3.0.0", + "debug": "^4.0.0", + "get-stream": "^5.0.0", + "import-from": "^3.0.0", + "into-stream": "^5.0.0", + "lodash": "^4.17.4", + "read-pkg-up": "^7.0.0" + } + }, + "@sindresorhus/is": { + "version": "2.1.1", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "4.0.6", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "dev": true + }, + "@types/cacheable-request": { + "version": "6.0.2", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "@types/glob": { + "version": "7.1.4", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "dev": true + }, + "@types/keyv": { + "version": "3.1.2", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.5", + "dev": true + }, + "@types/minimist": { + "version": "1.2.1", + "dev": true + }, + "@types/node": { + "version": "14.14.22", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "dev": true + }, + "@types/responselike": { + "version": "1.0.0", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/retry": { + "version": "0.12.0", + "dev": true + }, + "aggregate-error": { + "version": "3.1.0", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.0", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "ansicolors": { + "version": "0.3.2", + "dev": true + }, + "argv-formatter": { + "version": "1.0.0", + "dev": true + }, + "array-ify": { + "version": "1.0.0", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "dev": true + }, + "before-after-hook": { + "version": "2.1.0", + "dev": true + }, + "bottleneck": { + "version": "2.19.5", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "cacheable-lookup": { + "version": "2.0.1", + "dev": true, + "requires": { + "@types/keyv": "^3.1.1", + "keyv": "^4.0.0" + } + }, + "cacheable-request": { + "version": "7.0.2", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "dev": true + }, + "camelcase-keys": { + "version": "6.2.2", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "dev": true + }, + "map-obj": { + "version": "4.1.0", + "dev": true + } + } + }, + "cardinal": { + "version": "2.1.1", + "dev": true, + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } + }, + "chalk": { + "version": "2.4.2", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "clean-stack": { + "version": "2.2.0", + "dev": true + }, + "cli-table": { + "version": "0.3.6", + "dev": true, + "requires": { + "colors": "1.0.3" + } + }, + "cliui": { + "version": "7.0.4", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + }, + "dependencies": { + "mimic-response": { + "version": "1.0.1", + "dev": true + } + } + }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, + "colors": { + "version": "1.0.3", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commitlint-gitlab-ci": { + "version": "0.0.4", + "dev": true, + "requires": { + "@commitlint/cli": "^13.1.0" + } + }, + "compare-func": { + "version": "2.0.0", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "concat-map": { + "version": "0.0.1", + "dev": true + }, + "conventional-changelog-angular": { + "version": "5.0.12", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "q": "^1.5.1" + } + }, + "conventional-changelog-conventionalcommits": { + "version": "4.5.0", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + } + }, + "conventional-changelog-writer": { + "version": "4.1.0", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "conventional-commits-filter": "^2.0.7", + "dateformat": "^3.0.0", + "handlebars": "^4.7.6", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "semver": "^6.0.0", + "split": "^1.0.0", + "through2": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "semver": { + "version": "6.3.0", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "through2": { + "version": "4.0.2", + "dev": true, + "requires": { + "readable-stream": "3" + } + } + } + }, + "conventional-commits-filter": { + "version": "2.0.7", + "dev": true, + "requires": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.0" + } + }, + "conventional-commits-parser": { + "version": "3.2.0", + "dev": true, + "requires": { + "is-text-path": "^1.0.1", + "JSONStream": "^1.0.4", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^2.0.0", + "through2": "^4.0.0", + "trim-off-newlines": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "dev": true + }, + "split2": { + "version": "2.2.0", + "dev": true, + "requires": { + "through2": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "through2": { + "version": "2.0.5", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + } + } + }, + "string_decoder": { + "version": "1.3.0", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "dev": true + } + } + }, + "through2": { + "version": "4.0.2", + "dev": true, + "requires": { + "readable-stream": "3" + } + } + } + }, + "core-util-is": { + "version": "1.0.2", + "dev": true + }, + "cosmiconfig": { + "version": "7.0.0", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cross-spawn": { + "version": "7.0.3", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "crypto-random-string": { + "version": "2.0.0", + "dev": true + }, + "dargs": { + "version": "7.0.0", + "dev": true + }, + "dateformat": { + "version": "3.0.3", + "dev": true + }, + "debug": { + "version": "4.3.1", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "dev": true + } + } + }, + "decamelize": { + "version": "1.2.0", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "dev": true + }, + "decompress-response": { + "version": "5.0.0", + "dev": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "dev": true + }, + "defer-to-connect": { + "version": "2.0.1", + "dev": true + }, + "del": { + "version": "6.0.0", + "dev": true, + "requires": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "dependencies": { + "p-map": { + "version": "4.0.0", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "rimraf": { + "version": "3.0.2", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "dev": true + }, + "deprecation": { + "version": "2.3.1", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dot-prop": { + "version": "5.3.0", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "duplexer2": { + "version": "0.1.4", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "duplexer3": { + "version": "0.1.4", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "env-ci": { + "version": "5.0.2", + "dev": true, + "requires": { + "execa": "^4.0.0", + "java-properties": "^1.0.0" + }, + "dependencies": { + "execa": { + "version": "4.1.0", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + } + } + }, + "error-ex": { + "version": "1.3.2", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escalade": { + "version": "3.1.1", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "dev": true + }, + "execa": { + "version": "5.1.1", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "6.0.1", + "dev": true + }, + "human-signals": { + "version": "2.1.0", + "dev": true + } + } + }, + "fast-glob": { + "version": "3.2.5", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, + "fastq": { + "version": "1.10.0", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "figures": { + "version": "3.2.0", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "fill-range": { + "version": "7.0.1", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "filter-obj": { + "version": "1.1.0", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "find-versions": { + "version": "4.0.0", + "dev": true, + "requires": { + "semver-regex": "^3.1.2" + } + }, + "form-data": { + "version": "3.0.1", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "from2": { + "version": "2.3.0", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "9.1.0", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stream": { + "version": "5.2.0", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "git-log-parser": { + "version": "1.2.0", + "dev": true, + "requires": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "~0.6.6" + } + }, + "git-raw-commits": { + "version": "2.0.9", + "dev": true, + "requires": { + "dargs": "^7.0.0", + "lodash.template": "^4.0.2", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "split2": { + "version": "3.2.2", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "through2": { + "version": "4.0.2", + "dev": true, + "requires": { + "readable-stream": "3" + } + } + } + }, + "glob": { + "version": "7.1.7", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-promise": { + "version": "4.2.0", + "dev": true, + "requires": { + "@types/glob": "^7.1.3" + } + }, + "global-dirs": { + "version": "0.1.1", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "globby": { + "version": "11.0.2", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "got": { + "version": "10.7.0", + "dev": true, + "requires": { + "@sindresorhus/is": "^2.0.0", + "@szmarczak/http-timer": "^4.0.0", + "@types/cacheable-request": "^6.0.1", + "cacheable-lookup": "^2.0.0", + "cacheable-request": "^7.0.1", + "decompress-response": "^5.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^5.0.0", + "lowercase-keys": "^2.0.0", + "mimic-response": "^2.1.0", + "p-cancelable": "^2.0.0", + "p-event": "^4.0.0", + "responselike": "^2.0.0", + "to-readable-stream": "^2.0.0", + "type-fest": "^0.10.0" + }, + "dependencies": { + "type-fest": { + "version": "0.10.0", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.2.4", + "dev": true + }, + "handlebars": { + "version": "4.7.6", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "hard-rejection": { + "version": "2.1.0", + "dev": true + }, + "has": { + "version": "1.0.3", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "dev": true + }, + "has-symbols": { + "version": "1.0.2", + "dev": true + }, + "hook-std": { + "version": "2.0.0", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "dev": true + }, + "http-proxy-agent": { + "version": "4.0.1", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "agent-base": { + "version": "6.0.2", + "dev": true, + "requires": { + "debug": "4" + } + } + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "agent-base": { + "version": "6.0.2", + "dev": true, + "requires": { + "debug": "4" + } + } + } + }, + "human-signals": { + "version": "1.1.1", + "dev": true + }, + "husky": { + "version": "7.0.2", + "dev": true + }, + "ignore": { + "version": "5.1.8", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "dev": true + } + } + }, + "import-from": { + "version": "3.0.0", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "indent-string": { + "version": "4.0.0", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "dev": true + }, + "ini": { + "version": "1.3.8", + "dev": true + }, + "into-stream": { + "version": "5.1.1", + "dev": true, + "requires": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "dev": true + }, + "is-core-module": { + "version": "2.2.0", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "dev": true + }, + "is-path-inside": { + "version": "3.0.2", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "dev": true + }, + "is-plain-object": { + "version": "5.0.0", + "dev": true + }, + "is-ssh": { + "version": "1.3.3", + "dev": true, + "requires": { + "protocols": "^1.1.0" + } + }, + "is-stream": { + "version": "2.0.0", + "dev": true + }, + "is-text-path": { + "version": "1.0.1", + "dev": true, + "requires": { + "text-extensions": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "dev": true + }, + "issue-parser": { + "version": "6.0.0", + "dev": true, + "requires": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + } + }, + "java-properties": { + "version": "1.0.2", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonparse": { + "version": "1.3.1", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "keyv": { + "version": "4.0.3", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "dev": true + }, + "lines-and-columns": { + "version": "1.1.6", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pify": { + "version": "3.0.0", + "dev": true + } + } + }, + "locate-path": { + "version": "2.0.0", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "dev": true + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "dev": true + }, + "lodash.capitalize": { + "version": "4.2.1", + "dev": true + }, + "lodash.escaperegexp": { + "version": "4.1.2", + "dev": true + }, + "lodash.ismatch": { + "version": "4.4.0", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "dev": true + }, + "lodash.isstring": { + "version": "4.0.1", + "dev": true + }, + "lodash.template": { + "version": "4.5.0", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" + } + }, + "lodash.templatesettings": { + "version": "4.2.0", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + }, + "lodash.uniqby": { + "version": "4.7.0", + "dev": true + }, + "lowercase-keys": { + "version": "2.0.0", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "map-obj": { + "version": "1.0.1", + "dev": true + }, + "marked": { + "version": "2.1.3", + "dev": true + }, + "marked-terminal": { + "version": "4.1.1", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.1", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "cli-table": "^0.3.1", + "node-emoji": "^1.10.0", + "supports-hyperlinks": "^2.1.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "meow": { + "version": "8.1.2", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "dependencies": { + "hosted-git-info": { + "version": "3.0.7", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "normalize-package-data": { + "version": "3.0.0", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "7.3.4", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "type-fest": { + "version": "0.18.1", + "dev": true + } + } + }, + "merge-stream": { + "version": "2.0.0", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "mime": { + "version": "2.5.0", + "dev": true + }, + "mime-db": { + "version": "1.49.0", + "dev": true + }, + "mime-types": { + "version": "2.1.32", + "dev": true, + "requires": { + "mime-db": "1.49.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "dev": true + }, + "mimic-response": { + "version": "2.1.0", + "dev": true + }, + "min-indent": { + "version": "1.0.1", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "dev": true + }, + "minimist-options": { + "version": "4.1.0", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + } + }, + "modify-values": { + "version": "1.0.1", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "dev": true + }, + "nerf-dart": { + "version": "1.0.0", + "dev": true + }, + "node-emoji": { + "version": "1.11.0", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "node-fetch": { + "version": "2.6.1", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-url": { + "version": "6.1.0", + "dev": true + }, + "npm": { + "version": "7.22.0", + "dev": true, + "requires": { + "@npmcli/arborist": "^2.8.3", + "@npmcli/ci-detect": "^1.2.0", + "@npmcli/config": "^2.3.0", + "@npmcli/map-workspaces": "^1.0.4", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^1.8.6", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "archy": "~1.0.0", + "cacache": "^15.3.0", + "chalk": "^4.1.2", + "chownr": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.6.0", + "columnify": "~1.5.4", + "fastest-levenshtein": "^1.0.12", + "glob": "^7.1.7", + "graceful-fs": "^4.2.8", + "hosted-git-info": "^4.0.2", + "ini": "^2.0.0", + "init-package-json": "^2.0.4", + "is-cidr": "^4.0.2", + "json-parse-even-better-errors": "^2.3.1", + "libnpmaccess": "^4.0.2", + "libnpmdiff": "^2.0.4", + "libnpmexec": "^2.0.1", + "libnpmfund": "^1.1.0", + "libnpmhook": "^6.0.2", + "libnpmorg": "^2.0.2", + "libnpmpack": "^2.0.1", + "libnpmpublish": "^4.0.1", + "libnpmsearch": "^3.1.1", + "libnpmteam": "^2.0.3", + "libnpmversion": "^1.2.1", + "make-fetch-happen": "^9.1.0", + "minipass": "^3.1.3", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "ms": "^2.1.2", + "node-gyp": "^7.1.2", + "nopt": "^5.0.0", + "npm-audit-report": "^2.1.5", + "npm-package-arg": "^8.1.5", + "npm-pick-manifest": "^6.1.1", + "npm-profile": "^5.0.3", + "npm-registry-fetch": "^11.0.0", + "npm-user-validate": "^1.0.1", + "npmlog": "^5.0.1", + "opener": "^1.5.2", + "pacote": "^11.3.5", + "parse-conflict-json": "^1.1.1", + "qrcode-terminal": "^0.12.0", + "read": "~1.0.7", + "read-package-json": "^4.1.1", + "read-package-json-fast": "^2.0.3", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "tar": "^6.1.11", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^1.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^2.0.2", + "write-file-atomic": "^3.0.3" + }, + "dependencies": { + "@gar/promisify": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "@npmcli/arborist": { + "version": "2.8.3", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/map-workspaces": "^1.0.2", + "@npmcli/metavuln-calculator": "^1.1.0", + "@npmcli/move-file": "^1.1.0", + "@npmcli/name-from-folder": "^1.0.1", + "@npmcli/node-gyp": "^1.0.1", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^1.8.2", + "bin-links": "^2.2.1", + "cacache": "^15.0.3", + "common-ancestor-path": "^1.0.1", + "json-parse-even-better-errors": "^2.3.1", + "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^8.1.5", + "npm-pick-manifest": "^6.1.0", + "npm-registry-fetch": "^11.0.0", + "pacote": "^11.3.5", + "parse-conflict-json": "^1.1.1", + "proc-log": "^1.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^2.0.2", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "treeverse": "^1.0.4", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/ci-detect": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "@npmcli/config": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "ini": "^2.0.0", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "semver": "^7.3.4", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/disparity-colors": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.3.0" + } + }, + "@npmcli/fs": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "bundled": true, + "dev": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/map-workspaces": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/name-from-folder": "^1.0.1", + "glob": "^7.1.6", + "minimatch": "^3.0.4", + "read-package-json-fast": "^2.0.1" + } + }, + "@npmcli/metavuln-calculator": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "cacache": "^15.0.5", + "pacote": "^11.1.11", + "semver": "^7.3.2" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/name-from-folder": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "@npmcli/node-gyp": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "@npmcli/package-json": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.1" + } + }, + "@npmcli/promise-spawn": { + "version": "1.3.2", + "bundled": true, + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "1.8.6", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^7.1.0", + "read-package-json-fast": "^2.0.1" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "bundled": true, + "dev": true, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.1.4", + "bundled": true, + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "bundled": true, + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.6", + "bundled": true, + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "asap": { + "version": "2.0.6", + "bundled": true, + "dev": true + }, + "asn1": { + "version": "0.2.4", + "bundled": true, + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "bundled": true, + "dev": true + }, + "aws4": { + "version": "1.11.0", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bin-links": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "cmd-shim": "^4.0.1", + "mkdirp": "^1.0.3", + "npm-normalize-package-bin": "^1.0.0", + "read-cmd-shim": "^2.0.0", + "rimraf": "^3.0.0", + "write-file-atomic": "^3.0.3" + } + }, + "binary-extensions": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtins": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "cacache": { + "version": "15.3.0", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + } + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "chalk": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chownr": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "cidr-regex": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "requires": { + "ip-regex": "^4.1.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "cli-columns": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" + } + }, + "cli-table3": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "4.2.2", + "bundled": true, + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "cmd-shim": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "mkdirp-infer-owner": "^2.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, + "color-support": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "colors": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "dev": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.8", + "bundled": true, + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "common-ancestor-path": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "4.3.2", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "defaults": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "depd": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "diff": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "bundled": true, + "dev": true + }, + "encoding": { + "version": "0.1.13", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "env-paths": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "err-code": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "extend": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "bundled": true, + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.12", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true + }, + "fs-minipass": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "gauge": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1 || ^2.0.0", + "strip-ansi": "^3.0.1 || ^4.0.0", + "wide-align": "^1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.7", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.8", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "bundled": true, + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "hosted-git-info": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "http-proxy-agent": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "http-signature": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ignore-walk": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "ini": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "init-package-json": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^8.1.2", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0" + } + }, + "ip": { + "version": "1.1.5", + "bundled": true, + "dev": true + }, + "ip-regex": { + "version": "4.3.0", + "bundled": true, + "dev": true + }, + "is-cidr": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "cidr-regex": "^3.1.1" + } + }, + "is-core-module": { + "version": "2.6.0", + "bundled": true, + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-lambda": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "bundled": true, + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "bundled": true, + "dev": true + }, + "json-stringify-nice": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true, + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "just-diff": { + "version": "3.1.1", + "bundled": true, + "dev": true + }, + "just-diff-apply": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "libnpmaccess": { + "version": "4.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "minipass": "^3.1.1", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0" + } + }, + "libnpmdiff": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/disparity-colors": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", + "binary-extensions": "^2.2.0", + "diff": "^5.0.0", + "minimatch": "^3.0.4", + "npm-package-arg": "^8.1.4", + "pacote": "^11.3.4", + "tar": "^6.1.0" + } + }, + "libnpmexec": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/arborist": "^2.3.0", + "@npmcli/ci-detect": "^1.3.0", + "@npmcli/run-script": "^1.8.4", + "chalk": "^4.1.0", + "mkdirp-infer-owner": "^2.0.0", + "npm-package-arg": "^8.1.2", + "pacote": "^11.3.1", + "proc-log": "^1.0.0", + "read": "^1.0.7", + "read-package-json-fast": "^2.0.2", + "walk-up-path": "^1.0.0" + } + }, + "libnpmfund": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/arborist": "^2.5.0" + } + }, + "libnpmhook": { + "version": "6.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" + } + }, + "libnpmorg": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" + } + }, + "libnpmpack": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/run-script": "^1.8.3", + "npm-package-arg": "^8.1.0", + "pacote": "^11.2.6" + } + }, + "libnpmpublish": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "normalize-package-data": "^3.0.2", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0", + "semver": "^7.1.3", + "ssri": "^8.0.1" + } + }, + "libnpmsearch": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "npm-registry-fetch": "^11.0.0" + } + }, + "libnpmteam": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" + } + }, + "libnpmversion": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/git": "^2.0.7", + "@npmcli/run-script": "^1.8.4", + "json-parse-even-better-errors": "^2.3.1", + "semver": "^7.3.5", + "stringify-package": "^1.0.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-fetch-happen": { + "version": "9.1.0", + "bundled": true, + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, + "mime-db": { + "version": "1.49.0", + "bundled": true, + "dev": true + }, + "mime-types": { + "version": "2.1.32", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.49.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minipass": { + "version": "3.1.3", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "requires": { + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "mkdirp-infer-owner": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "chownr": "^2.0.0", + "infer-owner": "^1.0.4", + "mkdirp": "^1.0.3" + } + }, + "ms": { + "version": "2.1.3", + "bundled": true, + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "bundled": true, + "dev": true + }, + "node-gyp": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "nopt": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-audit-report": { + "version": "2.1.5", + "bundled": true, + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "npm-bundled": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-install-checks": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "npm-package-arg": { + "version": "8.1.5", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "2.2.2", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "6.1.1", + "bundled": true, + "dev": true, + "requires": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + } + }, + "npm-profile": { + "version": "5.0.4", + "bundled": true, + "dev": true, + "requires": { + "npm-registry-fetch": "^11.0.0" + } + }, + "npm-registry-fetch": { + "version": "11.0.0", + "bundled": true, + "dev": true, + "requires": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + } + }, + "npm-user-validate": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "npmlog": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + }, + "dependencies": { + "are-we-there-yet": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + } + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.5.2", + "bundled": true, + "dev": true + }, + "p-map": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "pacote": { + "version": "11.3.5", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/git": "^2.1.0", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^11.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" + } + }, + "parse-conflict-json": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "just-diff": "^3.0.1", + "just-diff-apply": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "proc-log": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "promise-all-reject-late": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-call-limit": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "read": "1" + } + }, + "psl": { + "version": "1.8.0", + "bundled": true, + "dev": true + }, + "punycode": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "qs": { + "version": "6.5.2", + "bundled": true, + "dev": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "read-package-json": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "read-package-json-fast": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "request": { + "version": "2.88.2", + "bundled": true, + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "bundled": true, + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "tough-cookie": { + "version": "2.5.0", + "bundled": true, + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, + "retry": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "semver": { + "version": "7.3.5", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "bundled": true, + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "bundled": true, + "dev": true + }, + "socks": { + "version": "2.6.1", + "bundled": true, + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + } + }, + "spdx-correct": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.10", + "bundled": true, + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "bundled": true, + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "8.0.1", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "stringify-package": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tar": { + "version": "6.1.11", + "bundled": true, + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "treeverse": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "bundled": true, + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "unique-filename": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "uri-js": { + "version": "4.4.1", + "bundled": true, + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "uuid": { + "version": "3.4.0", + "bundled": true, + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "walk-up-path": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "yallist": { + "version": "4.0.0", + "bundled": true, + "dev": true + } + } + }, + "npm-run-path": { + "version": "4.0.1", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "dev": true + }, + "once": { + "version": "1.4.0", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-cancelable": { + "version": "2.1.1", + "dev": true + }, + "p-each-series": { + "version": "2.2.0", + "dev": true + }, + "p-event": { + "version": "4.2.0", + "dev": true, + "requires": { + "p-timeout": "^3.1.0" + } + }, + "p-filter": { + "version": "2.1.0", + "dev": true, + "requires": { + "p-map": "^2.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "dev": true + }, + "p-is-promise": { + "version": "3.0.0", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + }, + "dependencies": { + "p-limit": { + "version": "1.3.0", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "dev": true + } + } + }, + "p-map": { + "version": "2.1.0", + "dev": true + }, + "p-reduce": { + "version": "2.1.0", + "dev": true + }, + "p-retry": { + "version": "4.2.0", + "dev": true, + "requires": { + "@types/retry": "^0.12.0", + "retry": "^0.12.0" + } + }, + "p-timeout": { + "version": "3.2.0", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse-path": { + "version": "4.0.3", + "dev": true, + "requires": { + "is-ssh": "^1.3.0", + "protocols": "^1.4.0", + "qs": "^6.9.4", + "query-string": "^6.13.8" + } + }, + "path-exists": { + "version": "3.0.0", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "dev": true + }, + "pkg-conf": { + "version": "2.1.0", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "dev": true + }, + "protocols": { + "version": "1.4.8", + "dev": true + }, + "pump": { + "version": "3.0.0", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "q": { + "version": "1.5.1", + "dev": true + }, + "qs": { + "version": "6.10.1", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "query-string": { + "version": "6.14.1", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + } + }, + "quick-lru": { + "version": "4.0.1", + "dev": true + }, + "rc": { + "version": "1.2.8", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read-pkg": { + "version": "5.2.0", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + } + }, + "read-pkg-up": { + "version": "7.0.1", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "dev": true + } + } + }, + "readable-stream": { + "version": "2.3.7", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "dev": true + } + } + }, + "redent": { + "version": "3.0.0", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "redeyed": { + "version": "2.1.1", + "dev": true, + "requires": { + "esprima": "~4.0.0" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "require-directory": { + "version": "2.1.1", + "dev": true + }, + "resolve": { + "version": "1.19.0", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "5.0.0", + "dev": true + }, + "resolve-global": { + "version": "1.0.0", + "dev": true, + "requires": { + "global-dirs": "^0.1.1" + } + }, + "responselike": { + "version": "2.0.0", + "dev": true, + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "retry": { + "version": "0.12.0", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "dev": true + }, + "run-parallel": { + "version": "1.1.10", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "dev": true + }, + "sax": { + "version": "1.2.4", + "dev": true + }, + "semantic-release": { + "version": "17.4.7", + "dev": true, + "requires": { + "@semantic-release/commit-analyzer": "^8.0.0", + "@semantic-release/error": "^2.2.0", + "@semantic-release/github": "^7.0.0", + "@semantic-release/npm": "^7.0.0", + "@semantic-release/release-notes-generator": "^9.0.0", + "aggregate-error": "^3.0.0", + "cosmiconfig": "^7.0.0", + "debug": "^4.0.0", + "env-ci": "^5.0.0", + "execa": "^5.0.0", + "figures": "^3.0.0", + "find-versions": "^4.0.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^2.0.0", + "hosted-git-info": "^4.0.0", + "lodash": "^4.17.21", + "marked": "^2.0.0", + "marked-terminal": "^4.1.1", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "p-reduce": "^2.0.0", + "read-pkg-up": "^7.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "semver-diff": "^3.1.1", + "signale": "^1.2.1", + "yargs": "^16.2.0" + }, + "dependencies": { + "get-stream": { + "version": "6.0.1", + "dev": true + }, + "hosted-git-info": { + "version": "4.0.2", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "semver": { + "version": "7.3.4", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "semantic-release-dotnet": { + "version": "1.0.0", + "dev": true, + "requires": { + "glob": "^7.1.7", + "glob-promise": "^4.2.0", + "xml-js": "^1.6.11" + } + }, + "semantic-release-nuget": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semantic-release-nuget/-/semantic-release-nuget-1.1.0.tgz", + "integrity": "sha512-Eaqb39E+dPTgYgHif0/P6cUj7IxZxI9e2BgmfE+NkRlPArpRPa94UZTi8UFMbEKiKg0IaNnAO79yexUPcZnuHA==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "dev": true + }, + "semver-diff": { + "version": "3.1.1", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "dev": true + } + } + }, + "semver-regex": { + "version": "3.1.2", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.3", + "dev": true + }, + "signale": { + "version": "1.4.0", + "dev": true, + "requires": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "dependencies": { + "figures": { + "version": "2.0.0", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + } + } + }, + "slash": { + "version": "3.0.0", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "dev": true + }, + "spawn-error-forwarder": { + "version": "1.0.0", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.7", + "dev": true + }, + "split": { + "version": "1.0.1", + "dev": true, + "requires": { + "through": "2" + } + }, + "split-on-first": { + "version": "1.1.0", + "dev": true + }, + "split2": { + "version": "1.0.0", + "dev": true, + "requires": { + "through2": "~2.0.0" + } + }, + "stream-combiner2": { + "version": "1.1.1", + "dev": true, + "requires": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "strict-uri-encode": { + "version": "2.0.0", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "dev": true + } + } + }, + "string-width": { + "version": "4.2.2", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "temp-dir": { + "version": "2.0.0", + "dev": true + }, + "tempy": { + "version": "1.0.0", + "dev": true, + "requires": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "dependencies": { + "type-fest": { + "version": "0.16.0", + "dev": true + } + } + }, + "text-extensions": { + "version": "1.9.0", + "dev": true + }, + "through": { + "version": "2.3.8", + "dev": true + }, + "through2": { + "version": "2.0.5", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "to-readable-stream": { + "version": "2.1.0", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "traverse": { + "version": "0.6.6", + "dev": true + }, + "trim-newlines": { + "version": "3.0.0", + "dev": true + }, + "trim-off-newlines": { + "version": "1.0.1", + "dev": true + }, + "type-fest": { + "version": "0.6.0", + "dev": true + }, + "uglify-js": { + "version": "3.12.5", + "dev": true, + "optional": true + }, + "unique-string": { + "version": "2.0.0", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universal-user-agent": { + "version": "6.0.0", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "dev": true + }, + "url-join": { + "version": "4.0.1", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "dev": true + }, + "xml-js": { + "version": "1.6.11", + "dev": true, + "requires": { + "sax": "^1.2.4" + } + }, + "xtend": { + "version": "4.0.2", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "dev": true + }, + "yaml": { + "version": "1.10.0", + "dev": true + }, + "yargs": { + "version": "17.1.1", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d8e2770 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "nitride-cil", + "version": "1.0.0", + "private": true, + "scripts": { + "prepare": "husky install" + }, + "devDependencies": { + "@commitlint/cli": "^13.1.0", + "@commitlint/config-conventional": "^13.1.0", + "@semantic-release/changelog": "^5.0.1", + "@semantic-release/git": "^9.0.0", + "@semantic-release/gitlab": "^6.2.2", + "@semantic-release/npm": "^7.1.3", + "commitlint-gitlab-ci": "^0.0.4", + "husky": "^7.0.2", + "semantic-release": "^17.4.7", + "semantic-release-dotnet": "^1.0.0", + "semantic-release-nuget": "^1.1.0" + } +} diff --git a/release.config.js b/release.config.js new file mode 100644 index 0000000..e0233f1 --- /dev/null +++ b/release.config.js @@ -0,0 +1,20 @@ +module.exports = { + branches: ["main"], + message: "chore(release): v${nextRelease.version}\n\n${nextRelease.notes}", + plugins: [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/npm", + "semantic-release-dotnet", + [ + "semantic-release-nuget", + { + packArguments: ["--include-symbols", "--include-source"], + pushFiles: ["src/*/bin/Debug/*.nupkg"], + }, + ], + "@semantic-release/changelog", + "@semantic-release/git", + "@semantic-release/gitlab", + ], +}; diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..a532a7e --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,14 @@ + + + + true + Dylan Moonfire + Moonfire Games + https://gitlab.com/mfgames-cil/nitride-cil + Git + nitride + https://gitlab.com/mfgames-cil/nitride-cil + MIT + + + diff --git a/src/Nitride.Calendar/CreateCalender.cs b/src/Nitride.Calendar/CreateCalender.cs new file mode 100644 index 0000000..1049919 --- /dev/null +++ b/src/Nitride.Calendar/CreateCalender.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Gallium; +using Ical.Net.CalendarComponents; +using Ical.Net.DataTypes; +using Ical.Net.Serialization; +using Nitride.Contents; +using Nitride.Temporal; +using NodaTime; +using Zio; + +namespace Nitride.Calendar +{ + /// + /// Creates an iCalendar file from all the entities passed into the method + /// that have a NodaTime.Instant component. This will write both past and + /// future events. + /// + [WithProperties] + public partial class CreateCalender : NitrideOperationBase + { + private readonly NitrideClock clock; + + public CreateCalender(NitrideClock clock) + { + this.clock = clock; + } + + /// + /// Gets or sets a callback to get the summary of the event representing + /// the entity. + /// + public Func? GetEventSummary { get; set; } + + /// + /// Gets or sets a callback to get the optional URL of an event for + /// the entity. + /// + public Func? GetEventUrl { get; set; } + + /// + /// Gets or sets the file system path for the resulting calendar. + /// + public UPath? Path { get; set; } + + /// + public override IEnumerable Run(IEnumerable input) + { + this.CheckNotNull(x => x.Path); + this.CheckNotNull(x => x.GetEventSummary); + + IEnumerable output = input + .ForEntities(this.CreateCalendarEntity); + + return output; + } + + private IEnumerable CreateCalendarEntity( + IEnumerable entities) + { + // Create the calendar in the same time zone as the rest of the system. + var calendar = new Ical.Net.Calendar(); + + calendar.TimeZones.Add(new VTimeZone(this.clock.DateTimeZone.Id)); + + // Go through the events and add all of them. + List input = entities.ToList(); + IEnumerable events = + input.Select(this.CreateCalendarEvent); + + calendar.Events.AddRange(events); + + // Create the iCalendar file. + var serializer = new CalendarSerializer(); + string serializedCalendar = serializer.SerializeToString(calendar); + + // Create the calendar entity and populate everything. + Entity calendarEntity = new Entity() + .Set(IsCalendar.Instance) + .Set(this.Path!.Value) + .SetTextContent(serializedCalendar); + + // Return the results along with the new calendar. + return input.Union(new[] { calendarEntity }); + } + + private CalendarEvent CreateCalendarEvent(Entity entity) + { + var instant = entity.Get(); + var when = this.clock.ToDateTime(instant); + string summary = this.GetEventSummary!(entity); + Uri? url = this.GetEventUrl?.Invoke(entity); + var calendarEvent = new CalendarEvent + { + Summary = summary, + Start = new CalDateTime(when), + Url = url, + }; + + return calendarEvent; + } + } +} diff --git a/src/Nitride.Calendar/IsCalendar.cs b/src/Nitride.Calendar/IsCalendar.cs new file mode 100644 index 0000000..c8e761d --- /dev/null +++ b/src/Nitride.Calendar/IsCalendar.cs @@ -0,0 +1,10 @@ +namespace Nitride.Calendar +{ + /// + /// A marker component for identifying an entity that represents a calendar. + /// + public class IsCalendar + { + public static IsCalendar Instance { get; } = new(); + } +} diff --git a/src/Nitride.Calendar/Nitride.Calendar.csproj b/src/Nitride.Calendar/Nitride.Calendar.csproj new file mode 100644 index 0000000..653a79a --- /dev/null +++ b/src/Nitride.Calendar/Nitride.Calendar.csproj @@ -0,0 +1,37 @@ + + + + net5.0 + enable + + + + An extension to Nitride static site generator to generate iCalendar files. + + + + + + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.Calendar/NitrideCalendarBuilderExtensions.cs b/src/Nitride.Calendar/NitrideCalendarBuilderExtensions.cs new file mode 100644 index 0000000..57f4e54 --- /dev/null +++ b/src/Nitride.Calendar/NitrideCalendarBuilderExtensions.cs @@ -0,0 +1,16 @@ +using Autofac; +using Nitride.Temporal; + +namespace Nitride.Calendar +{ + public static class NitrideCalendarBuilderExtensions + { + public static NitrideBuilder UseCalendar(this NitrideBuilder builder) + { + return builder + .UseTemporal() + .ConfigureContainer( + x => x.RegisterModule()); + } + } +} diff --git a/src/Nitride.Calendar/NitrideCalendarModule.cs b/src/Nitride.Calendar/NitrideCalendarModule.cs new file mode 100644 index 0000000..eb2ac45 --- /dev/null +++ b/src/Nitride.Calendar/NitrideCalendarModule.cs @@ -0,0 +1,6 @@ +namespace Nitride.Calendar +{ + public class NitrideCalendarModule : NitrideModuleBase + { + } +} diff --git a/src/Nitride.Feeds/CreateAtomFeeds.cs b/src/Nitride.Feeds/CreateAtomFeeds.cs new file mode 100644 index 0000000..865e924 --- /dev/null +++ b/src/Nitride.Feeds/CreateAtomFeeds.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Gallium; +using Nitride.Contents; +using Nitride.Feeds.Structure; +using NodaTime; +using Serilog; +using Zio; + +namespace Nitride.Feeds +{ + /// + /// Creates various feeds from the given input. + /// + [WithProperties] + public partial class CreateAtomFeeds : NitrideOperationBase + { + private readonly ILogger logger; + + public CreateAtomFeeds(ILogger logger) + { + this.logger = logger; + this.GetAlternateMimeType = _ => "text/html"; + } + + /// + /// Gets or sets the base URL for all the links. + /// + public string? BaseUrl { get; set; } + + /// + /// Gets or sets the alternate MIME type. + /// + public Func GetAlternateMimeType { get; set; } + + /// + /// Gets or sets the alternate URL associated with the feed. + /// + public Func? GetAlternateUrl { get; set; } + + /// + /// Gets or sets the callback to get the author for the feed. + /// + public Func? GetAuthor { get; set; } + + /// + /// Gets or sets the callback to get the entries associated with the + /// feed. + /// + public Func>? GetEntries { get; set; } + + /// + /// Gets or sets the identifier (typically a URL) of the feed. + /// + public Func? GetId { get; set; } + + /// + /// Gets or sets the callback to get the path of the generated feed. + /// + public Func? GetPath { get; set; } + + /// + /// Gets or sets the rights (license) of the feed. + /// + public Func? GetRights { get; set; } + + /// + /// A callback that gets the title of the feed from the given entity. + /// + public Func? GetTitle { get; set; } + + /// + /// Gets or sets the updated timestamp for the feed. + /// + public Func? GetUpdated { get; set; } + + /// + /// Gets or sets the URL associated with the feed. + /// + public Func? GetUrl { get; set; } + + /// + public override IEnumerable Run(IEnumerable input) + { + this.CheckNotNull(x => this.GetTitle); + this.CheckNotNull(x => this.GetPath); + this.CheckNotNull(x => this.GetEntries); + + return input.SelectMany(this.CreateEntityFeed); + } + + private IEnumerable CreateEntityFeed(Entity entity) + { + // Create the top-level feed. All the nullable callbacks were + // verified in the function that calls this. + var feed = new AtomFeed() + .WithTitle(this.GetTitle?.Invoke(entity)) + .WithId(this.GetId?.Invoke(entity)) + .WithRights(this.GetRights?.Invoke(entity)) + .WithUpdated(this.GetUpdated?.Invoke(entity)) + .WithUrl(this.GetUrl?.Invoke(entity)) + .WithAlternateUrl(this.GetAlternateUrl?.Invoke(entity)) + .WithAlternateMimeType(this.GetAlternateMimeType.Invoke(entity)) + .WithAuthor(this.GetAuthor?.Invoke(entity)) + .ToXElement(); + + // Go through all the items inside the feed and add them. + foreach (var entry in this.GetEntries!(entity)) + { + feed.Add(entry.ToXElement()); + } + + // Create the feed entity and return both objects. + Entity feedEntity = new Entity() + .Set(IsFeed.Instance) + .Set(this.GetPath!(entity)) + .SetTextContent(feed + "\n"); + + return new[] { entity, feedEntity }; + } + } +} diff --git a/src/Nitride.Feeds/HasFeed.cs b/src/Nitride.Feeds/HasFeed.cs new file mode 100644 index 0000000..eaeee87 --- /dev/null +++ b/src/Nitride.Feeds/HasFeed.cs @@ -0,0 +1,15 @@ +namespace Nitride.Feeds +{ + /// + /// A marker component that indicates this entity has a feed associated with + /// it. + /// + public class HasFeed + { + public HasFeed() + { + } + + public static HasFeed Instance { get; } = new(); + } +} diff --git a/src/Nitride.Feeds/IsFeed.cs b/src/Nitride.Feeds/IsFeed.cs new file mode 100644 index 0000000..f38927a --- /dev/null +++ b/src/Nitride.Feeds/IsFeed.cs @@ -0,0 +1,14 @@ +namespace Nitride.Feeds +{ + /// + /// A marker component that indicates this page is a feed. + /// + public class IsFeed + { + public IsFeed() + { + } + + public static IsFeed Instance { get; } = new(); + } +} diff --git a/src/Nitride.Feeds/Nitride.Feeds.csproj b/src/Nitride.Feeds/Nitride.Feeds.csproj new file mode 100644 index 0000000..cbe27f6 --- /dev/null +++ b/src/Nitride.Feeds/Nitride.Feeds.csproj @@ -0,0 +1,36 @@ + + + + net5.0 + enable + + + + An extension to Nitride static site generator to generate Atom feeds. + + + + + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.Feeds/NitrideFeedsBuilderExtensions.cs b/src/Nitride.Feeds/NitrideFeedsBuilderExtensions.cs new file mode 100644 index 0000000..b9e0ca6 --- /dev/null +++ b/src/Nitride.Feeds/NitrideFeedsBuilderExtensions.cs @@ -0,0 +1,16 @@ +using Autofac; +using Nitride.Temporal; + +namespace Nitride.Feeds +{ + public static class NitrideFeedsBuilderExtensions + { + public static NitrideBuilder UseFeeds(this NitrideBuilder builder) + { + return builder + .UseTemporal() + .ConfigureContainer( + x => x.RegisterModule()); + } + } +} diff --git a/src/Nitride.Feeds/NitrideFeedsModule.cs b/src/Nitride.Feeds/NitrideFeedsModule.cs new file mode 100644 index 0000000..fc5b1ad --- /dev/null +++ b/src/Nitride.Feeds/NitrideFeedsModule.cs @@ -0,0 +1,6 @@ +namespace Nitride.Feeds +{ + public class NitrideFeedsModule : NitrideModuleBase + { + } +} diff --git a/src/Nitride.Feeds/Structure/AtomAuthor.cs b/src/Nitride.Feeds/Structure/AtomAuthor.cs new file mode 100644 index 0000000..0111417 --- /dev/null +++ b/src/Nitride.Feeds/Structure/AtomAuthor.cs @@ -0,0 +1,41 @@ +using System.Xml.Linq; + +namespace Nitride.Feeds.Structure +{ + /// + /// The type-safe structure for an author element. + /// + [WithProperties] + public partial class AtomAuthor + { + /// + /// Gets or sets the name of the author. + /// + public string? Name { get; set; } + + /// + /// Creates an XML element out of the feed along with all items inside + /// the feed. + /// + /// + public XElement? ToXElement() + { + if (this.Name == null) + { + return null; + } + + var author = new XElement(XmlConstants.AtomNamespace + "author"); + + if (!string.IsNullOrEmpty(this.Name)) + { + author.Add( + new XElement( + XmlConstants.AtomNamespace + "name", + new XText(this.Name))); + } + + return author; + } + } +} diff --git a/src/Nitride.Feeds/Structure/AtomCategory.cs b/src/Nitride.Feeds/Structure/AtomCategory.cs new file mode 100644 index 0000000..71928b6 --- /dev/null +++ b/src/Nitride.Feeds/Structure/AtomCategory.cs @@ -0,0 +1,57 @@ +using System; +using System.Xml.Linq; + +namespace Nitride.Feeds.Structure +{ + /// + /// The type-safe structure for a entry's category element. + /// + [WithProperties] + public partial class AtomCategory + { + /// + /// Gets or sets the label associated with the category. + /// + public string? Label { get; set; } + + /// + /// Gets or sets the scheme associated with the category. + /// + public Uri? Scheme { get; set; } + + /// + /// Gets or sets the term of the category. + /// + public string? Term { get; set; } + + /// + /// Creates an XML element out of the feed along with all items inside + /// the feed. + /// + /// + public XElement ToXElement() + { + if (this.Term == null) + { + throw new NullReferenceException( + "Category term cannot be null."); + } + + var elem = new XElement( + XmlConstants.AtomNamespace + "category", + new XAttribute("term", this.Term)); + + if (this.Scheme != null) + { + elem.Add(new XAttribute("scheme", this.Scheme.ToString())); + } + + if (!string.IsNullOrEmpty(this.Label)) + { + elem.Add(new XAttribute("label", this.Label)); + } + + return elem; + } + } +} diff --git a/src/Nitride.Feeds/Structure/AtomEntry.cs b/src/Nitride.Feeds/Structure/AtomEntry.cs new file mode 100644 index 0000000..84b4952 --- /dev/null +++ b/src/Nitride.Feeds/Structure/AtomEntry.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Xml.Linq; +using NodaTime; +using static Nitride.Feeds.Structure.XmlConstants; + +namespace Nitride.Feeds.Structure +{ + /// + /// The type-safe structure for an entry in the Atom feed. + /// + [WithProperties] + public partial class AtomEntry + { + /// + /// Gets or sets the author for the feed. + /// + public AtomAuthor? Author { get; set; } + + /// + /// Gets or sets the categories associated with this entry. + /// + public IEnumerable? Categories { get; set; } + + /// + /// Gets or sets the content of the entry. + /// + public string? Content { get; set; } + + /// + /// Gets or sets the type of content (text, html) of the content. + /// + public string ContentType { get; set; } = "html"; + + /// + /// Gets or sets the ID of the feed. + /// + public string? Id { get; set; } + + /// + /// Gets or sets the summary of the entry. + /// + public string? Summary { get; set; } + + /// + /// Gets or sets the type of content (text, html) of the summary. + /// + public string SummaryType { get; set; } = "html"; + + /// + /// Gets or sets the title of the Feed. + /// + public string? Title { get; set; } + + /// + /// Gets or sets the timestamp that the feed was updated. + /// + public Instant? Updated { get; set; } + + /// + /// Gets or sets the URL associated with this feed. + /// + public Uri? Url { get; set; } + + /// + /// Creates an XML element out of the feed along with all items inside + /// the feed. + /// + /// + public XElement? ToXElement() + { + var elem = new XElement(AtomNamespace + "entry"); + + AtomHelper.AddIfSet(elem, "title", this.Title); + + if (this.Url != null) + { + elem.Add( + new XElement( + AtomNamespace + "link", + new XAttribute("rel", "alternate"), + new XAttribute("href", this.Url.ToString()))); + } + + AtomHelper.AddIfSet( + elem, + "updated", + this.Updated?.ToString("g", null)); + AtomHelper.AddIfSet(elem, "id", this.Id); + AtomHelper.AddIfSet(elem, this.Author?.ToXElement()); + + if (this.Categories != null) + { + foreach (var category in this.Categories) + { + elem.Add(category.ToXElement()); + } + } + + if (!string.IsNullOrWhiteSpace(this.Summary)) + { + elem.Add( + new XElement( + AtomNamespace + "summary", + new XAttribute("type", this.SummaryType), + new XText(this.Summary))); + } + + if (!string.IsNullOrWhiteSpace(this.Content)) + { + elem.Add( + new XElement( + AtomNamespace + "content", + new XAttribute("type", this.ContentType), + new XText(this.Content))); + } + + return elem; + } + } +} diff --git a/src/Nitride.Feeds/Structure/AtomFeed.cs b/src/Nitride.Feeds/Structure/AtomFeed.cs new file mode 100644 index 0000000..4a12229 --- /dev/null +++ b/src/Nitride.Feeds/Structure/AtomFeed.cs @@ -0,0 +1,104 @@ +using System; +using System.Xml.Linq; +using NodaTime; +using static Nitride.Feeds.Structure.XmlConstants; + +namespace Nitride.Feeds.Structure +{ + /// + /// The type-safe structure of the top-level feed. + /// + [WithProperties] + public partial class AtomFeed + { + /// + /// Gets or sets the MIME type for the alternate URL. + /// + public string AlternateMimeType { get; set; } = "text/html"; + + /// + /// Gets or sets the alternate URL for this feed. + /// + public Uri? AlternateUrl { get; set; } + + /// + /// Gets or sets the author for the feed. + /// + public AtomAuthor? Author { get; set; } + + /// + /// Gets or sets the ID of the feed. + /// + public string? Id { get; set; } + + /// + /// Gets or sets the rights (license) of the feed. + /// + public string? Rights { get; set; } + + /// + /// Gets or sets the title of the Feed. + /// + public string? Title { get; set; } + + /// + /// Gets or sets the timestamp that the feed was updated. + /// + public Instant? Updated { get; set; } + + /// + /// Gets or sets the URL associated with this feed. + /// + public Uri? Url { get; set; } + + /// + /// Creates an XML element out of the feed along with all items inside + /// the feed. + /// + /// + public XElement ToXElement() + { + var elem = new XElement(AtomNamespace + "feed"); + + if (!string.IsNullOrWhiteSpace(this.Title)) + { + elem.Add( + new XElement( + AtomNamespace + "title", + new XAttribute("type", "text"), + new XAttribute(XNamespace.Xml + "lang", "en"), + new XText(this.Title))); + } + + if (this.Url != null) + { + elem.Add( + new XElement( + AtomNamespace + "link", + new XAttribute("type", "application/atom+xml"), + new XAttribute("href", this.Url.ToString()), + new XAttribute("rel", "self"))); + } + + if (this.AlternateUrl != null) + { + elem.Add( + new XElement( + AtomNamespace + "link", + new XAttribute("type", this.AlternateMimeType), + new XAttribute("href", this.AlternateUrl.ToString()), + new XAttribute("rel", "alternate"))); + } + + AtomHelper.AddIfSet( + elem, + "updated", + this.Updated?.ToString("g", null)); + AtomHelper.AddIfSet(elem, "id", this.Id); + AtomHelper.AddIfSet(elem, this.Author?.ToXElement()); + AtomHelper.AddIfSet(elem, "rights", this.Rights); + + return elem; + } + } +} diff --git a/src/Nitride.Feeds/Structure/AtomHelper.cs b/src/Nitride.Feeds/Structure/AtomHelper.cs new file mode 100644 index 0000000..2c6666a --- /dev/null +++ b/src/Nitride.Feeds/Structure/AtomHelper.cs @@ -0,0 +1,29 @@ +using System.Xml.Linq; + +namespace Nitride.Feeds.Structure +{ + /// + /// Helper methods for working with XML elements. + /// + public static class AtomHelper + { + public static void AddIfSet(XElement root, XElement? elem) + { + if (elem != null) + { + root.Add(elem); + } + } + + public static void AddIfSet(XElement elem, string name, string? text) + { + if (!string.IsNullOrWhiteSpace(text)) + { + elem.Add( + new XElement( + XmlConstants.AtomNamespace + name, + new XText(text))); + } + } + } +} diff --git a/src/Nitride.Feeds/Structure/XmlConstants.cs b/src/Nitride.Feeds/Structure/XmlConstants.cs new file mode 100644 index 0000000..a315c04 --- /dev/null +++ b/src/Nitride.Feeds/Structure/XmlConstants.cs @@ -0,0 +1,22 @@ +using System.Xml.Linq; + +namespace Nitride.Feeds.Structure +{ + /// + /// Common constants used while generating feeds. + /// + public static class XmlConstants + { + /// + /// The XML namespace for Atom feeds. + /// + public static readonly XNamespace AtomNamespace = + "http://www.w3.org/2005/Atom"; + + /// + /// The XML namespace for media. + /// + public static readonly XNamespace MediaNamespace = + "http://search.yahoo.com/mrss/"; + } +} diff --git a/src/Nitride.Gemtext/IsGemtext.cs b/src/Nitride.Gemtext/IsGemtext.cs new file mode 100644 index 0000000..352fa3f --- /dev/null +++ b/src/Nitride.Gemtext/IsGemtext.cs @@ -0,0 +1,11 @@ +namespace Nitride.Gemtext +{ + /// + /// A marker component for indicating that an entity is Gemtext, the format + /// for text files using the Gemini protocol. + /// + public class IsGemtext + { + public static IsGemtext Instance { get; } = new IsGemtext(); + } +} diff --git a/src/Nitride.Gemtext/Nitride.Gemtext.csproj b/src/Nitride.Gemtext/Nitride.Gemtext.csproj new file mode 100644 index 0000000..cc60e1c --- /dev/null +++ b/src/Nitride.Gemtext/Nitride.Gemtext.csproj @@ -0,0 +1,27 @@ + + + + net5.0 + + + + An extension to Nitride static site generator to generate Gemtext output. + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.Gemtext/NitrideGemtextBuilderExtensions.cs b/src/Nitride.Gemtext/NitrideGemtextBuilderExtensions.cs new file mode 100644 index 0000000..19b307a --- /dev/null +++ b/src/Nitride.Gemtext/NitrideGemtextBuilderExtensions.cs @@ -0,0 +1,14 @@ +using Autofac; + +namespace Nitride.Gemtext +{ + public static class NitrideGemtextBuilderExtensions + { + public static NitrideBuilder UseGemtext(this NitrideBuilder builder) + { + return builder + .ConfigureContainer( + x => x.RegisterModule()); + } + } +} diff --git a/src/Nitride.Gemtext/NitrideGemtextModule.cs b/src/Nitride.Gemtext/NitrideGemtextModule.cs new file mode 100644 index 0000000..d2866e8 --- /dev/null +++ b/src/Nitride.Gemtext/NitrideGemtextModule.cs @@ -0,0 +1,6 @@ +namespace Nitride.Gemtext +{ + public class NitrideGemtextModule : NitrideModuleBase + { + } +} diff --git a/src/Nitride.Generators/CodeAnalysisExtensions.cs b/src/Nitride.Generators/CodeAnalysisExtensions.cs new file mode 100644 index 0000000..afe66cf --- /dev/null +++ b/src/Nitride.Generators/CodeAnalysisExtensions.cs @@ -0,0 +1,159 @@ +using Microsoft.CodeAnalysis; + +namespace Nitride.Generators +{ + /// + /// Various wrappers around the diagnostics to simplify generation. + /// + public static class CodeAnalysisExtensions + { + /// + /// Creates an error message to break the build while generating code. + /// + /// The context that contains the diagnostic. + /// The normalized message code. + /// The string format for the message. + /// The optional parameters. + public static void Error( + this GeneratorExecutionContext context, + MessageCode messageCode, + string format, + params object[] parameters) + { + Error(context, messageCode, null, format, parameters); + } + + /// + /// Creates an error message to break the build while generating code. + /// + /// The context that contains the diagnostic. + /// The normalized message code. + /// The optional location for the message. + /// The string format for the message. + /// The optional parameters. + public static void Error( + this GeneratorExecutionContext context, + MessageCode messageCode, + Location? location, + string format, + params object[] parameters) + { + context.Message( + messageCode, + location, + DiagnosticSeverity.Error, + format, + parameters); + } + + /// + /// Creates an informational message to break the build while generating code. + /// + /// The context that contains the diagnostic. + /// The normalized message code. + /// The string format for the message. + /// The optional parameters. + public static void Information( + this GeneratorExecutionContext context, + MessageCode messageCode, + string format, + params object[] parameters) + { + Information(context, messageCode, null, format, parameters); + } + + /// + /// Creates an informational message to break the build while generating code. + /// + /// The context that contains the diagnostic. + /// The normalized message code. + /// The optional location for the message. + /// The string format for the message. + /// The optional parameters. + public static void Information( + this GeneratorExecutionContext context, + MessageCode messageCode, + Location? location, + string format, + params object[] parameters) + { + context.Message( + messageCode, + location, + DiagnosticSeverity.Info, + format, + parameters); + } + + /// + /// Creates a warning message to break the build while generating code. + /// + /// The context that contains the diagnostic. + /// The normalized message code. + /// The string format for the message. + /// The optional parameters. + public static void Warning( + this GeneratorExecutionContext context, + MessageCode messageCode, + string format, + params object[] parameters) + { + Warning(context, messageCode, null, format, parameters); + } + + /// + /// Creates a warning message to break the build while generating code. + /// + /// The context that contains the diagnostic. + /// The normalized message code. + /// The optional location for the message. + /// The string format for the message. + /// The optional parameters. + public static void Warning( + this GeneratorExecutionContext context, + MessageCode messageCode, + Location? location, + string format, + params object[] parameters) + { + context.Message( + messageCode, + location, + DiagnosticSeverity.Warning, + format, + parameters); + } + + /// + /// Creates a message to break the build while generating code. + /// + /// The context that contains the diagnostic. + /// The normalized message code. + /// The optional location for the message. + /// The string format for the message. + /// The optional parameters. + /// The severity of the message. + private static void Message( + this GeneratorExecutionContext context, + MessageCode messageCode, + Location? location, + DiagnosticSeverity severity, + string format, + params object[] parameters) + { + context.ReportDiagnostic( + Diagnostic.Create( + "GN" + ((int)messageCode).ToString("D4"), + "Nitride", + string.Format(format, parameters), + severity, + severity, + true, + severity is DiagnosticSeverity.Warning + or DiagnosticSeverity.Info + ? 4 + : 0, + location: location)); + } + } +} diff --git a/src/Nitride.Generators/MessageCode.cs b/src/Nitride.Generators/MessageCode.cs new file mode 100644 index 0000000..98cc85b --- /dev/null +++ b/src/Nitride.Generators/MessageCode.cs @@ -0,0 +1,10 @@ +namespace Nitride.Generators +{ + /// + /// All the error messages produced by the generators. + /// + public enum MessageCode + { + Debug = 1, + } +} diff --git a/src/Nitride.Generators/Nitride.Generators.csproj b/src/Nitride.Generators/Nitride.Generators.csproj new file mode 100644 index 0000000..381ef97 --- /dev/null +++ b/src/Nitride.Generators/Nitride.Generators.csproj @@ -0,0 +1,19 @@ + + + + net5.0 + enable + + + + Common source generators for Nitride. + + + + + + + + + + diff --git a/src/Nitride.Generators/WithPropertySourceGenerator.cs b/src/Nitride.Generators/WithPropertySourceGenerator.cs new file mode 100644 index 0000000..0037a73 --- /dev/null +++ b/src/Nitride.Generators/WithPropertySourceGenerator.cs @@ -0,0 +1,209 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; + +namespace Nitride.Generators +{ + /// + /// Implements a source generator that creates Set* methods for the various + /// properties that also returns the same object for purposes of chaining + /// together calls. + /// + [Generator] + public class WithPropertySourceGenerator : ISourceGenerator + { + public void Execute(GeneratorExecutionContext context) + { + // Get the generator infrastructure will create a receiver and + // populate it we can retrieve the populated instance via the + // context. + var syntaxReceiver = (SyntaxReceiver?)context.SyntaxReceiver; + + if (syntaxReceiver == null) + { + return; + } + + // Report any messages. + foreach (var message in syntaxReceiver.Messages) + { + context.Information( + MessageCode.Debug, + Location.Create( + "Temporary.g.cs", + TextSpan.FromBounds(0, 0), + new LinePositionSpan( + new LinePosition(0, 0), + new LinePosition(0, 0))), + "Generating additional identifier code: {0}", + message); + } + + // If we didn't find anything, then there is nothing to do. + if (syntaxReceiver.ClassesToAugment.Count == 0) + { + return; + } + + // Go through each one. + foreach (var cds in syntaxReceiver.ClassesToAugment) + { + this.GenerateClassFile(context, cds); + } + } + + public void Initialize(GeneratorInitializationContext context) + { + // Register a factory that can create our custom syntax receiver + context.RegisterForSyntaxNotifications( + () => new SyntaxReceiver(context)); + } + + private void GenerateClassFile( + GeneratorExecutionContext context, + ClassDeclarationSyntax cds) + { + // Get the namespace. + var nds = (NamespaceDeclarationSyntax?)cds.Parent; + + if (nds == null) + { + return; + } + + string? ns = nds.Name.ToString(); + + // Create the partial class. + StringBuilder buffer = new(); + buffer.AppendLine("#nullable enable"); + + // Copy the using statements from the file. + if (nds.Parent is CompilationUnitSyntax cus) + { + foreach (var uds in cus.Usings) + { + buffer.AppendLine(uds.ToString()); + } + + buffer.AppendLine(); + } + + // Create the namespace. + buffer.AppendLine($"namespace {ns}"); + buffer.AppendLine("{"); + buffer.AppendLine($" public partial class {cds.Identifier}"); + buffer.AppendLine(" {"); + + // Go through the properties of the namespace. + IEnumerable properties = cds.Members + .Where(m => m.Kind() == SyntaxKind.PropertyDeclaration) + .Cast(); + bool first = true; + + foreach (PropertyDeclarationSyntax pds in properties) + { + // See if we have a setter. + bool found = + pds.AccessorList?.Accessors + .Any(x => x.Keyword.ToString() == "set") + ?? false; + + if (!found) + { + continue; + } + + // If we aren't first, then add a newline before it. + if (first) + { + first = false; + } + else + { + buffer.AppendLine(); + } + + // Write some documentation. + buffer.AppendLine(" /// "); + buffer.AppendLine( + string.Format( + " /// Sets the {0} value and returns the operation for chaining.", + pds.Identifier)); + buffer.AppendLine(" /// "); + + // We have the components for writing out a setter. + buffer.AppendLine( + string.Format( + " public {0} With{1}({2} value)", + cds.Identifier, + pds.Identifier, + pds.Type)); + buffer.AppendLine(" {"); + buffer.AppendLine( + string.Format( + " this.{0} = value;", + pds.Identifier)); + buffer.AppendLine(" return this;"); + buffer.AppendLine(" }"); + } + + // Finish up the class. + buffer.AppendLine(" }"); + buffer.AppendLine("}"); + + // Create the source text and write out the file. + SourceText sourceText = SourceText.From( + buffer.ToString(), + Encoding.UTF8); + context.AddSource(cds.Identifier + ".Generated.cs", sourceText); + } + + private class SyntaxReceiver : ISyntaxReceiver + { + private readonly GeneratorInitializationContext context; + + public SyntaxReceiver(GeneratorInitializationContext context) + { + this.context = context; + this.ClassesToAugment = new List(); + this.Messages = new List(); + } + + public List ClassesToAugment { get; } + + public List Messages { get; } + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + // We only care about class declarations. + if (syntaxNode is not ClassDeclarationSyntax cds) + { + return; + } + + // See if the class has our set properties attribute. + bool found = cds + .AttributeLists + .AsEnumerable() + .SelectMany(x => x.Attributes) + .Select(x => x.Name.ToString()) + .Any( + x => x switch + { + "WithProperties" => true, + "WithPropertiesAttribute" => true, + _ => false, + }); + + if (found) + { + this.ClassesToAugment.Add(cds); + } + } + } + } +} diff --git a/src/Nitride.Handlebars/ApplyContentHandlebarsTemplate.cs b/src/Nitride.Handlebars/ApplyContentHandlebarsTemplate.cs new file mode 100644 index 0000000..2f49644 --- /dev/null +++ b/src/Nitride.Handlebars/ApplyContentHandlebarsTemplate.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using Gallium; +using HandlebarsDotNet; +using Nitride.Contents; + +namespace Nitride.Handlebars +{ + /// + /// An operation that uses the content to create a template that is then + /// applied against the content and metadata and then replaces the content + /// of that entity. + /// + public class ApplyContentHandlebarsTemplate : NitrideOperationBase + { + private readonly HandlebarsTemplateCache cache; + + public ApplyContentHandlebarsTemplate(HandlebarsTemplateCache cache) + { + this.cache = cache; + } + + /// + /// Gets or sets the callback used to create a model from a given + /// entity. This allows for the website to customize what information is + /// being passed to the template. + /// + public Func? CreateModelCallback { get; set; } + + /// + public override IEnumerable Run(IEnumerable input) + { + this.CheckNotNull(x => x.CreateModelCallback); + + return input + .ForEachEntity(this.Apply); + } + + /// + /// Sets the callback for the template and returns the operation to + /// chain operations. + /// + /// The callback to set. + /// The ApplyContentHandlebarsTemplate to chain requests. + public ApplyContentHandlebarsTemplate WithCreateModelCallback( + Func? callback) + { + this.CreateModelCallback = callback; + return this; + } + + private Entity Apply( + Entity entity, + HasHandlebarsTemplate _, + ITextContent content) + { + // Create the model using the callback. + TModel model = this.CreateModelCallback!(entity); + + // Create a template from the contents. + string text = content.GetText(); + HandlebarsTemplate template = + this.cache.GetLiteralTemplate(text); + + // Render the template and create a new entity with the updated + // text. + string result = template(model!); + + return entity + .Remove() + .SetTextContent(new StringTextContent(result)); + } + } +} diff --git a/src/Nitride.Handlebars/ApplyStyleHandlebarsTemplate.cs b/src/Nitride.Handlebars/ApplyStyleHandlebarsTemplate.cs new file mode 100644 index 0000000..84c2278 --- /dev/null +++ b/src/Nitride.Handlebars/ApplyStyleHandlebarsTemplate.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using Gallium; +using HandlebarsDotNet; +using Nitride.Contents; + +namespace Nitride.Handlebars +{ + /// + /// An operation that applies a common or shared template on the content of + /// a document that includes theme or styling information. + /// + public class ApplyStyleHandlebarsTemplate : NitrideOperationBase + { + private readonly HandlebarsTemplateCache cache; + + public ApplyStyleHandlebarsTemplate(HandlebarsTemplateCache cache) + { + this.cache = cache; + } + + /// + /// Gets or sets the callback used to create a model from a given + /// entity. This allows for the website to customize what information is + /// being passed to the template. + /// + public Func? CreateModelCallback { get; set; } + + /// + /// Gets or sets the callback used to determine which template to use + /// for a given entity. This lets one have a per-page template change. + /// + public Func? GetTemplateName { get; set; } + + public IHandlebars? Handlebars { get; set; } + + /// + public override IEnumerable Run(IEnumerable input) + { + // Make sure we have sane data. + this.CheckNotNull(x => x.CreateModelCallback); + this.CheckNotNull(x => x.Handlebars); + this.CheckNotNull(x => x.GetTemplateName); + + // Create and set up the Handlebars. + return input + .ForEachEntity(this.Apply); + } + + /// + /// Sets the callback for the template and returns the operation to + /// chain operations. + /// + /// The callback to set. + /// The ApplyContentHandlebarsTemplate to chain requests. + public ApplyStyleHandlebarsTemplate WithCreateModelCallback( + Func? callback) + { + this.CreateModelCallback = callback; + return this; + } + + public ApplyStyleHandlebarsTemplate WithGetTemplateName( + Func? callback) + { + this.GetTemplateName = callback; + return this; + } + + public ApplyStyleHandlebarsTemplate WithHandlebars( + IHandlebars? handlebars) + { + this.Handlebars = handlebars; + return this; + } + + private Entity Apply(Entity entity, ITextContent content) + { + TModel model = this.CreateModelCallback!(entity); + string name = this.GetTemplateName!(entity); + HandlebarsTemplate template = + this.cache.GetNamedTemplate(name); + string result = template(model!); + + return entity.SetTextContent(result); + } + } +} diff --git a/src/Nitride.Handlebars/HandlebarsTemplateCache.cs b/src/Nitride.Handlebars/HandlebarsTemplateCache.cs new file mode 100644 index 0000000..3451fbd --- /dev/null +++ b/src/Nitride.Handlebars/HandlebarsTemplateCache.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using HandlebarsDotNet; +using Open.Threading; + +namespace Nitride.Handlebars +{ + /// + /// Implements a cache for templates to prevent compiling the same template + /// more than once. + /// + public class HandlebarsTemplateCache + { + private readonly IHandlebars handlebars; + + private readonly ModificationSynchronizer locker; + + private readonly Dictionary> + templates; + + public HandlebarsTemplateCache(IHandlebars handlebars) + { + this.handlebars = handlebars; + this.locker = new ModificationSynchronizer(); + this.templates = + new Dictionary>(); + } + + /// + /// Caches the template by name based on the contents of the disk. It + /// does it once in a multi-threaded manner to ensure it is only cached + /// once in memory. + /// + /// The string that contains the template. + /// + public HandlebarsTemplate GetLiteralTemplate( + string literal) + { + // Start with a read lock to see if we've already compiled it. + this.locker.Modifying( + () => !this.templates.ContainsKey(literal), + () => + { + HandlebarsTemplate template = + this.handlebars + !.Compile(literal); + + this.templates[literal] = template; + + return true; + }); + + return this.locker.Reading(() => this.templates[literal]); + } + + /// + /// Caches the template by name based on the contents of the disk. It + /// does it once in a multi-threaded manner to ensure it is only cached + /// once in memory. + /// + /// + /// + public HandlebarsTemplate GetNamedTemplate( + string templateName) + { + string template = $"{{{{> {templateName}}}}}"; + + return this.GetLiteralTemplate(template); + } + } +} diff --git a/src/Nitride.Handlebars/HasHandlebarsTemplate.cs b/src/Nitride.Handlebars/HasHandlebarsTemplate.cs new file mode 100644 index 0000000..acedb47 --- /dev/null +++ b/src/Nitride.Handlebars/HasHandlebarsTemplate.cs @@ -0,0 +1,11 @@ +namespace Nitride.Handlebars +{ + /// + /// A marker component that indicates that a given file with text component + /// has a Handlebars template in it. + /// + public class HasHandlebarsTemplate + { + public static HasHandlebarsTemplate Instance { get; } = new(); + } +} diff --git a/src/Nitride.Handlebars/IdentifyHandlebars.cs b/src/Nitride.Handlebars/IdentifyHandlebars.cs new file mode 100644 index 0000000..5a59d6a --- /dev/null +++ b/src/Nitride.Handlebars/IdentifyHandlebars.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Gallium; +using Nitride.Contents; + +namespace Nitride.Handlebars +{ + /// + /// An operation that discovers which text files have a Handlebars template + /// inside them. + /// + public class IdentifyHandlebars : INitrideOperation + { + /// + public IEnumerable Run(IEnumerable input) + { + return input + .ForEachEntity(this.ScanContent); + } + + private Entity ScanContent(Entity entity, ITextContent content) + { + string text = content.GetText(); + + if (text.Contains("{{") && text.Contains("}}")) + { + return entity.Set(HasHandlebarsTemplate.Instance); + } + + return entity; + } + } +} diff --git a/src/Nitride.Handlebars/Nitride.Handlebars.csproj b/src/Nitride.Handlebars/Nitride.Handlebars.csproj new file mode 100644 index 0000000..7865823 --- /dev/null +++ b/src/Nitride.Handlebars/Nitride.Handlebars.csproj @@ -0,0 +1,36 @@ + + + + net5.0 + enable + + + + An extension to Nitride static site generator to style output with Handlebars. + + + + + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.Handlebars/NitrideHandlebarsBuilderExtensions.cs b/src/Nitride.Handlebars/NitrideHandlebarsBuilderExtensions.cs new file mode 100644 index 0000000..00b6764 --- /dev/null +++ b/src/Nitride.Handlebars/NitrideHandlebarsBuilderExtensions.cs @@ -0,0 +1,14 @@ +using Autofac; + +namespace Nitride.Handlebars +{ + public static class NitrideHandlebarsBuilderExtensions + { + public static NitrideBuilder UseHandlebars(this NitrideBuilder builder) + { + return builder + .ConfigureContainer( + x => x.RegisterModule()); + } + } +} diff --git a/src/Nitride.Handlebars/NitrideHandlebarsModule.cs b/src/Nitride.Handlebars/NitrideHandlebarsModule.cs new file mode 100644 index 0000000..9351949 --- /dev/null +++ b/src/Nitride.Handlebars/NitrideHandlebarsModule.cs @@ -0,0 +1,22 @@ +using Autofac; + +namespace Nitride.Handlebars +{ + public class NitrideHandlebarsModule : NitrideModuleBase + { + /// + protected override void Register(ContainerBuilder builder) + { + builder + .RegisterType() + .AsSelf() + .SingleInstance(); + builder + .RegisterGeneric(typeof(ApplyContentHandlebarsTemplate<>)) + .As(typeof(ApplyContentHandlebarsTemplate<>)); + builder + .RegisterGeneric(typeof(ApplyStyleHandlebarsTemplate<>)) + .As(typeof(ApplyStyleHandlebarsTemplate<>)); + } + } +} diff --git a/src/Nitride.Handlebars/README.md b/src/Nitride.Handlebars/README.md new file mode 100644 index 0000000..6bcd33f --- /dev/null +++ b/src/Nitride.Handlebars/README.md @@ -0,0 +1,26 @@ +Nitride.Handlebars +================== + +This is a collection +of [Handlebars](https://github.com/Handlebars-Net/Handlebars.Net) +operations that work with Nitride. There are two ways of using Handelbars in +this package. + +## IHandlebars + +This library does *not* configure or register `IHandlebars` but requires it to +be injected into the DI container (Autofac) along with any templates or inlines +loaded. + +## Styling Templates + +The first is to use it to apply a Handlebars theme to a page or text content. +This would include adding links to the CSS, any javascript, generating menus, +and common navigation elements. + +## Content Templates + +The second is used to apply it to the Handlebars inside the text content. This +is the page-specific content that needs to be resolved. A good example of this +might be creating a "last five posts" page or embedding some metadata from the +YAML header into the page. diff --git a/src/Nitride.Html/HtmlEntitiesToUnicode.cs b/src/Nitride.Html/HtmlEntitiesToUnicode.cs new file mode 100644 index 0000000..a60cd2c --- /dev/null +++ b/src/Nitride.Html/HtmlEntitiesToUnicode.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Net; +using Gallium; +using Nitride.Contents; + +namespace Nitride.Html +{ + /// + /// Converts the text input that uses HTML entities and turns them into + /// Unicode variations. + /// + public class HtmlEntitiesToUnicode : NitrideOperationBase + { + /// + public override IEnumerable Run(IEnumerable input) + { + return input + .ForEachEntity(this.ResolveHtmlEntities); + } + + private Entity ResolveHtmlEntities( + Entity entity, + ITextContent content) + { + string text = content.GetText(); + string resolved = WebUtility.HtmlDecode(text); + + return entity.SetTextContent(resolved); + } + } +} diff --git a/src/Nitride.Html/IsHtml.cs b/src/Nitride.Html/IsHtml.cs new file mode 100644 index 0000000..8e687ec --- /dev/null +++ b/src/Nitride.Html/IsHtml.cs @@ -0,0 +1,10 @@ +namespace Nitride.Html +{ + /// + /// A marker component that indicates that the entity is an HTML file. + /// + public class IsHtml + { + public static IsHtml Instance { get; } = new(); + } +} diff --git a/src/Nitride.Html/Nitride.Html.csproj b/src/Nitride.Html/Nitride.Html.csproj new file mode 100644 index 0000000..7aa6d8e --- /dev/null +++ b/src/Nitride.Html/Nitride.Html.csproj @@ -0,0 +1,31 @@ + + + + net5.0 + + + + An extension to Nitride static site generator to generate HTML output. + + + + + + + + + True + + + + + Analyzer + False + + + + + + + + diff --git a/src/Nitride.Html/NitrideHtmlBuilderExtensions.cs b/src/Nitride.Html/NitrideHtmlBuilderExtensions.cs new file mode 100644 index 0000000..77ae44b --- /dev/null +++ b/src/Nitride.Html/NitrideHtmlBuilderExtensions.cs @@ -0,0 +1,14 @@ +using Autofac; + +namespace Nitride.Html +{ + public static class NitrideHtmlBuilderExtensions + { + public static NitrideBuilder UseHtml(this NitrideBuilder builder) + { + return builder + .ConfigureContainer( + x => x.RegisterModule()); + } + } +} diff --git a/src/Nitride.Html/NitrideHtmlModule.cs b/src/Nitride.Html/NitrideHtmlModule.cs new file mode 100644 index 0000000..0534448 --- /dev/null +++ b/src/Nitride.Html/NitrideHtmlModule.cs @@ -0,0 +1,6 @@ +namespace Nitride.Html +{ + public class NitrideHtmlModule : NitrideModuleBase + { + } +} diff --git a/src/Nitride.IO.Tests/AddPathPrefixTests.cs b/src/Nitride.IO.Tests/AddPathPrefixTests.cs new file mode 100644 index 0000000..4f6b36c --- /dev/null +++ b/src/Nitride.IO.Tests/AddPathPrefixTests.cs @@ -0,0 +1,48 @@ +using System.Linq; +using Autofac; +using Nitride.IO.Contents; +using Nitride.IO.Paths; +using Xunit; +using Xunit.Abstractions; +using Zio; +using Zio.FileSystems; + +namespace Nitride.IO.Tests +{ + public class AddPathPrefixTests : NitrideIOTestsBase + { + private readonly MemoryFileSystem fileSystem; + + public AddPathPrefixTests(ITestOutputHelper output) + : base(output) + { + this.fileSystem = new MemoryFileSystem(); + this.fileSystem.CreateFile("/b1.txt"); + this.fileSystem.CreateFile("/c1.md"); + } + + [Fact] + public void PrefixAllFiles() + { + // Set up the operation. + var readFiles = this.Container.Resolve(); + var op = new AddPathPrefix("/prefix"); + + // Read and replace the paths. + IOrderedEnumerable output = readFiles(this.fileSystem) + .Read() + .Run(op) + .Select(x => x.Get().ToString()) + .OrderBy(x => x); + + // Verify the results. + Assert.Equal( + new[] + { + "/prefix/b1.txt", + "/prefix/c1.md", + }, + output); + } + } +} diff --git a/src/Nitride.IO.Tests/MoveToIndexPathsTests.cs b/src/Nitride.IO.Tests/MoveToIndexPathsTests.cs new file mode 100644 index 0000000..77e8831 --- /dev/null +++ b/src/Nitride.IO.Tests/MoveToIndexPathsTests.cs @@ -0,0 +1,80 @@ +using System.Linq; +using Autofac; +using Nitride.IO.Contents; +using Nitride.IO.Paths; +using Xunit; +using Xunit.Abstractions; +using Zio; +using Zio.FileSystems; + +namespace Nitride.IO.Tests +{ + public class MoveToIndexPathsTests : NitrideIOTestsBase + { + private readonly MemoryFileSystem fileSystem; + + public MoveToIndexPathsTests(ITestOutputHelper output) + : base(output) + { + this.fileSystem = new MemoryFileSystem(); + this.fileSystem.CreateDirectory("/c1"); + this.fileSystem.CreateFile("/a1"); + this.fileSystem.CreateFile("/b1.txt"); + this.fileSystem.CreateFile("/c1/index.md"); + this.fileSystem.CreateFile("/d1.html"); + } + + [Fact] + public void MoveAllFiles() + { + // Set up the operation. + var readFiles = this.Container.Resolve(); + var op = new MoveToIndexPaths(); + + // Read and replace the paths. + IOrderedEnumerable output = readFiles(this.fileSystem) + .Read() + .Run(op) + .Select(x => x.Get().ToString()) + .OrderBy(x => x); + + // Verify the results. + Assert.Equal( + new[] + { + "/a1", + "/b1.txt", + "/c1/index.md", + "/d1/index.html", + }, + output); + } + + [Fact] + public void OverrideCanMoveCallback() + { + // Set up the operation. + var readFiles = this.Container.Resolve(); + MoveToIndexPaths? op = new MoveToIndexPaths() + .WithCanMoveCallback((path) => path.ToString().Contains("a1")); + + // Read and replace the paths. + IOrderedEnumerable output = readFiles(this.fileSystem) + .Read() + .Run(op) + .Select(x => x.Get().ToString()) + .OrderBy(x => x); + + // Verify the results. + Assert.Equal( + new[] + { + "/a1/index", + "/b1.txt", + "/c1/index.md", + "/d1.html", + }, + output); + } + } +} diff --git a/src/Nitride.IO.Tests/Nitride.IO.Tests.csproj b/src/Nitride.IO.Tests/Nitride.IO.Tests.csproj new file mode 100644 index 0000000..a04bedc --- /dev/null +++ b/src/Nitride.IO.Tests/Nitride.IO.Tests.csproj @@ -0,0 +1,29 @@ + + + + net5.0 + enable + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + diff --git a/src/Nitride.IO.Tests/NitrideIOTestsBase.cs b/src/Nitride.IO.Tests/NitrideIOTestsBase.cs new file mode 100644 index 0000000..e93ccfd --- /dev/null +++ b/src/Nitride.IO.Tests/NitrideIOTestsBase.cs @@ -0,0 +1,21 @@ +using Autofac; +using Nitride.Tests; +using Xunit.Abstractions; + +namespace Nitride.IO.Tests +{ + public abstract class NitrideIOTestsBase : NitrideTestsBase + { + protected NitrideIOTestsBase(ITestOutputHelper output) + : base(output) + { + } + + /// + protected override void ConfigureContainer(ContainerBuilder builder) + { + base.ConfigureContainer(builder); + builder.RegisterModule(); + } + } +} diff --git a/src/Nitride.IO.Tests/ReadFilesTests.cs b/src/Nitride.IO.Tests/ReadFilesTests.cs new file mode 100644 index 0000000..1e84103 --- /dev/null +++ b/src/Nitride.IO.Tests/ReadFilesTests.cs @@ -0,0 +1,97 @@ +using System.Linq; +using Autofac; +using Nitride.IO.Contents; +using Xunit; +using Xunit.Abstractions; +using Zio; +using Zio.FileSystems; + +namespace Nitride.IO.Tests +{ + /// + /// Tests the functionality of the ReadFiles(). + /// + public class ReadFilesTests : NitrideIOTestsBase + { + private readonly MemoryFileSystem fileSystem; + + public ReadFilesTests(ITestOutputHelper output) + : base(output) + { + this.fileSystem = new MemoryFileSystem(); + this.fileSystem.CreateDirectory("/b1"); + this.fileSystem.CreateDirectory("/c1"); + this.fileSystem.CreateDirectory("/c1/c2"); + this.fileSystem.CreateDirectory("/d1"); + this.fileSystem.WriteAllText("/a.txt", "File A"); + this.fileSystem.WriteAllText("/b1/b.md", "File B"); + this.fileSystem.WriteAllText("/c1/c.txt", "File C"); + this.fileSystem.WriteAllText("/c1/c2/e.md", "File C"); + } + + [Fact] + public void ReadAllFiles() + { + // Set up the operation. + var factory = this.Container.Resolve(); + ReadFiles op = factory(this.fileSystem); + + // Verify the paths. + IOrderedEnumerable paths = op.Read() + .Select(x => x.Get()) + .Select(x => (string)x) + .OrderBy(x => x); + + Assert.Equal( + new[] + { + "/a.txt", + "/b1/b.md", + "/c1/c.txt", + "/c1/c2/e.md", + }, + paths); + } + + [Fact] + public void ReadGlob() + { + // Set up the operation. + var factory = this.Container.Resolve(); + ReadFiles op = factory(this.fileSystem); + + // Verify the paths. + IOrderedEnumerable paths = op.Read("/*.txt") + .Select(x => (string)x.Get()) + .OrderBy(x => x); + + Assert.Equal( + new[] + { + "/a.txt", + }, + paths); + } + + [Fact] + public void ReadGlobWithSubdirectories() + { + // Set up the operation. + var factory = this.Container.Resolve(); + ReadFiles op = factory(this.fileSystem); + + // Verify the paths. + IOrderedEnumerable paths = op.Read("**/*.txt") + .Select(x => (string)x.Get()) + .OrderBy(x => x); + + Assert.Equal( + new[] + { + "/a.txt", + "/c1/c.txt", + }, + paths); + } + } +} diff --git a/src/Nitride.IO.Tests/RemovePathPrefixTests.cs b/src/Nitride.IO.Tests/RemovePathPrefixTests.cs new file mode 100644 index 0000000..99270bc --- /dev/null +++ b/src/Nitride.IO.Tests/RemovePathPrefixTests.cs @@ -0,0 +1,50 @@ +using System.Linq; +using Autofac; +using Nitride.IO.Contents; +using Nitride.IO.Paths; +using Xunit; +using Xunit.Abstractions; +using Zio; +using Zio.FileSystems; + +namespace Nitride.IO.Tests +{ + public class RemovePathPrefixTests : NitrideIOTestsBase + { + private readonly MemoryFileSystem fileSystem; + + public RemovePathPrefixTests(ITestOutputHelper output) + : base(output) + { + this.fileSystem = new MemoryFileSystem(); + this.fileSystem.CreateDirectory("/a"); + this.fileSystem.CreateDirectory("/a/a"); + this.fileSystem.CreateFile("/a/b1.txt"); + this.fileSystem.CreateFile("/a/a/c1.md"); + } + + [Fact] + public void PrefixAllFiles() + { + // Set up the operation. + var readFiles = this.Container.Resolve(); + var op = new RemovePathPrefix("/a"); + + // Read and replace the paths. + IOrderedEnumerable output = readFiles(this.fileSystem) + .Read() + .Run(op) + .Select(x => x.Get().ToString()) + .OrderBy(x => x); + + // Verify the results. + Assert.Equal( + new[] + { + "/a/c1.md", + "/b1.txt", + }, + output); + } + } +} diff --git a/src/Nitride.IO.Tests/WriteFilesTest.cs b/src/Nitride.IO.Tests/WriteFilesTest.cs new file mode 100644 index 0000000..5c9aacf --- /dev/null +++ b/src/Nitride.IO.Tests/WriteFilesTest.cs @@ -0,0 +1,63 @@ +using System.Linq; +using Autofac; +using Nitride.Contents; +using Nitride.IO.Contents; +using Xunit; +using Xunit.Abstractions; +using Zio; +using Zio.FileSystems; + +namespace Nitride.IO.Tests +{ + /// + /// Tests the functionality of the WriteFiles(). + /// + public class WriteFilesTest : NitrideIOTestsBase + { + private readonly MemoryFileSystem fileSystem; + + public WriteFilesTest(ITestOutputHelper output) + : base(output) + { + this.fileSystem = new MemoryFileSystem(); + this.fileSystem.CreateDirectory("/b1"); + this.fileSystem.CreateDirectory("/c1"); + this.fileSystem.CreateDirectory("/c1/c2"); + this.fileSystem.CreateDirectory("/d1"); + this.fileSystem.WriteAllText("/a.txt", "File A"); + this.fileSystem.WriteAllText("/b1/b.md", "File B"); + this.fileSystem.WriteAllText("/c1/c2/e.md", "File E"); + } + + [Fact] + public void WriteAllFiles() + { + // Set up the operation. + var output = new MemoryFileSystem(); + var readFiles = this.Container.Resolve(); + var factory = this.Container.Resolve(); + WriteFiles op = factory(output); + + // Read and write out the files. We switch one of the files to be + // text content to make sure that works too. + readFiles(this.fileSystem) + .Read() + .Select( + x => x.Get() == "/b1/b.md" + ? x.SetTextContent( + ((ITextContentConvertable)x.GetBinaryContent()) + .ToTextContent()) + : x) + .Run(op); + + // Verify the results. + Assert.True(output.FileExists("/a.txt")); + Assert.True(output.FileExists("/b1/b.md")); + Assert.True(output.FileExists("/c1/c2/e.md")); + + Assert.Equal("File A", output.ReadAllText("/a.txt")); + Assert.Equal("File B", output.ReadAllText("/b1/b.md")); + Assert.Equal("File E", output.ReadAllText("/c1/c2/e.md")); + } + } +} diff --git a/src/Nitride.IO/Contents/FileEntryBinaryContent.cs b/src/Nitride.IO/Contents/FileEntryBinaryContent.cs new file mode 100644 index 0000000..aaf16e7 --- /dev/null +++ b/src/Nitride.IO/Contents/FileEntryBinaryContent.cs @@ -0,0 +1,35 @@ +using System.IO; +using Nitride.Contents; +using Zio; + +namespace Nitride.IO.Contents +{ + /// + /// Contains a wrapper around a file entry to retrieve the binary data. + /// + public class FileEntryBinaryContent + : IBinaryContent, ITextContentConvertable + { + private readonly FileEntry entry; + + public FileEntryBinaryContent(FileEntry entry) + { + this.entry = entry; + } + + /// + public Stream GetStream() + { + return this.entry.Open( + FileMode.Open, + FileAccess.Read, + FileShare.Read); + } + + /// + public ITextContent ToTextContent() + { + return new FileEntryTextContent(this.entry); + } + } +} diff --git a/src/Nitride.IO/Contents/FileEntryTextContent.cs b/src/Nitride.IO/Contents/FileEntryTextContent.cs new file mode 100644 index 0000000..1e6a4d1 --- /dev/null +++ b/src/Nitride.IO/Contents/FileEntryTextContent.cs @@ -0,0 +1,38 @@ +using System.IO; +using System.Text; +using Nitride.Contents; +using Zio; + +namespace Nitride.IO.Contents +{ + /// + /// Contains a wrapper around a file entry to retrieve text data. + /// + public class FileEntryTextContent + : ITextContent, IBinaryContentConvertable + { + private readonly FileEntry entry; + + public FileEntryTextContent(FileEntry entry) + { + this.entry = entry; + } + + /// + public TextReader GetReader() + { + return new StreamReader( + this.entry.Open( + FileMode.Open, + FileAccess.Read, + FileShare.Read), + Encoding.UTF8); + } + + /// + public IBinaryContent ToBinaryContent() + { + return new FileEntryBinaryContent(this.entry); + } + } +} diff --git a/src/Nitride.IO/Contents/ReadFiles.cs b/src/Nitride.IO/Contents/ReadFiles.cs new file mode 100644 index 0000000..dd09433 --- /dev/null +++ b/src/Nitride.IO/Contents/ReadFiles.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using DotNet.Globbing; +using Gallium; +using Nitride.Contents; +using Zio; + +namespace Nitride.IO.Contents +{ + /// + /// A module that reads files from the file system and wraps them in an + /// entity with the following components: UPath, IContent. + /// + public class ReadFiles : FileSystemOperation + { + public ReadFiles(IFileSystem fileSystem) + : base(fileSystem) + { + } + + /// + /// Primary method for creating a read file. + /// + public delegate ReadFiles Factory(IFileSystem fileSystem); + + /// + /// Reads all files from the file system and returns them. + /// + /// A populated collection of entities. + public IEnumerable Read( + UPath path = new(), + string searchPattern = "*", + SearchOption search = SearchOption.AllDirectories) + { + // Normalize the path. + path = path == new UPath() ? "/" : path; + + // Search for the file and wrap the results. + IEnumerable files = this.FileSystem + .EnumerateFileEntries(path, searchPattern, search); + IEnumerable entities = files.Select(this.ToEntity); + + return entities; + } + + /// + /// Reads all files from the file system and returns them. + /// + /// A populated collection of entities. + public IEnumerable Read(string glob) + { + Glob parsed = Glob.Parse(glob); + + return this.Read(parsed); + } + + /// + /// Reads all files from the file system, filtering them out by the + /// minimatch pattern (as defined by DotNet.Blob). + /// + /// A populated collection of entities. + public IEnumerable Read(Glob glob) + { + IEnumerable files = this.FileSystem + .EnumerateFileEntries("/", "*.*", SearchOption.AllDirectories) + .Where(x => glob.IsMatch(x.Path.ToString())); + IEnumerable entities = files.Select(this.ToEntity); + + return entities; + } + + /// + /// Creates an entity with the standard components for all Zio-based + /// files. This attaches the file's path relative to the file system + /// and a way of accessing the content from the file system. + /// + /// The Zio file entry. + /// An Entity with appropriate content. + private Entity ToEntity(FileEntry file) + { + Entity entity = new Entity() + .Set(file.Path) + .SetBinaryContent(new FileEntryBinaryContent(file)); + + return entity; + } + } +} diff --git a/src/Nitride.IO/Contents/WriteFiles.cs b/src/Nitride.IO/Contents/WriteFiles.cs new file mode 100644 index 0000000..5e49160 --- /dev/null +++ b/src/Nitride.IO/Contents/WriteFiles.cs @@ -0,0 +1,220 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Gallium; +using Nitride.Contents; +using Serilog; +using Zio; + +namespace Nitride.IO.Contents +{ + /// + /// An operation that writes out entities to a file system. + /// + [WithProperties] + public partial class WriteFiles : FileSystemOperation, INitrideOperation + { + private readonly ILogger logger; + + private Dictionary> factories; + + public WriteFiles( + IFileSystem fileSystem, + ILogger logger) + : base(fileSystem) + { + this.logger = logger.ForContext(); + this.factories = new Dictionary> + { + [typeof(IBinaryContent)] = GetBinaryStream, + [typeof(ITextContent)] = this.GetTextStream, + }; + } + + /// + /// Primary method for creating a write files operation. + /// + public delegate WriteFiles Factory(IFileSystem fileSystem); + + public Dictionary> StreamFactories + { + get => this.factories; + set => this.factories = + value ?? throw new ArgumentNullException(nameof(value)); + } + + /// + /// Gets or sets the encoding to force any text output. + /// + public Encoding? TextEncoding { get; set; } + + /// + /// Writes out all the files to the given file system using the paths + /// currently stored in the `UPath` component. Only files that have + /// a path and a registered writer will be written. + /// + /// The entities to parse. + /// The same list of entities without changes. + public IEnumerable Run(IEnumerable entities) + { + // We need the `ToList()` here, otherwise it doesn't work. + IEnumerable results = entities + .ForEachEntity(this.Process) + .ToList(); + + return results; + } + + private static Stream GetBinaryStream(IContent content) + { + return ((IBinaryContent)content).GetStream(); + } + + private Stream GetTextStream(IContent content) + { + // See if we can convert the stream first. If that is the case, then + // we don't have to load it entirely in memory. + if (content is IBinaryContentConvertable convertable) + { + return convertable.ToBinaryContent().GetStream(); + } + + // We have the load the text into memory and convert it. + var textContent = (ITextContent)content; + string text = textContent.GetReader().ReadToEnd(); + var stream = new MemoryStream(); + var writer = new StreamWriter( + stream, + this.TextEncoding ?? Encoding.UTF8); + + writer.Write(text); + writer.Flush(); + stream.Position = 0; + + return stream; + } + + /// + /// Internal method for writing out the entity. This handles the + /// registered writers to allow for multiple `IContent` types being + /// written out automatically. + /// + /// The entity to write out. + /// The path of the entity. + /// The entity passed in. + private Entity Process(Entity entity, UPath path) + { + // See if we have any content. If we don't, then there is nothing + // to do. + if (!entity.HasContent()) + { + return entity; + } + + // First see if we have a factory for the exact type of content. + IContent content = entity.GetContent(); + + if (this.factories.TryGetValue( + content.GetType(), + out var getStream)) + { + Stream stream = getStream(content); + + return this.Process(entity, path, stream); + } + + // If we have an easy conversion, then use that so we don't have to + // walk up the tree looking for one we do have. + if (content is IBinaryContentConvertable binaryConvertable + && this.factories.TryGetValue( + typeof(IBinaryContent), + out var binaryContent)) + { + Stream stream = + binaryContent(binaryConvertable.ToBinaryContent()); + + return this.Process(entity, path, stream); + } + + if (content is ITextContentConvertable textConvertable + && this.factories.TryGetValue( + typeof(ITextContent), + out var textContent)) + { + Stream stream = textContent(textConvertable.ToTextContent()); + + return this.Process(entity, path, stream); + } + + // For everything else, we have to find a content that we have a + // registered type for by walking up the inheritance tree and + // finding the right type. + List types = new() { content.GetType() }; + + while (types.Count > 0) + { + // Check to see if we have any of these types. + Func? found = types + .Select( + x => this.factories.TryGetValue(x, out var factory) + ? factory + : null) + .FirstOrDefault(x => x != null); + + if (found != null) + { + Stream stream = found(content); + + return this.Process(entity, path, stream); + } + + // We didn't find one, so add all the parent types and try + // again with the new list. + types = types + .SelectMany( + x => new[] { x.BaseType } + .Union(x.GetInterfaces())) + .Where(x => x != null) + .Select(x => x!) + .ToList(); + } + + // If we got this far, we never found a content to handle. + throw new InvalidOperationException( + "Cannot write out entity " + + path + + " because cannot determine how to get a stream out content type " + + content.GetType().FullName + + ". To resolve, register a function to this.StreamFactories."); + } + + /// + /// Writes out a stream to the given path in the file system. + /// + /// The entity being written out. + /// The path to write out, directories will be created. + /// The stream to write out. + /// The entity passed in. + private Entity Process(Entity entity, UPath path, Stream stream) + { + // Make sure we have the directory structure. + UPath directory = path.GetDirectory(); + + if (directory != "/") + { + this.FileSystem.CreateDirectory(directory); + } + + // Write out the file. + using Stream fileStream = this.FileSystem.CreateFile(path); + + stream.CopyTo(fileStream); + stream.Close(); + + // Return the entity because we've written out the files. + return entity; + } + } +} diff --git a/src/Nitride.IO/Directories/ClearDirectory.cs b/src/Nitride.IO/Directories/ClearDirectory.cs new file mode 100644 index 0000000..fe66530 --- /dev/null +++ b/src/Nitride.IO/Directories/ClearDirectory.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using Gallium; +using Serilog; +using Zio; + +namespace Nitride.IO.Directories +{ + /// + /// A Nitride operation that removes the contents of a directory but not + /// the directory itself. This is used because some tools don't handle + /// when the root directory is removed. + /// This will create the top-level directory if it doesn't exist. + /// + [WithProperties] + public partial class ClearDirectory : FileSystemOperation, INitrideOperation + { + private readonly ILogger logger; + + public ClearDirectory( + ILogger logger, + IFileSystem fileSystem) + : base(fileSystem) + { + this.logger = logger.ForContext(); + } + + /// + /// Gets or sets the path of the directory to clear. + /// + public UPath? Path { get; set; } + + public IEnumerable Run() + { + return this.Run(new List()); + } + + /// + public IEnumerable Run(IEnumerable input) + { + // This really isn't an input-type of operation, but it can fit + // inside one to keep a pattern. + if (!this.Path.HasValue) + { + throw new InvalidOperationException( + nameof(ClearDirectory) + + "cannot be used without setting the path either by the" + + "factory method, the constructor, the property, or " + + "SetPath method."); + } + + // See if the directory exists. If it doesn't, then we make it. + UPath path = this.Path.Value; + + if (!this.FileSystem.DirectoryExists(path)) + { + this.logger.Information( + "Creating the directory {Path}", + path); + this.FileSystem.CreateDirectory(path); + } + + // Clear out the contents. + IEnumerable files = this.FileSystem.EnumerateFiles(path); + IEnumerable directories = + this.FileSystem.EnumerateDirectories(path); + + foreach (UPath file in files) + { + this.FileSystem.DeleteFile(file); + } + + foreach (UPath directory in directories) + { + this.FileSystem.DeleteDirectory(directory, true); + } + + // Just pass the input on. + return input; + } + } +} diff --git a/src/Nitride.IO/FileSystemOperation.cs b/src/Nitride.IO/FileSystemOperation.cs new file mode 100644 index 0000000..5d9a4ba --- /dev/null +++ b/src/Nitride.IO/FileSystemOperation.cs @@ -0,0 +1,14 @@ +using Zio; + +namespace Nitride.IO +{ + public abstract class FileSystemOperation + { + protected FileSystemOperation(IFileSystem fileSystem) + { + this.FileSystem = fileSystem; + } + + protected IFileSystem FileSystem { get; } + } +} diff --git a/src/Nitride.IO/Nitride.IO.csproj b/src/Nitride.IO/Nitride.IO.csproj new file mode 100644 index 0000000..e12b0c2 --- /dev/null +++ b/src/Nitride.IO/Nitride.IO.csproj @@ -0,0 +1,37 @@ + + + + net5.0 + enable + Nitride.IO + + + + An extension to Nitride static site generator to read and write files. + + + + + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.IO/NitrideIOBuilderExtensions.cs b/src/Nitride.IO/NitrideIOBuilderExtensions.cs new file mode 100644 index 0000000..bd2310c --- /dev/null +++ b/src/Nitride.IO/NitrideIOBuilderExtensions.cs @@ -0,0 +1,14 @@ +using Autofac; + +namespace Nitride.IO +{ + public static class NitrideIOBuilderExtensions + { + public static NitrideBuilder UseIO(this NitrideBuilder builder) + { + return builder + .ConfigureContainer( + x => x.RegisterModule()); + } + } +} diff --git a/src/Nitride.IO/NitrideIOModule.cs b/src/Nitride.IO/NitrideIOModule.cs new file mode 100644 index 0000000..1c6123e --- /dev/null +++ b/src/Nitride.IO/NitrideIOModule.cs @@ -0,0 +1,6 @@ +namespace Nitride.IO +{ + public class NitrideIOModule : NitrideModuleBase + { + } +} diff --git a/src/Nitride.IO/Paths/AddPathPrefix.cs b/src/Nitride.IO/Paths/AddPathPrefix.cs new file mode 100644 index 0000000..e000486 --- /dev/null +++ b/src/Nitride.IO/Paths/AddPathPrefix.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Gallium; +using Zio; + +namespace Nitride.IO.Paths +{ + [WithProperties] + public partial class AddPathPrefix : INitrideOperation + { + public AddPathPrefix() + { + } + + public AddPathPrefix(UPath pathPrefix) + { + this.PathPrefix = pathPrefix; + } + + /// + /// Gets or sets the prefix for the path operations. + /// + public UPath? PathPrefix { get; set; } + + public IEnumerable Run(IEnumerable input) + { + if (this.PathPrefix == null) + { + throw new InvalidOperationException( + nameof(AddPathPrefix) + + ".Prefix was not set " + + "(via constructor, property, or SetPrefix) before " + + "Run() was called."); + } + + ReplacePaths replacePaths = new ReplacePaths() + .WithReplacement(this.RunReplacement); + + return replacePaths.Run(input); + } + + private UPath RunReplacement(Entity _, UPath path) + { + string innerRelativePath = path.ToString().TrimStart('/'); + return this.PathPrefix!.Value / innerRelativePath; + } + } +} diff --git a/src/Nitride.IO/Paths/ChangePathExtension.cs b/src/Nitride.IO/Paths/ChangePathExtension.cs new file mode 100644 index 0000000..22df27c --- /dev/null +++ b/src/Nitride.IO/Paths/ChangePathExtension.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Gallium; +using Zio; + +namespace Nitride.IO.Paths +{ + /// + /// Changes the extension of the paths given. + /// + [WithProperties] + public partial class ChangePathExtension : INitrideOperation + { + public ChangePathExtension() + { + } + + public ChangePathExtension(string extension) + { + this.Extension = extension; + } + + /// + /// Gets or sets the prefix for the path operations. + /// + public string? Extension { get; set; } + + public IEnumerable Run(IEnumerable input) + { + if (this.Extension == null) + { + throw new InvalidOperationException( + nameof(AddPathPrefix) + + ".Extension was not set " + + "(via constructor, property, or SetExtension) before " + + "Run() was called."); + } + + ReplacePaths replacePaths = new ReplacePaths() + .WithReplacement(this.RunReplacement); + + return replacePaths.Run(input); + } + + private UPath RunReplacement(Entity _, UPath path) + { + return path.ChangeExtension(this.Extension!); + } + } +} diff --git a/src/Nitride.IO/Paths/MoveToIndexPaths.cs b/src/Nitride.IO/Paths/MoveToIndexPaths.cs new file mode 100644 index 0000000..521b172 --- /dev/null +++ b/src/Nitride.IO/Paths/MoveToIndexPaths.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using Gallium; +using Zio; + +namespace Nitride.IO.Paths +{ + /// + /// Moves various files to indexes of a direction with the base filename. + /// + [WithProperties] + public partial class MoveToIndexPaths : INitrideOperation + { + public MoveToIndexPaths() + { + this.CanMoveCallback = DefaultCanMoveCallback; + } + + /// + /// Gets or sets the callback to determine if the file should be moved. + /// This will not be called if the file is already an index. + /// + public Func? CanMoveCallback { get; set; } + + /// + /// Default implement of the operation moves .html, .htm, .md, and + /// .markdown files into their indexes. + /// + /// + /// True if the file should move, otherwise false. + public static bool DefaultCanMoveCallback(UPath path) + { + return path.GetExtensionWithDot() switch + { + ".htm" => true, + ".html" => true, + ".md" => true, + ".markdown" => true, + _ => false, + }; + } + + public IEnumerable Run(IEnumerable input) + { + if (this.CanMoveCallback == null) + { + throw new InvalidOperationException( + nameof(MoveToIndexPaths) + + ".CanMoveCallback was not set " + + "(via constructor, property, or SetCanMoveCallback) before " + + "Run() was called."); + } + + ReplacePaths replacePaths = new ReplacePaths() + .WithReplacement(this.RunReplacement); + + return replacePaths.Run(input); + } + + private UPath RunReplacement(Entity _, UPath path) + { + // See if we are already an index. If that is true, then we don't + // have to move any further. + string? nameWithoutExtension = path.GetNameWithoutExtension(); + + if (nameWithoutExtension is null or "index") + { + return path; + } + + // See if the path should be moved. If it can't, then just stop + // processing. + if (!this.CanMoveCallback!.Invoke(path)) + { + return path; + } + + // Move the file to an index. + UPath parent = path.GetDirectory(); + string? extension = path.GetExtensionWithDot(); + string index = "index" + extension; + + return parent / nameWithoutExtension / index; + } + } +} diff --git a/src/Nitride.IO/Paths/RemovePathPrefix.cs b/src/Nitride.IO/Paths/RemovePathPrefix.cs new file mode 100644 index 0000000..461ef39 --- /dev/null +++ b/src/Nitride.IO/Paths/RemovePathPrefix.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using Gallium; +using Zio; + +namespace Nitride.IO.Paths +{ + /// + /// An operation that removes a path prefix from the input. + /// + [WithProperties] + public partial class RemovePathPrefix : INitrideOperation + { + public RemovePathPrefix() + { + } + + public RemovePathPrefix(UPath pathPrefix) + { + this.PathPrefix = pathPrefix; + } + + /// + /// Gets or sets the prefix for the path operations. + /// + public UPath? PathPrefix { get; set; } + + public IEnumerable Run(IEnumerable input) + { + if (this.PathPrefix == null) + { + throw new InvalidOperationException( + nameof(RemovePathPrefix) + + ".Prefix was not set " + + "(via constructor, property, or SetPrefix) before " + + "Replace() was called."); + } + + ReplacePaths replacePaths = new ReplacePaths() + .WithReplacement(this.RunReplacement); + + return replacePaths.Run(input); + } + + private UPath RunReplacement(Entity _, UPath path) + { + string normalized = path.ToString(); + string prefix = this.PathPrefix.ToString()!; + + if (normalized.StartsWith(prefix)) + { + return (UPath)path.ToString().Substring(prefix.Length); + } + + return path; + } + } +} diff --git a/src/Nitride.IO/Paths/ReplacePaths.cs b/src/Nitride.IO/Paths/ReplacePaths.cs new file mode 100644 index 0000000..52d9d83 --- /dev/null +++ b/src/Nitride.IO/Paths/ReplacePaths.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Gallium; +using Zio; + +namespace Nitride.IO.Paths +{ + /// + /// A pipeline operation that replaces the UPath of the given entity + /// with the results of a lambda output. Entities without a path component + /// are passed on without touching. + /// + [WithProperties] + public partial class ReplacePaths : INitrideOperation + { + public ReplacePaths() + { + } + + public ReplacePaths(Func replacement) + { + this.Replacement = replacement; + } + + /// + /// Gets or sets the replacement callback to alter the paths. + /// + public Func? Replacement { get; set; } + + /// + /// Performs the replacement on the input streams and outputs the + /// resulting entities. Only entities that have had their paths changed + /// will be updated, the others will be passed on as-is. + /// + /// The list of input entities. + /// The output entities. + public IEnumerable Run(IEnumerable input) + { + if (this.Replacement == null) + { + throw new InvalidOperationException( + "ReplacePaths.Replacement was not set " + + "(via constructor, property, or SetReplacement) before " + + "Replace() was called."); + } + + return input + .ForEachEntity( + (entity, oldPath) => + { + UPath newPath = this.Replacement(entity, oldPath); + + return newPath != oldPath + ? entity.Set(newPath) + : entity; + }); + } + } +} diff --git a/src/Nitride.IO/Paths/UPathExtensions.cs b/src/Nitride.IO/Paths/UPathExtensions.cs new file mode 100644 index 0000000..eeafcba --- /dev/null +++ b/src/Nitride.IO/Paths/UPathExtensions.cs @@ -0,0 +1,41 @@ +using Zio; + +namespace Nitride.IO.Paths +{ + /// + /// Extension methods for the UPath class. + /// + public static class UPathExtensions + { + /// + /// Gets the directory path, which excludes the directory at the end + /// of the path. + /// + /// The path to manipulate. + /// A normalized path. + public static string GetDirectoryIndexPath(this UPath path) + { + if (path.GetNameWithoutExtension() == "index") + { + return path.GetDirectory().ToString().TrimEnd('/') + "/"; + } + + return path.ToString(); + } + + public static string GetParentDirectoryIndexPath(this UPath path) + { + UPath indexPath = path.GetDirectoryIndexPath(); + UPath parent = indexPath.GetDirectory(); + + if (parent == null!) + { + parent = "/"; + } + + string parentPath = parent.ToString().TrimEnd('/') + "/"; + + return parentPath; + } + } +} diff --git a/src/Nitride.IO/README.md b/src/Nitride.IO/README.md new file mode 100644 index 0000000..8835ec0 --- /dev/null +++ b/src/Nitride.IO/README.md @@ -0,0 +1,31 @@ +# Nitride.IO + +This assembly contains the primary system for reading and writing from the disk, +along with various processes to manipulate paths. It contains three primary +components: + +- File System I/O +- Path Normalization +- Disk-Based Content + +## File System I/O + +Internally, this assembly uses [Zio](https://github.com/xoofx/zio), an file +system abstraction that also has an in-memory implementation which is ideal for +running unit tests. Zio also provides a way of treating an arbitrary directory +as a root directory so all paths are relative to the "root". + +## Path Normalization + +Zio also provides `UPath`, a normalization class that handles relative and +absolute paths. Entities that are read from the disk, such as with `ReadFiles`, +will have a `UPath` component with the path from the file. This component is +also used to determine the path when writing out the results. + +## Disk-Based Content + +This assembly also extends the `Nitride.Contents.IBinaryContent` and +`Nitride.Contents.ITextContent` to have file system based implementations. These +keep track of the original path and file system regardless of changes made to +the `UPath` component. + diff --git a/src/Nitride.Javascript/InstallYarn.cs b/src/Nitride.Javascript/InstallYarn.cs new file mode 100644 index 0000000..5eb2f57 --- /dev/null +++ b/src/Nitride.Javascript/InstallYarn.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Gallium; +using Serilog; +using Zio; + +namespace Nitride.Javascript +{ + /// + /// Installs Yarn in a given directory if it is missing. If the + /// `node_modules` is already there, this step is skipped unless + /// ForceInstall is set to true. + /// + [WithProperties] + public partial class InstallYarn : INitrideOperation + { + private readonly IFileSystem fileSystem; + + private readonly ILogger logger; + + public InstallYarn(ILogger logger, IFileSystem fileSystem) + { + this.fileSystem = fileSystem; + this.logger = logger.ForContext(); + this.Directory = "/"; + } + + /// + /// Gets or sets the directory that the install should be run from. This + /// is typically the same file as the package.json and the yarn.lock. + /// + public UPath? Directory { get; set; } + + /// + /// Gets or sets a value indicating whether the install should be + /// forced. + /// + public bool ForceInstall { get; set; } + + /// + public IEnumerable Run(IEnumerable input) + { + // Make sure we have a sane value. + if (!this.Directory.HasValue) + { + throw new InvalidOperationException( + nameof(InstallYarn) + + ".Directory was not set before Run() was called."); + } + + // Make sure the directory exists in case we are the first. + UPath directory = this.Directory.Value; + + if (!this.fileSystem.DirectoryExists(directory)) + { + this.logger.Information("Creating directory {Path}", directory); + this.fileSystem.CreateDirectory(directory); + } + + // Check to see if the directory exists. + UPath modulesPath = directory / "node_modules"; + bool exists = this.fileSystem.DirectoryExists(modulesPath); + + if (exists) + { + if (!this.ForceInstall) + { + this.logger.Debug( + "{Path} already exists, skipping", + modulesPath); + return input; + } + + this.logger.Information( + "{Path} already exists, forcing installation", + modulesPath); + this.fileSystem.DeleteDirectory(modulesPath, true); + } + + // Run Yarn install on the directory. Sadly, Yarn doesn't understand + // a C# abstraction layer, so we need the "real" path to work with + // these operations. + string realPath = this.fileSystem + .ConvertPathToInternal(directory); + + // Run the install. + string command = YarnHelper.GetYarnCommand(); + var start = new ProcessStartInfo + { + FileName = command, + Arguments = "install", + WorkingDirectory = realPath, + RedirectStandardOutput = true, + }; + Process process = Process.Start(start); + + if (process == null) + { + throw new InvalidOperationException( + "Cannot start yarn install"); + } + + process.WaitForExit(); + + // We are done, so just pass our input on. + return input; + } + } +} diff --git a/src/Nitride.Javascript/Nitride.Javascript.csproj b/src/Nitride.Javascript/Nitride.Javascript.csproj new file mode 100644 index 0000000..fbbc107 --- /dev/null +++ b/src/Nitride.Javascript/Nitride.Javascript.csproj @@ -0,0 +1,33 @@ + + + + net5.0 + + + + An extension to Nitride static site generator to generate Webpack output. + + + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.Javascript/NitrideJavascriptBuilderExtensions.cs b/src/Nitride.Javascript/NitrideJavascriptBuilderExtensions.cs new file mode 100644 index 0000000..f1f37a9 --- /dev/null +++ b/src/Nitride.Javascript/NitrideJavascriptBuilderExtensions.cs @@ -0,0 +1,14 @@ +using Autofac; + +namespace Nitride.Javascript +{ + public static class NitrideJavascriptBuilderExtensions + { + public static NitrideBuilder UseJavascript(this NitrideBuilder builder) + { + return builder + .ConfigureContainer( + x => x.RegisterModule()); + } + } +} diff --git a/src/Nitride.Javascript/NitrideJavascriptModule.cs b/src/Nitride.Javascript/NitrideJavascriptModule.cs new file mode 100644 index 0000000..933a677 --- /dev/null +++ b/src/Nitride.Javascript/NitrideJavascriptModule.cs @@ -0,0 +1,6 @@ +namespace Nitride.Javascript +{ + public class NitrideJavascriptModule : NitrideModuleBase + { + } +} diff --git a/src/Nitride.Javascript/RunWebpack.cs b/src/Nitride.Javascript/RunWebpack.cs new file mode 100644 index 0000000..fc5c9be --- /dev/null +++ b/src/Nitride.Javascript/RunWebpack.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Gallium; +using Nitride.IO.Contents; +using Nitride.IO.Paths; +using Serilog; +using Zio; + +namespace Nitride.Javascript +{ + /// + /// Runs `webpack` in the directory, writing out whatever files need to be + /// written. + /// + [WithProperties] + public partial class RunWebpack : INitrideOperation + { + private readonly IFileSystem fileSystem; + + private readonly ILogger logger; + + private readonly ReadFiles readFiles; + + public RunWebpack( + ILogger logger, + IFileSystem fileSystem, + ReadFiles readFiles) + { + this.fileSystem = fileSystem; + this.readFiles = readFiles; + this.logger = logger.ForContext(); + this.WebpackDirectory = "/"; + } + + /// + /// Gets or sets the directory that contains the output from the + /// webpack execution. + /// + public UPath? OutputDirectory { get; set; } + + /// + /// Gets or sets the directory that the install should be run from. This + /// is typically the same file as the webpack.config.js. + /// + public UPath? WebpackDirectory { get; set; } + + /// + public IEnumerable Run(IEnumerable input) + { + // Make sure we have a sane values. + if (!this.WebpackDirectory.HasValue) + { + throw new InvalidOperationException( + nameof(InstallYarn) + + ".WebpackDirectory was not set before Run() was called."); + } + + if (!this.OutputDirectory.HasValue) + { + throw new InvalidOperationException( + nameof(InstallYarn) + + ".OutputDirectory was not set before Run() was called."); + } + + // Make sure the directory exists in case we are the first. + UPath directory = this.WebpackDirectory.Value; + + if (!this.fileSystem.DirectoryExists(directory)) + { + this.logger.Information("Creating directory {Path}", directory); + this.fileSystem.CreateDirectory(directory); + } + + // Sadly, Yarn doesn't understand virtual file systems, so we need + // the "real" path to the directory for this. + string realPath = this.fileSystem + .ConvertPathToInternal(directory); + + // Run the install. + this.logger.Debug("Running Webpack via Yarn"); + + string command = YarnHelper.GetYarnCommand(); + var start = new ProcessStartInfo + { + FileName = command, + Arguments = "run webpack", + WorkingDirectory = realPath, + RedirectStandardOutput = true, + }; + Process process = Process.Start(start); + + if (process == null) + { + throw new InvalidOperationException( + "Cannot start yarn run webpack"); + } + + process.WaitForExit(); + + // We are done and all the output will be written into the + // filesystem, so merge it with our input. + this.logger.Debug("Adding Webpack output to the pipeline"); + + UPath outputDirectory = this.OutputDirectory.Value; + + return input + .Union( + this.readFiles + .Read(outputDirectory) + .Run(new RemovePathPrefix(outputDirectory))); + } + } +} diff --git a/src/Nitride.Javascript/YarnHelper.cs b/src/Nitride.Javascript/YarnHelper.cs new file mode 100644 index 0000000..09a3883 --- /dev/null +++ b/src/Nitride.Javascript/YarnHelper.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; + +namespace Nitride.Javascript +{ + /// + /// A helper class for finding how to run or install Yarn. + /// + public static class YarnHelper + { + /// + /// Gets the name of the command to run Yarn. + /// + /// The command to run. + public static string GetYarnCommand() + { + // Figure out how to run Yarn. This is needed because Windows can't + // run the script like the shell can. + string command = "yarn"; + string appData = Path.Combine( + Environment.GetFolderPath( + Environment.SpecialFolder.ApplicationData), + "npm", + "yarn.cmd"); + + if (File.Exists(appData)) + { + command = appData; + } + + return command; + } + } +} diff --git a/src/Nitride.Markdown/IdentifyMarkdown.cs b/src/Nitride.Markdown/IdentifyMarkdown.cs new file mode 100644 index 0000000..06150c6 --- /dev/null +++ b/src/Nitride.Markdown/IdentifyMarkdown.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using Gallium; +using Nitride.Contents; +using Zio; + +namespace Nitride.Markdown +{ + /// + /// An operation that identifies Markdown files by their common extensions + /// and converts them to text input while also adding the IsMarkdown + /// component to identify them. + /// + [WithProperties] + public partial class IdentifyMarkdown : INitrideOperation + { + public IdentifyMarkdown() + { + this.IsMarkdownTest = DefaultIsMarkdown; + } + + public Func IsMarkdownTest { get; set; } + + /// + public IEnumerable Run(IEnumerable input) + { + return input + .ForEachEntity( + (entity, path, _) => + { + // If we aren't a Markdown file, then there is nothing + // we can do about that. + if (!this.IsMarkdownTest(entity, path)) + { + return entity; + } + + // We are already text, so just mark it as Markdown. + entity = entity + .Set(IsMarkdown.Instance); + + return entity; + }) + .ForEachEntity( + (entity, path, binary) => + { + // If we aren't a Markdown file, then there is nothing + // we can do about that. + if (!this.IsMarkdownTest(entity, path)) + { + return entity; + } + + // Convert the file as a binary. + if (binary is ITextContentConvertable textConvertable) + { + entity = entity + .SetTextContent(textConvertable.ToTextContent()) + .Set(IsMarkdown.Instance); + } + else + { + throw new InvalidOperationException( + "Cannot convert a binary content to a " + + "text without ITextContentConvertable."); + } + + return entity; + }); + } + + private static bool DefaultIsMarkdown(Entity entity, UPath path) + { + return (path.GetExtensionWithDot() ?? string.Empty) + .ToLowerInvariant() switch + { + ".md" => true, + ".markdown" => true, + _ => false, + }; + } + } +} diff --git a/src/Nitride.Markdown/IsMarkdown.cs b/src/Nitride.Markdown/IsMarkdown.cs new file mode 100644 index 0000000..f714e2d --- /dev/null +++ b/src/Nitride.Markdown/IsMarkdown.cs @@ -0,0 +1,10 @@ +namespace Nitride.Markdown +{ + /// + /// A marker class that indicates that the file is a Markdown file. + /// + public class IsMarkdown + { + public static IsMarkdown Instance { get; } = new(); + } +} diff --git a/src/Nitride.Markdown/MarkdownOperationBase.cs b/src/Nitride.Markdown/MarkdownOperationBase.cs new file mode 100644 index 0000000..b28319e --- /dev/null +++ b/src/Nitride.Markdown/MarkdownOperationBase.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Gallium; +using Markdig; +using Nitride.Contents; + +namespace Nitride.Markdown +{ + public abstract class MarkdownOperationBase : INitrideOperation + { + /// + /// Gets or sets an additional callback to configure additional features + /// from the baseline Markdown. + /// + public Action? ConfigureMarkdown { get; set; } + + /// + public IEnumerable Run(IEnumerable input) + { + // Create the Markdown pipeline used for formatting. + var builder = new MarkdownPipelineBuilder(); + + this.ConfigureMarkdown?.Invoke(builder); + + MarkdownPipeline options = builder.Build(); + + // Process the Markdown files (while passing everything on). + return input + .ForEachEntity( + (entity, _, content) => this.Convert( + entity, + content, + options)); + } + + /// + /// Converts the Markdown file into HTML. + /// + /// The entity to convert. + /// The content for this entity. + /// The markdown pipeline. + /// A converted entity. + protected abstract Entity Convert( + Entity entity, + ITextContent markdownContent, + MarkdownPipeline options); + } +} diff --git a/src/Nitride.Markdown/MarkdownToGemtext.cs b/src/Nitride.Markdown/MarkdownToGemtext.cs new file mode 100644 index 0000000..1476282 --- /dev/null +++ b/src/Nitride.Markdown/MarkdownToGemtext.cs @@ -0,0 +1,40 @@ +using Gallium; +using Markdig; +using MfGames.Markdown.Gemtext; +using Nitride.Contents; +using Nitride.Gemtext; + +namespace Nitride.Markdown +{ + /// + /// Converts the input Markdown files into Gemtext using Markdig and + /// MfGames.Markdown.Gemtext. This only processes files with a text input + /// and the IsMarkdown component. + /// + public class MarkdownToGemtext : MarkdownOperationBase + { + /// + /// Converts the Markdown file into HTML. + /// + /// The entity to convert. + /// The content for this entity. + /// The markdown pipeline. + /// A converted entity. + protected override Entity Convert( + Entity entity, + ITextContent markdownContent, + MarkdownPipeline options) + { + string markdown = markdownContent.GetText(); + string gemtext = MarkdownGemtext.ToGemtext(markdown, options); + var content = new StringTextContent(gemtext); + + entity = entity + .SetTextContent(content) + .Remove() + .Set(IsGemtext.Instance); + + return entity; + } + } +} diff --git a/src/Nitride.Markdown/MarkdownToHtml.cs b/src/Nitride.Markdown/MarkdownToHtml.cs new file mode 100644 index 0000000..70dd66d --- /dev/null +++ b/src/Nitride.Markdown/MarkdownToHtml.cs @@ -0,0 +1,40 @@ +using Gallium; +using Markdig; +using Nitride.Contents; +using Nitride.Html; + +namespace Nitride.Markdown +{ + /// + /// Converts the input Markdown files into HTML using Markdig. This only + /// processes files with a text input and the IsMarkdown component. + /// + public class MarkdownToHtml : MarkdownOperationBase + { + /// + /// Converts the Markdown file into HTML. + /// + /// The entity to convert. + /// The content for this entity. + /// The markdown pipeline. + /// A converted entity. + protected override Entity Convert( + Entity entity, + ITextContent markdownContent, + MarkdownPipeline options) + { + // Convert the entity to Html. + string markdown = markdownContent.GetText(); + string html = Markdig.Markdown.ToHtml(markdown, options); + var htmlContent = new StringTextContent(html); + + entity = entity + .SetTextContent(htmlContent) + .Remove() + .Set(IsHtml.Instance); + + // Return the resulting entity. + return entity; + } + } +} diff --git a/src/Nitride.Markdown/MarkdownToOperationBaseExtension.cs b/src/Nitride.Markdown/MarkdownToOperationBaseExtension.cs new file mode 100644 index 0000000..ae74163 --- /dev/null +++ b/src/Nitride.Markdown/MarkdownToOperationBaseExtension.cs @@ -0,0 +1,22 @@ +using System; +using Markdig; + +namespace Nitride.Markdown +{ + /// + /// Extension methods to handle generics while configuring a Markdown + /// operation. + /// + public static class MarkdownToOperationBaseExtension + { + public static T WithConfigureMarkdown( + this T operation, + Action? callback) + where T : MarkdownOperationBase + + { + operation.ConfigureMarkdown = callback; + return operation; + } + } +} diff --git a/src/Nitride.Markdown/Nitride.Markdown.csproj b/src/Nitride.Markdown/Nitride.Markdown.csproj new file mode 100644 index 0000000..a3d397a --- /dev/null +++ b/src/Nitride.Markdown/Nitride.Markdown.csproj @@ -0,0 +1,37 @@ + + + + net5.0 + enable + + + + An extension to Nitride static site generator to render Markdown content. + + + + + + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.Markdown/NitrideMarkdownBuilderExtensions.cs b/src/Nitride.Markdown/NitrideMarkdownBuilderExtensions.cs new file mode 100644 index 0000000..e4e18fe --- /dev/null +++ b/src/Nitride.Markdown/NitrideMarkdownBuilderExtensions.cs @@ -0,0 +1,14 @@ +using Autofac; + +namespace Nitride.Markdown +{ + public static class NitrideMarkdownBuilderExtensions + { + public static NitrideBuilder UseMarkdown(this NitrideBuilder builder) + { + return builder + .ConfigureContainer( + x => x.RegisterModule()); + } + } +} diff --git a/src/Nitride.Markdown/NitrideMarkdownModule.cs b/src/Nitride.Markdown/NitrideMarkdownModule.cs new file mode 100644 index 0000000..fc0e8ff --- /dev/null +++ b/src/Nitride.Markdown/NitrideMarkdownModule.cs @@ -0,0 +1,6 @@ +namespace Nitride.Markdown +{ + public class NitrideMarkdownModule : NitrideModuleBase + { + } +} diff --git a/src/Nitride.Slugs/ISlugProvider.cs b/src/Nitride.Slugs/ISlugProvider.cs new file mode 100644 index 0000000..86b8c76 --- /dev/null +++ b/src/Nitride.Slugs/ISlugProvider.cs @@ -0,0 +1,15 @@ +namespace Nitride.Slugs +{ + /// + /// An interface that provides slugs for various paths. + /// + public interface ISlugProvider + { + /// + /// Converts the given input into a slug. + /// + /// The input string to normalize. + /// The resulting slug. + string ToSlug(string input); + } +} diff --git a/src/Nitride.Slugs/Nitride.Slugs.csproj b/src/Nitride.Slugs/Nitride.Slugs.csproj new file mode 100644 index 0000000..ced4fca --- /dev/null +++ b/src/Nitride.Slugs/Nitride.Slugs.csproj @@ -0,0 +1,31 @@ + + + + net5.0 + + + + An extension to Nitride static site generator to generate slugs. + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.Slugs/NitrideSlugsBuilderExtensions.cs b/src/Nitride.Slugs/NitrideSlugsBuilderExtensions.cs new file mode 100644 index 0000000..55d5907 --- /dev/null +++ b/src/Nitride.Slugs/NitrideSlugsBuilderExtensions.cs @@ -0,0 +1,28 @@ +using System; +using Autofac; + +namespace Nitride.Slugs +{ + public static class NitrideSlugsBuilderExtensions + { + public static NitrideBuilder UseSlugs( + this NitrideBuilder builder, + ISlugProvider slugs) + { + if (slugs == null) + { + throw new ArgumentNullException(nameof(slugs)); + } + + return builder + .ConfigureContainer( + x => + { + x.RegisterInstance(slugs) + .As() + .SingleInstance(); + x.RegisterModule(); + }); + } + } +} diff --git a/src/Nitride.Slugs/NitrideSlugsModule.cs b/src/Nitride.Slugs/NitrideSlugsModule.cs new file mode 100644 index 0000000..255c2b9 --- /dev/null +++ b/src/Nitride.Slugs/NitrideSlugsModule.cs @@ -0,0 +1,8 @@ +using Autofac; + +namespace Nitride.Slugs +{ + public class NitrideSlugsModule : Module + { + } +} diff --git a/src/Nitride.Slugs/SimpleSlugProvider.cs b/src/Nitride.Slugs/SimpleSlugProvider.cs new file mode 100644 index 0000000..9685d7c --- /dev/null +++ b/src/Nitride.Slugs/SimpleSlugProvider.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Slugify; + +namespace Nitride.Slugs +{ + /// + /// A default implementation of ISlugProvider. + /// + public class SimpleSlugProvider : ISlugProvider, IEnumerable + { + private readonly List<(string, string)> replacements; + + public SimpleSlugProvider() + { + this.replacements = new List<(string, string)>(); + } + + public SimpleSlugProvider(IDictionary replacements) + : this() + { + foreach (KeyValuePair pair in replacements) + { + this.Add(pair.Key, pair.Value); + } + } + + /// + /// Adds a replacement for the resulting slug. + /// + /// The text to search for. + /// The replacement string. + public void Add(string search, string replace) + { + this.replacements.Add((search, replace)); + } + + /// + public IEnumerator GetEnumerator() + { + return this.replacements + .Select(x => x.Item1) + .GetEnumerator(); + } + + /// + public virtual string ToSlug(string input) + { + // If we have null or whitespace, we have a problem. + if (string.IsNullOrWhiteSpace(input)) + { + throw new ArgumentException( + "Cannot have a blank or null input", + nameof(input)); + } + + // Create a slug.. + var helper = new SlugHelper(); + string output = helper.GenerateSlug(input); + + // Perform any additional replacements. + foreach ((string search, string replace) in this.replacements) + { + output = output.Replace(search, replace); + } + + return output; + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + } +} diff --git a/src/Nitride.Slugs/UnicodeNormalizingSlugProvider.cs b/src/Nitride.Slugs/UnicodeNormalizingSlugProvider.cs new file mode 100644 index 0000000..2b7451b --- /dev/null +++ b/src/Nitride.Slugs/UnicodeNormalizingSlugProvider.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace Nitride.Slugs +{ + /// + /// Extends the slug provider to strip out accented characters for + /// a normalized form. + /// + public class UnicodeNormalizingSlugProvider : SimpleSlugProvider + { + /// + public UnicodeNormalizingSlugProvider() + { + } + + /// + public UnicodeNormalizingSlugProvider( + IDictionary replacements) + : base(replacements) + { + } + + /// + public override string ToSlug(string input) + { + // If we have null or whitespace, we have a problem. + if (string.IsNullOrWhiteSpace(input)) + { + throw new ArgumentException( + "Cannot have a blank or null input", + nameof(input)); + } + + // Normalize the Unicode objects. + // Strip out the accents. This is a cheesy way of doing so. + char[] chars = input + .Normalize(NormalizationForm.FormD) + .Where(this.IsNonSpacingMark) + .ToArray(); + string normalized = new string(chars) + .Normalize(NormalizationForm.FormC); + + // Return the base implementation. + return base.ToSlug(normalized); + } + + private bool IsNonSpacingMark(char c) + { + UnicodeCategory category = CharUnicodeInfo.GetUnicodeCategory(c); + + return category != UnicodeCategory.NonSpacingMark; + } + } +} diff --git a/src/Nitride.Temporal/CanExpire.cs b/src/Nitride.Temporal/CanExpire.cs new file mode 100644 index 0000000..cd15869 --- /dev/null +++ b/src/Nitride.Temporal/CanExpire.cs @@ -0,0 +1,10 @@ +namespace Nitride.Temporal +{ + /// + /// A marker component for identifying a post that can expire. + /// + public class CanExpire + { + public static CanExpire Instance { get; } = new(); + } +} diff --git a/src/Nitride.Temporal/DatePipelineCommandOption.cs b/src/Nitride.Temporal/DatePipelineCommandOption.cs new file mode 100644 index 0000000..325f274 --- /dev/null +++ b/src/Nitride.Temporal/DatePipelineCommandOption.cs @@ -0,0 +1,69 @@ +using System; +using System.CommandLine; +using System.CommandLine.Invocation; +using System.Globalization; +using Nitride.Commands; +using Nitride.Registration; +using NodaTime; +using NodaTime.Testing; +using Serilog; + +namespace Nitride.Temporal +{ + /// + /// A factory to inject the "--date=XXXX-XX-XX" argument into the build + /// and other pipeline commands. + /// + [NoRegistration] + public class DatePipelineCommandOption : IPipelineCommandOption + { + private readonly NitrideClock clock; + + private readonly ILogger logger; + + public DatePipelineCommandOption( + ILogger logger, + NitrideClock clock) + { + this.logger = logger.ForContext(); + this.clock = clock; + this.Option = new Option("--date") + { + Description = "Sets the date to something other than now", + ArgumentHelpName = "DATE", + }; + } + + /// + public Option Option { get; } + + /// + public void Handle(InvocationContext context) + { + // If we got a date, then use NodaTime's fake clock to set it so + // everything will use that. + var value = (DateTime?)context.ParseResult + .ValueForOption(this.Option); + + if (value.HasValue && value.Value != DateTime.MinValue) + { + // We have a date, so we need to create a fake clock that has this + // date for the entire run. + Instant instant = this.clock.CreateInstant(value.Value); + + this.clock.Clock = new FakeClock(instant); + } + + // Report the date we are processing. + Instant now = this.clock.Clock.GetCurrentInstant(); + ZonedDateTime dateTime = now.InZone(this.clock.DateTimeZone); + string formatted = dateTime.ToString( + "yyyy-MM-dd HH:mm:ss x", + CultureInfo.CurrentCulture); + + this.logger.Information( + "Setting date/time to {When:l}", + formatted); + } + } +} diff --git a/src/Nitride.Temporal/ExpiresPipelineCommandOption.cs b/src/Nitride.Temporal/ExpiresPipelineCommandOption.cs new file mode 100644 index 0000000..4b283b9 --- /dev/null +++ b/src/Nitride.Temporal/ExpiresPipelineCommandOption.cs @@ -0,0 +1,75 @@ +using System.CommandLine; +using System.CommandLine.Invocation; +using System.Globalization; +using Nitride.Commands; +using Nitride.Registration; +using NodaTime; +using Serilog; +using TimeSpanParserUtil; + +namespace Nitride.Temporal +{ + /// + /// A factory to inject the "--expires=XXXX" argument into the build + /// and other pipeline commands. + /// + [NoRegistration] + public class ExpiresPipelineCommandOption : IPipelineCommandOption + { + private readonly NitrideClock clock; + + private readonly ILogger logger; + + public ExpiresPipelineCommandOption( + ILogger logger, + NitrideClock clock, + string? defaultValue = null) + { + this.logger = logger.ForContext(); + this.clock = clock; + this.Option = new Option("--expires", () => defaultValue) + { + Description = + "Sets the expiration time as time before the current date", + ArgumentHelpName = "TIMESPAN", + }; + } + + /// + public Option Option { get; } + + /// + public void Handle(InvocationContext context) + { + // If we have a format, then we are going to set one. If the format + // is blank or never, then we are going to treat it as not + // expiring anything. + string? value = (string?)context.ParseResult + .ValueForOption(this.Option); + + if (value != null && value.ToLowerInvariant() != "never") + { + // Parse the format using TimeSpanParser. + this.clock.Expires = TimeSpanParser.Parse(value); + } + + // If we don't have anything, then just report and we're done. + if (this.clock.Expiration == null) + { + this.logger.Information("No entities will be expired"); + return; + } + + // Figure out when we are going to be expiring. + Instant when = this.clock.Expiration.Value; + ZonedDateTime dateTime = when.InZone(this.clock.DateTimeZone); + string formatted = dateTime.ToString( + "yyyy-MM-dd HH:mm:ss x", + CultureInfo.CurrentCulture); + + this.logger.Information( + "Expiring entries before {When:l}", + formatted); + } + } +} diff --git a/src/Nitride.Temporal/FilterOutExpiredInstants.cs b/src/Nitride.Temporal/FilterOutExpiredInstants.cs new file mode 100644 index 0000000..d3452b3 --- /dev/null +++ b/src/Nitride.Temporal/FilterOutExpiredInstants.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.Linq; +using Gallium; +using NodaTime; + +namespace Nitride.Temporal +{ + /// + /// Filters out all expired entities that are before the expiration. + /// + public class FilterOutExpiredInstants : NitrideOperationBase + { + private readonly NitrideClock clock; + + public FilterOutExpiredInstants(NitrideClock clock) + { + this.clock = clock; + } + + /// + public override IEnumerable Run(IEnumerable input) + { + if (!this.clock.Expiration.HasValue) + { + return input; + } + + return input + .OrderBy(x => x.Get()) + .ForEntities( + x => x + .Where(this.IsNotExpired)); + } + + private bool IsNotExpired(Entity entity) + { + var instant = entity.Get(); + Instant expiration = this.clock.Expiration!.Value; + bool isExpired = instant.CompareTo(expiration) < 0; + + return !isExpired; + } + } +} diff --git a/src/Nitride.Temporal/FilterOutFutureInstants.cs b/src/Nitride.Temporal/FilterOutFutureInstants.cs new file mode 100644 index 0000000..e672cae --- /dev/null +++ b/src/Nitride.Temporal/FilterOutFutureInstants.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Gallium; +using NodaTime; + +namespace Nitride.Temporal +{ + /// + /// Filters out all entities that have an instant before the current + /// NitrideClock time. + /// + public class FilterOutFutureInstants : NitrideOperationBase + { + private readonly NitrideClock clock; + + public FilterOutFutureInstants(NitrideClock clock) + { + this.clock = clock; + } + + /// + public override IEnumerable Run(IEnumerable input) + { + Instant now = this.clock.Clock.GetCurrentInstant(); + + return input + .WhereEntities( + (_, instant) => instant.CompareTo(now) <= 0); + } + } +} diff --git a/src/Nitride.Temporal/Nitride.Temporal.csproj b/src/Nitride.Temporal/Nitride.Temporal.csproj new file mode 100644 index 0000000..5fd6c9d --- /dev/null +++ b/src/Nitride.Temporal/Nitride.Temporal.csproj @@ -0,0 +1,40 @@ + + + + net5.0 + enable + Nitride.Temporal + + + + An extension to Nitride static site generator to add time-based components and filters. + + + + + + + + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.Temporal/NitrideClock.cs b/src/Nitride.Temporal/NitrideClock.cs new file mode 100644 index 0000000..77d929d --- /dev/null +++ b/src/Nitride.Temporal/NitrideClock.cs @@ -0,0 +1,144 @@ +using System; +using Nitride.Registration; +using NodaTime; +using NodaTime.Testing; + +namespace Nitride.Temporal +{ + /// + /// A class that handles date and time processing. This provides identifying + /// the desire time zone along with various methods for processing parsed + /// DateTime objects into NodaTime.Instant. + /// + [Singleton] + public class NitrideClock + { + public NitrideClock() + { + // We use FakeClock because we don't want time to advance in the + // middle of running, just in case we are just a few seconds before + // rollover. + Instant instant = SystemClock.Instance.GetCurrentInstant(); + + this.DateTimeZone = DateTimeZoneProviders.Bcl.GetSystemDefault(); + this.Clock = new FakeClock(instant); + } + + /// + /// Gets or sets the clock used to perform time calculations. + /// + public IClock Clock { get; set; } + + /// + /// Gets or sets the date time zone used for processing. + /// + public DateTimeZone DateTimeZone { get; set; } + + /// + /// Gets the instant when the files expire. + /// + public Instant? Expiration => this.Expires.HasValue + ? this.Clock.GetCurrentInstant() + .Minus(Duration.FromTimeSpan(this.Expires.Value)) + : null; + + /// + /// Gets or sets the expiration time span, which is calculated from the + /// current time. + /// + public TimeSpan? Expires { get; set; } + + /// + /// Creates an instant from a given year, month, and day. + /// + /// The numerical year. + /// The numerical month. + /// The numerical day of month. + /// An instant in the clock's time zone. + public Instant CreateInstant(int year, int month, int day) + { + var date = new LocalDate(year, month, day); + + return this.CreateInstant(date); + } + + /// + /// Creates an instant from the given local date. + /// + /// The date to parse. + /// An instant in the clock's time zone. + public Instant CreateInstant(LocalDate date) + { + ZonedDateTime zoned = date.AtStartOfDayInZone(this.DateTimeZone); + var instant = zoned.ToInstant(); + + return instant; + } + + /// + /// Creates an instant from the given date time zone. + /// + /// The object to convert. + /// An instant representing this DateTimeOffset. + public Instant CreateInstant(DateTimeOffset when) + { + OffsetDateTime offset = OffsetDateTime.FromDateTimeOffset(when); + + return offset.ToInstant(); + } + + /// + /// Creates an instant from the given date time. + /// + /// The object to convert. + /// An instant representing this DateTimeOffset. + public Instant CreateInstant(DateTime when) + { + if (when.Kind == DateTimeKind.Unspecified) + { + LocalDate localDate = LocalDate.FromDateTime(when); + + return this.CreateInstant(localDate); + } + + var offset = new DateTimeOffset(when); + + return this.CreateInstant(offset); + } + + /// + /// Converts an instant into a DateTime for the clock's time zone. + /// + /// The instant to convert. + /// A DateTime in the correct date and time. + public DateTime ToDateTime(Instant instant) + { + return instant + .InZone(this.DateTimeZone) + .ToDateTimeOffset() + .DateTime; + } + + /// + /// Sets the clock used for time calculations. + /// + /// The new clock to use. + /// The instance for chaining methods. + public NitrideClock WithClock(IClock clock) + { + this.Clock = clock; + return this; + } + + /// + /// Sets the date time zone and returns itself for chaining. + /// + /// The name of the time zone. + /// The instance for chaining methods. + public NitrideClock WithDateTimeZone(string timeZoneName) + { + this.DateTimeZone = DateTimeZoneProviders.Tzdb[timeZoneName]; + return this; + } + } +} diff --git a/src/Nitride.Temporal/NitrideTemporalBuilderExtensions.cs b/src/Nitride.Temporal/NitrideTemporalBuilderExtensions.cs new file mode 100644 index 0000000..08e4fd6 --- /dev/null +++ b/src/Nitride.Temporal/NitrideTemporalBuilderExtensions.cs @@ -0,0 +1,105 @@ +using System; +using Autofac; +using Nitride.Commands; +using Serilog; +using Expires = Nitride.Temporal.ExpiresPipelineCommandOption; + +namespace Nitride.Temporal +{ + public static class NitrideTemporalBuilderExtensions + { + /// + /// Extends the builder to allow for configuring the temporal + /// settings for generation. + /// + /// The host builder being configured. + /// The callback to configure the clock. + /// The builder passed in. + public static NitrideBuilder ConfigureClock( + this NitrideBuilder builder, + Action callback) + { + return builder + .UseTemporal() + .ConfigureSite( + (_, scope) => + { + var clock = scope.Resolve(); + callback(clock); + }); + } + + public static NitrideBuilder UseTemporal(this NitrideBuilder builder) + { + return builder + .ConfigureContainer( + x => x.RegisterModule()); + } + + /// + /// Adds the "--date=XXXX-XX-XX" option into the pipeline commands. + /// + /// The host builder being configured. + /// The builder passed in. + public static NitrideBuilder WithClockFromOptions( + this NitrideBuilder builder) + { + return builder + .UseTemporal() + .ConfigureContainer( + x => + { + x + .RegisterType() + .As(); + }); + } + + /// + /// Adds the "--expire=XXXX" option into the pipeline commands where + /// "XXX" is a format like "5y" or "500000:00:00.0". This is parsed by + /// TimeSpanParser which gives an easy format. + /// + /// The host builder being configured. + /// The default expiration, if one is provided. + /// The builder passed in. + public static NitrideBuilder WithExpiresFromOptions( + this NitrideBuilder builder, + TimeSpan defaultValue) + { + return WithExpiresFromOptions(builder, defaultValue.ToString()); + } + + /// + /// Adds the "--expire=XXXX" option into the pipeline commands where + /// "XXX" is a format like "5y" or "500000:00:00.0". This is parsed by + /// TimeSpanParser which gives an easy format. + /// + /// The host builder being configured. + /// The default expiration, if one is provided. + /// The builder passed in. + public static NitrideBuilder WithExpiresFromOptions( + this NitrideBuilder builder, + string? defaultValue = null) + { + return builder + .ConfigureContainer( + x => + { + x + .Register( + context => + { + var logger = context.Resolve(); + var clock = context.Resolve(); + + return new Expires( + logger, + clock, + defaultValue); + }) + .As(); + }); + } + } +} diff --git a/src/Nitride.Temporal/NitrideTemporalModule.cs b/src/Nitride.Temporal/NitrideTemporalModule.cs new file mode 100644 index 0000000..0443875 --- /dev/null +++ b/src/Nitride.Temporal/NitrideTemporalModule.cs @@ -0,0 +1,15 @@ +using Autofac; + +namespace Nitride.Temporal +{ + public class NitrideTemporalModule : NitrideModuleBase + { + /// + protected override void Register(ContainerBuilder builder) + { + builder + .RegisterGeneric(typeof(SetInstantFromComponent<>)) + .As(typeof(SetInstantFromComponent<>)); + } + } +} diff --git a/src/Nitride.Temporal/README.md b/src/Nitride.Temporal/README.md new file mode 100644 index 0000000..67eb6d7 --- /dev/null +++ b/src/Nitride.Temporal/README.md @@ -0,0 +1,42 @@ +# Date Processing + +One of the common features of static websites are blogs which leads to having +some form of date-centric processing of pages to build archive pages, calendars, +and being able to write posts in the future. + +With the component system, the date of a given file is simply attached to +`Nodatime.Instant` component of the `Entity` object for the bulk of the +processing. + +## Supporting Time Zones + +The concept of time zones while date processing is one that is frequently +overlooked. A date is a date, right? However, most blogs and news sites have a +concept of when a new day starts but it isn't always the same time as the server +that is building the site. While a blog might be in America/Chicago time, a CI +server could be set to UTC (such as Azure build servers) and the +"day" may roll over fix or six hours before or after the blog's time. + +This is why Nitride uses `Instant` for when pages are implemented. These are +points in time that are independent of time zones, but we also provide tools for +converting a date model or one from the path into a proper instant based on the +blog's time zone. + +## Why NodaTime? + +We decided to use [NodaTime](https://nodatime.org/) instead of the built-in date +time functions for a number of reasons, mainly because it has a more intuitive +way of handling time zones + +## Configuring + +There are two callbacks on `NitrideBuilder` that can be used to define the date +and time processing for the blog. + +```csharp +NitrideBuilder builder; + +builder + .ConfigureDates((NitrideClock clock) => clock.SetTimeZone()) +``` + diff --git a/src/Nitride.Temporal/SetInstantFromComponent.cs b/src/Nitride.Temporal/SetInstantFromComponent.cs new file mode 100644 index 0000000..c9848d1 --- /dev/null +++ b/src/Nitride.Temporal/SetInstantFromComponent.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using Gallium; +using NodaTime; + +namespace Nitride.Temporal +{ + /// + /// Sets the instant from another component. This has methods for handling + /// nullable properties inside the component. + /// + public class SetInstantFromComponent : NitrideOperationBase + { + private readonly NitrideClock clock; + + public SetInstantFromComponent(NitrideClock clock) + { + this.clock = clock; + } + + /// + /// The callback used to get a date time object which is converted into + /// an Instant automatically. This can handle DateTime, DateTimeOffset, + /// LocalDate, and Instant. Nulls are skipped. + /// + public Func? GetDateTimeObject + { + get; + set; + } + + /// + public override IEnumerable Run(IEnumerable input) + { + this.CheckNotNull( + nameof(this.GetDateTimeObject), + this.GetDateTimeObject); + + return input + .ForEachEntity(this.Set); + } + + /// + /// Sets the callback used to get a date time object which is converted + /// into an Instant automatically. This can handle DateTime, + /// DateTimeOffset, LocalDate, and Instant. Nulls are skipped. + /// + public SetInstantFromComponent WithGetDateTimeObject( + Func? callback) + { + this.GetDateTimeObject = callback; + return this; + } + + private Entity Set(Entity entity, TComponent component) + { + object? temporal = this.GetDateTimeObject!(entity, component); + Instant instant; + + switch (temporal) + { + case null: + return entity; + case Instant direct: + instant = direct; + break; + case LocalDate other: + instant = this.clock.CreateInstant(other); + break; + case DateTime other: + instant = this.clock.CreateInstant(other); + break; + case DateTimeOffset other: + instant = this.clock.CreateInstant(other); + break; + default: + throw new InvalidOperationException( + "Did not get a date time object from the callback. " + + "Can only handle DateTime, DateTimeOffset, LocalDate, " + + "and Instant. Got a " + + temporal.GetType().Name + + " instead."); + } + + return entity.Set(instant); + } + } +} diff --git a/src/Nitride.Temporal/SetInstantFromPath.cs b/src/Nitride.Temporal/SetInstantFromPath.cs new file mode 100644 index 0000000..39cbc18 --- /dev/null +++ b/src/Nitride.Temporal/SetInstantFromPath.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Gallium; +using NodaTime; +using Zio; + +namespace Nitride.Temporal +{ + /// + /// Sets the instant in the file based on the path of the entity. This + /// defaults to a generous regular expression that handles most formats of + /// four digit year, a separator, two digit month, a separator, and a two + /// digit day of month. + /// + [WithProperties] + public partial class SetInstantFromPath : NitrideOperationBase + { + private readonly NitrideClock clock; + + public SetInstantFromPath(NitrideClock clock) + { + this.clock = clock; + this.PathRegex = new Regex( + @"(?\d{4})[/-](?\d{2})[/-](?\d{2})"); + } + + /// + /// Gets or sets a regular expression that has three named expressions: + /// year, month, and day. + /// + public Regex? PathRegex { get; set; } + + /// + public override IEnumerable Run(IEnumerable input) + { + this.CheckNotNull(nameof(this.PathRegex), this.PathRegex); + + return input.ForEachEntity(this.Set); + } + + private Entity Set(Entity entity, UPath path) + { + // See if the path matches the given expression. + Match match = this.PathRegex!.Match(path.ToString()); + + if (!match.Success) + { + return entity; + } + + // Create an Instant from this. + Instant instant = this.clock.CreateInstant( + Convert.ToInt32(match.Groups["year"].Value), + Convert.ToInt32(match.Groups["month"].Value), + Convert.ToInt32(match.Groups["day"].Value)); + + return entity.Set(instant); + } + } +} diff --git a/src/Nitride.Tests/EntityContentTests.cs b/src/Nitride.Tests/EntityContentTests.cs new file mode 100644 index 0000000..0cc94af --- /dev/null +++ b/src/Nitride.Tests/EntityContentTests.cs @@ -0,0 +1,75 @@ +using Gallium; +using Nitride.Contents; +using Xunit; +using Xunit.Abstractions; + +namespace Nitride.Tests +{ + /// + /// Tests the various functionality of the high-level content methods and + /// extension methods. + /// + public class EntityContentTests : NitrideTestsBase + { + public EntityContentTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void AddBinaryContent() + { + var content = new ByteArrayBinaryContent(new byte[0]); + Entity entity = new Entity() + .SetBinaryContent(content); + + Assert.Equal(1, entity.Count); + Assert.True(entity.HasContent()); + Assert.True(entity.HasBinaryContent()); + Assert.False(entity.HasTextContent()); + } + + [Fact] + public void AddTextContent() + { + var content = new StringTextContent("contents"); + Entity entity = new Entity() + .SetTextContent(content); + + Assert.Equal(1, entity.Count); + Assert.True(entity.HasContent()); + Assert.False(entity.HasBinaryContent()); + Assert.True(entity.HasTextContent()); + } + + [Fact] + public void SwitchBinaryToTextContent() + { + var binaryContent = new ByteArrayBinaryContent(new byte[0]); + var textContent = new StringTextContent("contents"); + Entity entity = new Entity() + .SetBinaryContent(binaryContent) + .SetTextContent(textContent); + + Assert.Equal(1, entity.Count); + Assert.True(entity.HasContent()); + Assert.False(entity.HasBinaryContent()); + Assert.True(entity.HasTextContent()); + } + + [Fact] + public void SwitchTextToBinaryContent() + { + var binaryContent = new ByteArrayBinaryContent(new byte[0]); + var textContent = new StringTextContent("contents"); + Entity entity = new Entity() + .SetContent(textContent) + .SetContent(binaryContent); + + Assert.Equal(1, entity.Count); + Assert.True(entity.HasContent()); + Assert.True(entity.HasBinaryContent()); + Assert.False(entity.HasTextContent()); + } + } +} diff --git a/src/Nitride.Tests/Nitride.Tests.csproj b/src/Nitride.Tests/Nitride.Tests.csproj new file mode 100644 index 0000000..6b92b54 --- /dev/null +++ b/src/Nitride.Tests/Nitride.Tests.csproj @@ -0,0 +1,30 @@ + + + + net5.0 + false + enable + Nitride.Tests + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/src/Nitride.Tests/NitrideTestsBase.cs b/src/Nitride.Tests/NitrideTestsBase.cs new file mode 100644 index 0000000..1cf3ada --- /dev/null +++ b/src/Nitride.Tests/NitrideTestsBase.cs @@ -0,0 +1,63 @@ +using Autofac; +using Serilog; +using Serilog.Core; +using Xunit.Abstractions; + +namespace Nitride.Tests +{ + /// + /// Common initialization logic for Nitride-based tests including setting + /// up containers, logging, and Serilog. + /// + public abstract class NitrideTestsBase + { + private readonly ITestOutputHelper output; + + public NitrideTestsBase(ITestOutputHelper output) + { + this.output = output; + + // Set up logging. + const string Template = + "[{Level:u3}] " + + "({SourceContext}) {Message}" + + "{NewLine}{Exception}"; + + this.Logger = new LoggerConfiguration() + .WriteTo.TestOutput( + output, + outputTemplate: Template) + .CreateLogger(); + + // Set up Autofac. + var builder = new ContainerBuilder(); + + builder.RegisterInstance(this.Logger) + .As() + .SingleInstance(); + builder.RegisterModule(); + + this.ConfigureContainer(builder); + + this.Container = builder.Build(); + } + + /// + /// Contains the Autofac container for this test. + /// + protected IContainer Container { get; } + + /// + /// Gets the logger used to report messages about the test. + /// + protected Logger Logger { get; } + + /// + /// Configures the Autofac container for this test instance. + /// + /// + protected virtual void ConfigureContainer(ContainerBuilder builder) + { + } + } +} diff --git a/src/Nitride.Yaml.Tests/Nitride.Yaml.Tests.csproj b/src/Nitride.Yaml.Tests/Nitride.Yaml.Tests.csproj new file mode 100644 index 0000000..cb94658 --- /dev/null +++ b/src/Nitride.Yaml.Tests/Nitride.Yaml.Tests.csproj @@ -0,0 +1,29 @@ + + + + net5.0 + enable + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + diff --git a/src/Nitride.Yaml.Tests/ParseYamlHeaderTests.cs b/src/Nitride.Yaml.Tests/ParseYamlHeaderTests.cs new file mode 100644 index 0000000..434513c --- /dev/null +++ b/src/Nitride.Yaml.Tests/ParseYamlHeaderTests.cs @@ -0,0 +1,114 @@ +using System.Collections.Generic; +using System.Linq; +using Gallium; +using Nitride.Contents; +using Nitride.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace Nitride.Yaml.Tests +{ + public class ParseYamlHeaderTests : NitrideTestsBase + { + public ParseYamlHeaderTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void ParseNoContent() + { + var input = new List + { + new Entity() + .SetTextContent( + new StringTextContent( + "---", + "title: Test Title 1", + "---")) + }; + + var op = new ParseYamlHeader(); + + Entity output = input + .Run(op) + .First(); + + Assert.True(output.Has()); + Assert.Equal( + new[] + { + string.Empty, + }, + output.Get().GetText().Split("\n")); + Assert.True(output.Has()); + Assert.Equal("Test Title 1", output.Get().Title); + } + + [Fact] + public void ParseNoHeader() + { + var input = new List + { + new Entity() + .SetTextContent( + new StringTextContent( + "Hello")) + }; + + var op = new ParseYamlHeader(); + + Entity output = input + .Run(op) + .First(); + + Assert.True(output.Has()); + Assert.Equal( + new[] + { + "Hello", + string.Empty, + }, + output.Get().GetText().Split("\n")); + Assert.True(output.Has()); + Assert.Null(output.Get().Title); + } + + [Fact] + public void ParseSimpleHeader() + { + var input = new List + { + new Entity() + .SetTextContent( + new StringTextContent( + "---", + "title: Test Title 1", + "---", + "Hello")) + }; + + var op = new ParseYamlHeader(); + + Entity output = input + .Run(op) + .First(); + + Assert.True(output.Has()); + Assert.Equal( + new[] + { + "Hello", + string.Empty, + }, + output.Get().GetText().Split("\n")); + Assert.True(output.Has()); + Assert.Equal("Test Title 1", output.Get().Title); + } + + private class TestHeader + { + public string? Title { get; set; } + } + } +} diff --git a/src/Nitride.Yaml/Nitride.Yaml.csproj b/src/Nitride.Yaml/Nitride.Yaml.csproj new file mode 100644 index 0000000..4221334 --- /dev/null +++ b/src/Nitride.Yaml/Nitride.Yaml.csproj @@ -0,0 +1,33 @@ + + + + net5.0 + enable + + + + An extension to Nitride static site generator to parse YAML content. + + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride.Yaml/NitrideYamlBuilderExtensions.cs b/src/Nitride.Yaml/NitrideYamlBuilderExtensions.cs new file mode 100644 index 0000000..146b250 --- /dev/null +++ b/src/Nitride.Yaml/NitrideYamlBuilderExtensions.cs @@ -0,0 +1,14 @@ +using Autofac; + +namespace Nitride.Yaml +{ + public static class NitrideYamlBuilderExtensions + { + public static NitrideBuilder UseYaml(this NitrideBuilder builder) + { + return builder + .ConfigureContainer( + x => x.RegisterModule()); + } + } +} diff --git a/src/Nitride.Yaml/NitrideYamlModule.cs b/src/Nitride.Yaml/NitrideYamlModule.cs new file mode 100644 index 0000000..09a5709 --- /dev/null +++ b/src/Nitride.Yaml/NitrideYamlModule.cs @@ -0,0 +1,15 @@ +using Autofac; + +namespace Nitride.Yaml +{ + public class NitrideYamlModule : NitrideModuleBase + { + /// + protected override void Register(ContainerBuilder builder) + { + builder + .RegisterGeneric(typeof(ParseYamlHeader<>)) + .As(typeof(ParseYamlHeader<>)); + } + } +} diff --git a/src/Nitride.Yaml/ParseYamlHeader.cs b/src/Nitride.Yaml/ParseYamlHeader.cs new file mode 100644 index 0000000..c4e6203 --- /dev/null +++ b/src/Nitride.Yaml/ParseYamlHeader.cs @@ -0,0 +1,163 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using Gallium; +using Nitride.Contents; +using YamlDotNet.Serialization; +using YamlDotNet.Serialization.NamingConventions; + +namespace Nitride.Yaml +{ + /// + /// An operation that parses the header of a text file and pulls out the + /// YAML header with a specific type. + /// + /// The model that represents the header. + public class ParseYamlHeader : NitrideOperationBase + where TModel : class, new() + { + private bool ignoreUnmatchedProperties; + + private INamingConvention namingConvention; + + public ParseYamlHeader() + { + this.namingConvention = CamelCaseNamingConvention.Instance; + this.ignoreUnmatchedProperties = true; + this.RemoveHeader = true; + } + + /// + /// Gets or sets a value indicating whether the header should be removed + /// and the text content be removed. + /// + private bool RemoveHeader { get; set; } + + /// + public override IEnumerable Run(IEnumerable input) + { + // Set up the YAML parsing. + DeserializerBuilder builder = new DeserializerBuilder() + .WithNamingConvention(this.namingConvention); + + if (this.ignoreUnmatchedProperties) + { + builder = builder.IgnoreUnmatchedProperties(); + } + + IDeserializer deserializer = builder.Build(); + + // Process through the files. We only care about the text ones + // and we'll put a default TModel in for those that don't have a + // header. + return input + .ForEachEntity( + (entity, content) => this.Parse( + entity, + content, + deserializer)); + } + + /// + /// Sets the flag if the module should ignore unmatched properties + /// which defaults to true (ignore). + /// + /// The new value. + /// The module for chaining. + public ParseYamlHeader WithIgnoreUnmatchedProperties(bool value) + { + this.ignoreUnmatchedProperties = value; + return this; + } + + /// + /// Sets the naming convention to something other than the default + /// camel case. + /// + /// The new naming convention. + /// The module for chaining. + public ParseYamlHeader WithNamingConvention( + INamingConvention value) + { + this.namingConvention = value; + return this; + } + + public ParseYamlHeader WithRemoveHeader(bool value) + { + this.RemoveHeader = value; + return this; + } + + private Entity Parse( + Entity entity, + ITextContent content, + IDeserializer deserializer) + { + // Get the textual input from the stream. + using TextReader reader = content.GetReader(); + + // See if the first line is one that indicates a YAML header. + string? line = reader.ReadLine(); + + if (line != "---") + { + // This file doesn't have a YAML header, so add the default + // version of our model and move on. + return entity.Set(new TModel()); + } + + // Read the rest of the header until we get to the end of the + // header. If we get to the end of the file first, then we don't + // have a valid file and just return the default. + StringBuilder buffer = new(); + + buffer.AppendLine(line); + + while ((line = reader.ReadLine()) != null) + { + // If have a separator, then we're done processing. + if (line == "---") + { + break; + } + + // Read the next line into memory. + buffer.AppendLine(line); + } + + // If the line is null, then we got to the end of the file without + // finding a proper header, so use a default and have no other + // changes. + if (line == null) + { + return entity.Set(new TModel()); + } + + // Pull out the model so we can append it later. + string yaml = buffer.ToString(); + + var model = deserializer.Deserialize(yaml); + + // If we are not removing the header, then we're done. + if (!this.RemoveHeader) + { + return entity.Set(model); + } + + // Read the rest of the reader into a new (reused) buffer so we can + // set the new text content to the text without the header. + buffer.Length = 0; + + while ((line = reader.ReadLine()) != null) + { + buffer.AppendLine(line); + } + + // Set the model and return it. + return entity + .Set(model) + .SetTextContent(new StringTextContent(buffer.ToString())); + } + } +} diff --git a/src/Nitride/Commands/BuildCommand.cs b/src/Nitride/Commands/BuildCommand.cs new file mode 100644 index 0000000..9444b27 --- /dev/null +++ b/src/Nitride/Commands/BuildCommand.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.CommandLine; +using System.CommandLine.Invocation; +using System.Threading.Tasks; +using Nitride.Pipelines; +using Serilog; + +namespace Nitride.Commands +{ + /// + /// The basic command to generate a website and run through the pipelines. + /// + public class BuildCommand : Command, ICommandHandler, ITopLevelCommand + { + private readonly ILogger logger; + + private readonly IList pipelineOptions; + + private readonly PipelineManager pipelines; + + public BuildCommand( + ILogger logger, + PipelineManager pipelines, + IList pipelineOptions) + : base("build", "Generate the website") + { + // Set up our simple member variables. + this.pipelines = pipelines; + this.pipelineOptions = pipelineOptions; + this.logger = logger.ForContext(); + this.Handler = this; + + // Handle any injected arguments into the command line. + foreach (var option in pipelineOptions) + { + this.AddOption(option.Option); + } + } + + /// + public async Task InvokeAsync(InvocationContext context) + { + // Process any injected options. + foreach (var option in this.pipelineOptions) + { + option.Handle(context); + } + + // This is the main entry point into the `build` command. This runs + // all the pipelines once and then quits when it finishes. + int pipelinesResults = await this.pipelines.RunAsync(); + + return pipelinesResults; + } + } +} diff --git a/src/Nitride/Commands/IPipelineCommandOption.cs b/src/Nitride/Commands/IPipelineCommandOption.cs new file mode 100644 index 0000000..6dbc6df --- /dev/null +++ b/src/Nitride/Commands/IPipelineCommandOption.cs @@ -0,0 +1,23 @@ +using System.CommandLine; +using System.CommandLine.Invocation; + +namespace Nitride.Commands +{ + /// + /// Creates new options for the build command to allow injecting an + /// option into the build command. + /// + public interface IPipelineCommandOption + { + /// + /// The option that used to bind to the command. + /// + Option Option { get; } + + /// + /// Handles the command after it has been created and the options bound. + /// + /// The context of the CLI command. + void Handle(InvocationContext context); + } +} diff --git a/src/Nitride/Commands/ITopLevelCommand.cs b/src/Nitride/Commands/ITopLevelCommand.cs new file mode 100644 index 0000000..301a6b8 --- /dev/null +++ b/src/Nitride/Commands/ITopLevelCommand.cs @@ -0,0 +1,12 @@ +using System.CommandLine; + +namespace Nitride.Commands +{ + /// + /// An interface that indicates that the given command is a top-level + /// command instead of one that is included as a sub-command inside another. + /// + public interface ITopLevelCommand : ICommand + { + } +} diff --git a/src/Nitride/ContainerBuiltHandler.cs b/src/Nitride/ContainerBuiltHandler.cs new file mode 100644 index 0000000..a851e7e --- /dev/null +++ b/src/Nitride/ContainerBuiltHandler.cs @@ -0,0 +1,7 @@ +namespace Nitride +{ + /// + /// Describes the signature of a callback for after the container is build. + /// + public delegate void ContainerBuiltHandler(); +} diff --git a/src/Nitride/Contents/ByteArrayBinaryContent.cs b/src/Nitride/Contents/ByteArrayBinaryContent.cs new file mode 100644 index 0000000..f8430d6 --- /dev/null +++ b/src/Nitride/Contents/ByteArrayBinaryContent.cs @@ -0,0 +1,26 @@ +using System; +using System.IO; + +namespace Nitride.Contents +{ + /// + /// Implements a purely in-memory binary content provider. + /// + public class ByteArrayBinaryContent : IBinaryContent + { + private readonly byte[] buffer; + + public ByteArrayBinaryContent(byte[] buffer) + { + this.buffer = + buffer ?? throw new ArgumentNullException(nameof(buffer)); + } + + /// + public Stream GetStream() + { + // Return a memory stream that cannot be written. + return new MemoryStream(this.buffer, false); + } + } +} diff --git a/src/Nitride/Contents/EntityBinaryContentExtensions.cs b/src/Nitride/Contents/EntityBinaryContentExtensions.cs new file mode 100644 index 0000000..954c65a --- /dev/null +++ b/src/Nitride/Contents/EntityBinaryContentExtensions.cs @@ -0,0 +1,47 @@ +using Gallium; + +namespace Nitride.Contents +{ + /// + /// Various extension methods for working with binary content. + /// + public static class EntityBinaryContentExtensions + { + /// + /// Retrieves the binary content associated with this entity. + /// + /// The entity to query. + /// The binary content. + public static IBinaryContent GetBinaryContent(this Entity entity) + { + return entity.Get(); + } + + /// + /// Determines if the entity has a registered IBinaryContent component. + /// + /// The entity to inspect. + /// True if there is a component extending `IContent`. + public static bool HasBinaryContent(this Entity entity) + { + return entity.Has(); + } + + /// + /// Remove all existing content components from the entity and then adds + /// the new binary content as a component into the entity before + /// returning it. + /// + /// The entity to query and modify. + /// The content to add to the entity. + /// The base type of the content. + /// The entity or a copy with the new component. + public static Entity SetBinaryContent( + this Entity entity, + TType content) + where TType : IBinaryContent + { + return entity.SetContent(content); + } + } +} diff --git a/src/Nitride/Contents/EntityContentExtensions.cs b/src/Nitride/Contents/EntityContentExtensions.cs new file mode 100644 index 0000000..1aa8ad5 --- /dev/null +++ b/src/Nitride/Contents/EntityContentExtensions.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Gallium; + +namespace Nitride.Contents +{ + /// + /// Various extension methods for working with content. + /// + public static class EntityContentExtensions + { + /// + /// Retrieves the single registered content entity inside the component. + /// If there is more than one, this will throw an exception. + /// + /// The entity to query. + /// The one and only content component. + public static IContent GetContent(this Entity entity) + { + Type type = entity + .GetComponentTypes() + .Single(x => typeof(IContent).IsAssignableFrom(x)); + + return entity.Get(type); + } + + /// + /// Determines if the entity has at least one content component. + /// + /// The entity to inspect. + /// True if there is a component extending `IContent`. + public static bool HasContent(this Entity entity) + { + return entity + .GetComponentTypes() + .Any(x => typeof(IContent).IsAssignableFrom(x)); + } + + /// + /// Remove all existing content components from the entity and then adds + /// the new component into the entity before returning it. + /// + /// The entity to query and modify. + /// The content to add to the entity. + /// The base type of the content. + /// The entity or a copy with the new component. + public static Entity SetContent( + this Entity entity, + TType content) + where TType : IContent + { + IEnumerable? existing = entity + .GetComponentTypes() + .Where(x => typeof(IContent).IsAssignableFrom(x)); + + foreach (var component in existing) + { + entity = entity.Remove(component); + } + + return entity.Add(content); + } + } +} diff --git a/src/Nitride/Contents/EntityTextContentExtensions.cs b/src/Nitride/Contents/EntityTextContentExtensions.cs new file mode 100644 index 0000000..71f479a --- /dev/null +++ b/src/Nitride/Contents/EntityTextContentExtensions.cs @@ -0,0 +1,53 @@ +using Gallium; + +namespace Nitride.Contents +{ + /// + /// Various extension methods for working with text content. + /// + public static class EntityTextContentExtensions + { + /// + /// Determines if the entity has a registered ITextContent component. + /// + /// The entity to inspect. + /// True if there is a component extending `IContent`. + public static bool HasTextContent(this Entity entity) + { + return entity.Has(); + } + + /// + /// Remove all existing content components from the entity and then adds + /// the new text content as a component into the entity before + /// returning it. + /// + /// The entity to query and modify. + /// The content to add to the entity. + /// The base type of the content. + /// The entity or a copy with the new component. + public static Entity SetTextContent( + this Entity entity, + TType content) + where TType : ITextContent + { + return entity.SetContent(content); + } + + /// + /// Remove all existing content components from the entity and then adds + /// the new text content as a component into the entity before + /// returning it. + /// + /// The entity to query and modify. + /// The content to add to the entity. + /// The base type of the content. + /// The entity or a copy with the new component. + public static Entity SetTextContent( + this Entity entity, + string content) + { + return entity.SetTextContent(new StringTextContent(content)); + } + } +} diff --git a/src/Nitride/Contents/FileBinaryContent.cs b/src/Nitride/Contents/FileBinaryContent.cs new file mode 100644 index 0000000..8e20643 --- /dev/null +++ b/src/Nitride/Contents/FileBinaryContent.cs @@ -0,0 +1,44 @@ +using System; +using System.IO; + +namespace Nitride.Contents +{ + /// + /// A binary content provider based on a file in the file system. + /// + public class FileBinaryContent : IBinaryContent, ITextContentConvertable + { + private readonly string path; + + public FileBinaryContent(string path) + { + this.path = path ?? throw new ArgumentNullException(nameof(path)); + } + + public FileBinaryContent(FileInfo file) + { + if (file == null) + { + throw new ArgumentNullException(nameof(file)); + } + + this.path = file.FullName; + } + + /// + public Stream GetStream() + { + return File.Open( + this.path, + FileMode.Open, + FileAccess.Read, + FileShare.Read); + } + + /// + public ITextContent ToTextContent() + { + return new FileTextContent(this.path); + } + } +} diff --git a/src/Nitride/Contents/FileTextContent.cs b/src/Nitride/Contents/FileTextContent.cs new file mode 100644 index 0000000..497123d --- /dev/null +++ b/src/Nitride/Contents/FileTextContent.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; +using System.Text; + +namespace Nitride.Contents +{ + /// + /// A text content provider based on a file in the file system. + /// + public class FileTextContent : ITextContent, IBinaryContentConvertable + { + private readonly string path; + + public FileTextContent(string path) + { + this.path = path ?? throw new ArgumentNullException(nameof(path)); + } + + public FileTextContent(FileInfo file) + { + if (file == null) + { + throw new ArgumentNullException(nameof(file)); + } + + this.path = file.FullName; + } + + /// + public TextReader GetReader() + { + return new StreamReader( + File.Open( + this.path, + FileMode.Open, + FileAccess.Read, + FileShare.Read), + Encoding.UTF8); + } + + /// + public IBinaryContent ToBinaryContent() + { + return new FileBinaryContent(this.path); + } + } +} diff --git a/src/Nitride/Contents/IBinaryContent.cs b/src/Nitride/Contents/IBinaryContent.cs new file mode 100644 index 0000000..f7c0147 --- /dev/null +++ b/src/Nitride/Contents/IBinaryContent.cs @@ -0,0 +1,19 @@ +using System.IO; + +namespace Nitride.Contents +{ + /// + /// Indicates a content source that works with binary data and streams. + /// + public interface IBinaryContent : IContent + { + /// + /// Opens a read-only stream into the underlying source of binary data. + /// + /// + /// It is up to the calling class to close this stream. + /// + /// A stream to the internal data. + Stream GetStream(); + } +} diff --git a/src/Nitride/Contents/IBinaryContentConvertable.cs b/src/Nitride/Contents/IBinaryContentConvertable.cs new file mode 100644 index 0000000..525cff9 --- /dev/null +++ b/src/Nitride/Contents/IBinaryContentConvertable.cs @@ -0,0 +1,15 @@ +namespace Nitride.Contents +{ + /// + /// An interface to indicates an object can be converted into a binary + /// content directly. + /// + public interface IBinaryContentConvertable + { + /// + /// Convert the given object into a binary content. + /// + /// + IBinaryContent ToBinaryContent(); + } +} diff --git a/src/Nitride/Contents/IContent.cs b/src/Nitride/Contents/IContent.cs new file mode 100644 index 0000000..4035fd9 --- /dev/null +++ b/src/Nitride/Contents/IContent.cs @@ -0,0 +1,12 @@ +namespace Nitride.Contents +{ + /// + /// Describes a content provider or source for an Entity. `IContent` is + /// also used for the mutual exclusivity login in `EntityContentExtensions` + /// where all `IContent` derived components are automatically removed when + /// setting a new content source. + /// + public interface IContent + { + } +} diff --git a/src/Nitride/Contents/ITextContent.cs b/src/Nitride/Contents/ITextContent.cs new file mode 100644 index 0000000..9a79e70 --- /dev/null +++ b/src/Nitride/Contents/ITextContent.cs @@ -0,0 +1,19 @@ +using System.IO; + +namespace Nitride.Contents +{ + /// + /// Indicates a content source that provides data as a TextReader and text. + /// + public interface ITextContent : IContent + { + /// + /// Opens a text reader into the underlying source of text data. + /// + /// + /// It is up to the calling class to close this reader. + /// + /// The text reader to the internal data. + TextReader GetReader(); + } +} diff --git a/src/Nitride/Contents/ITextContentConvertable.cs b/src/Nitride/Contents/ITextContentConvertable.cs new file mode 100644 index 0000000..e7f1fad --- /dev/null +++ b/src/Nitride/Contents/ITextContentConvertable.cs @@ -0,0 +1,15 @@ +namespace Nitride.Contents +{ + /// + /// An interface to indicates an object can be converted into a text + /// content directly. + /// + public interface ITextContentConvertable + { + /// + /// Convert the given object into a text content. + /// + /// + ITextContent ToTextContent(); + } +} diff --git a/src/Nitride/Contents/README.md b/src/Nitride/Contents/README.md new file mode 100644 index 0000000..fe29826 --- /dev/null +++ b/src/Nitride/Contents/README.md @@ -0,0 +1,186 @@ +# Contents + +The contents of a file may be stored as a component, however this increases the +memory pressure when Nitride works with hundreds or thousands of files. To +reduce this, memory is loaded on demand through an abstracted components such +as `IBinaryContent` and `ITextContent`. + +## Exclusivity + +The content interfaces are treated as *mutually exclusive* with each other by +extending the `IContent` interface. The intended reason for this is to have a +single source of data that doesn't go out of sync. Adding or setting +a `IBinaryContent` will remove the other content components in the entity, even +ones that are defined in other classes. In effect, all `IContent` +will be removed to ensure that. This is implemented via a number of extension +operations. + +```c# +Entity entity; +IBinaryContent binaryContent; +ITextContent textContent; + +entity.Add(binaryContent); +Assert.Equal(1, entity.Count); +Assert.True(entity.Has()); +Assert.True(entity.HasBinaryContent()); +Assert.True(entity.HasContent()); + +entity.SetContent(textContent); +Assert.Equal(1, entity.Count); +Assert.False(entity.Has()); +Assert.False(entity.HasBinaryContent()); +Assert.True(entity.Has()); +Assert.True(entity.HasTextContent()); +Assert.True(entity.HasContent()); + +entity.RemoveContent(); +Assert.Equal(0, entity.Count); +Assert.False(entity.Has()); +Assert.False(entity.HasBinaryContent()); +Assert.False(entity.Has()); +Assert.False(entity.HasTextContent()); +Assert.False(entity.HasContent()); +``` + +This exclusivity can be ignored by using direct `Add<>`, `Set<>`, and +`Remove<>` methods on the entity. That would allow multiple content to be added +and removed at the same time. + +```c# +Entity entity; +IBinaryContent binaryContent = entity.Get(); +using Stream binaryStream = binaryContent.GetStream(); +using StreamReader binaryReader = new StreamReader(binaryStream); +var text = binaryReader.ReadToEnd(); +var textContent = new StringTextContent(text); + +var switchedEntity = entity + .Set(textContent) + .Remove(); +Assert.Equal(1, switchedEntity.Count); +Assert.True(switchedEntity.Has()); +Assert.False(switchedEntity.Has()); + +var mergedEntity = entity + .Set(textContent); +Assert.Equal(2, switchedEntity.Count); +Assert.True(switchedEntity.Has()); +Assert.True(switchedEntity.Has()); +``` + +Implementing this with a parent interface (`IContent`) allows future content +providers, such as `IXmlContent` or other future content sources. + +## IBinaryComponent + +Most files start as only having access to binary content. + +```c# +Entity entity; +IBinaryContent content = entity.Get(); +using Stream stream = content.GetStream(); +``` + +There is no guarantee that the data behind the stream is loaded into memory or +even available on disk. Instead, the stream is good until it goes out of scope. + +### IBinaryContentConvertable + +There is an additional interface that allows a content to be converted into +an `IBinaryContent).` + +```c# +FileTextContent textContent; +IBinaryContent binaryContent = textContent.ToBinaryContent(); +``` + +### Extension Methods + +There are some convenience methods for working with entity components and +content since they are frequently used. + +```c# +IBinaryContent content = entity.GetBinaryContent(); +bool has = entity.HasBinaryContent(); + +// Internally, this uses `SetContent` above with some additonal type safety. +entity = entity.SetBinaryContent(content); +``` + +### ByteArrayBinaryComponent + +The `ByteArrayBinaryComponent` is a component that contains the entire binary +data in memory and returns it via `System.IO.MemoryStream` objects. + +```c# +byte[] bytes; +var content = new ByteArrayBinaryComponent(bytes); +``` + +### FileBinaryContent + +The `TextBinaryContent` takes a path or FileInfo object as the parameter and +will produce a stream directly from the file without loading the file into +memory. + +```c# +FileInfo file; + +new FileBinaryContent(@"C:\Temp\Bob.txt"); +new FileBinaryContent(file); +``` + +## ITextContent + +Text content allows for retrieving the contents via `TextReader` instead of a +stream. + +```c# +ITextContent content; + +using TextReader reader = content.GetReader(); +``` + +### ITextContentConvertable + +There is an additional interface that allows a content to be converted into +an `ITextContent).` + +```c# +FileBinaryContent binaryContent; +ITextContent textContent = binaryContent.ToTextContent(); +``` + +### Extension Methods + +Like the binary, there are some convenience methods for working with entity +components. + +```c# +ITextContent content = entity.GetTextContent(); +bool has = entity.HasTextContent(); + +entity = entity.SetTextContent(content); +``` + +### StringTextContent + +A simple, in-memory string text content takes a string as the parameter. + +```c# +string input; +ITextContent content = new StringTextContent(input); +``` + +### FileTextContent + +The `TextFileContent` takes a path or FileInfo object as the parameter and will +produce a reader directly from the file without loading the file into memory. + +```c# +FileInfo file; + +new FileTextContent(@"C:\Temp\Bob.txt"); +new FileTextContent(file); +``` diff --git a/src/Nitride/Contents/StringTextContent.cs b/src/Nitride/Contents/StringTextContent.cs new file mode 100644 index 0000000..770ea0c --- /dev/null +++ b/src/Nitride/Contents/StringTextContent.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using System.Text; + +namespace Nitride.Contents +{ + /// + /// Implements a pure, in-memory text content provider that uses a string + /// as the backing store. + /// + public class StringTextContent : ITextContent + { + private readonly string buffer; + + public StringTextContent(StringBuilder buffer) + : this(buffer.ToString()) + { + } + + public StringTextContent(string buffer) + { + this.buffer = + buffer ?? throw new ArgumentNullException(nameof(buffer)); + } + + public StringTextContent(params string[] lines) + : this(string.Join("\n", lines)) + { + } + + /// + public TextReader GetReader() + { + return new StringReader(this.buffer); + } + } +} diff --git a/src/Nitride/Contents/TextContentExtensions.cs b/src/Nitride/Contents/TextContentExtensions.cs new file mode 100644 index 0000000..133c52e --- /dev/null +++ b/src/Nitride/Contents/TextContentExtensions.cs @@ -0,0 +1,22 @@ +using System.IO; + +namespace Nitride.Contents +{ + public static class TextContentExtensions + { + public static string GetText(this ITextContent content) + { + var writer = new StringWriter(); + using TextReader reader = content.GetReader(); + string? line = reader.ReadLine(); + + while (line != null) + { + writer.WriteLine(line); + line = reader.ReadLine(); + } + + return writer.ToString(); + } + } +} diff --git a/src/Nitride/Entities/CreateIndexEntities.cs b/src/Nitride/Entities/CreateIndexEntities.cs new file mode 100644 index 0000000..61dd6c2 --- /dev/null +++ b/src/Nitride/Entities/CreateIndexEntities.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections.Generic; +using Gallium; +using Serilog; + +namespace Nitride.Entities +{ + /// + /// A Nitride operation that creates and merges entities that are intended + /// to be indexes of another entity. For example, this could be year and + /// month archive pages, tag or category pages. Support is given for + /// merging existing pages so a description could be written from a file + /// and then the index logic is automatically added. + /// + public partial class CreateIndexEntities : NitrideOperationBase + where TIndexKey : notnull + { + private readonly ILogger logger; + + public CreateIndexEntities(ILogger logger) + { + this.logger = logger.ForContext(typeof(CreateIndexEntities<>)); + } + + /// + /// Creates an index for a given key. This will not be called for any + /// index that has been already created. + /// + public Func, Entity>? CreateIndexEntity + { + get; + set; + } + + /// + /// Gets or sets the function to retrieve the key from an existing + /// index page. If this returns null, then the entity is considered not + /// to be an index page. + /// + public Func? GetIndexEntityKey { get; set; } + + /// + /// A method that gets the keys for a given entity. If this returns an + /// empty list, then the entity will not added to an index. + /// + public Func>? GetIndexKeys { get; set; } + + /// + /// Updates an existing index entity to include new information. + /// + public Func, Entity>? UpdateIndexEntity + { + get; + set; + } + + /// + public override IEnumerable Run(IEnumerable input) + { + // Make sure we have sane data. + this.CheckNotNull( + nameof(this.CreateIndexEntity), + this.CreateIndexEntity); + this.CheckNotNull( + nameof(this.GetIndexKeys), + this.GetIndexKeys); + this.CheckNotNull( + nameof(this.UpdateIndexEntity), + this.UpdateIndexEntity); + + // We need to process two lists out of the output, so we need to put + // it into a list so we can enumerate through it twice. This will + // also cause the output to be reordered. + Dictionary indexes = new(); + Dictionary> indexed = new(); + List results = new(); + + foreach (var entity in input) + { + // See if we are an index page first. + if (this.GetIndexEntityKey != null) + { + TIndexKey? indexKey = this.GetIndexEntityKey(entity); + + if (indexKey != null) + { + indexes[indexKey] = entity; + continue; + } + } + + // We aren't an index, so check to see if this entity is + // something to be indexed. + foreach (TIndexKey indexedKey in this.GetIndexKeys!(entity)) + { + if (!indexed.TryGetValue(indexedKey, out var list)) + { + indexed[indexedKey] = list = new List(); + } + + list.Add(entity); + } + + // Add to the non-index page list. + results.Add(entity); + } + + // Go through all the index pages and update them. We get a list of + // all the pages in the index and pass them into the function to + // update the existing index. Then we update the entity and add it + // to the bottom of the results list. + foreach ((TIndexKey key, var oldIndex) in indexes) + { + if (!indexed.TryGetValue(key, out var list)) + { + list = new List(); + } + + Entity newEntity = this.UpdateIndexEntity!(oldIndex, key, list); + + results.Add(newEntity); + } + + // Go through all the known index keys and create the missing pages. + int created = 0; + + foreach ((TIndexKey key, var list) in indexed) + { + // See if we already have a page, if we do, then we've already + // processed that page and don't have to do anything. + if (indexes.ContainsKey(key)) + { + continue; + } + + // We don't have that page and need to add it to the list. + Entity entity = this.CreateIndexEntity!(key, list); + + created++; + results.Add(entity); + } + + // Return the combined together version. + this.logger.Debug( + "Found {Old:N0} and created {New:N0} index pages for {Keys:N0} keys", + indexes.Count, + created, + indexed.Count); + + return results; + } + + public CreateIndexEntities WithCreateIndexEntity( + Func, Entity>? callback) + { + this.CreateIndexEntity = callback; + return this; + } + + public CreateIndexEntities WithGetIndexEntityKey( + Func? callback) + { + this.GetIndexEntityKey = callback; + return this; + } + + public CreateIndexEntities WithGetIndexKeys( + Func>? callback) + { + this.GetIndexKeys = callback; + return this; + } + + public CreateIndexEntities WithUpdateIndexEntity( + Func, Entity>? callback) + { + this.UpdateIndexEntity = callback; + return this; + } + } +} diff --git a/src/Nitride/Entities/LinkPreviousNextHandler.cs b/src/Nitride/Entities/LinkPreviousNextHandler.cs new file mode 100644 index 0000000..3e01fc2 --- /dev/null +++ b/src/Nitride/Entities/LinkPreviousNextHandler.cs @@ -0,0 +1,9 @@ +using Gallium; + +namespace Nitride.Entities +{ + public delegate Entity LinkPreviousNextHandler( + Entity entity, + Entity? previous, + Entity? next); +} diff --git a/src/Nitride/Entities/LinkSerialEntities.cs b/src/Nitride/Entities/LinkSerialEntities.cs new file mode 100644 index 0000000..16e0988 --- /dev/null +++ b/src/Nitride/Entities/LinkSerialEntities.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Linq; +using Gallium; + +namespace Nitride.Entities +{ + /// + /// Links a series of entities together in some manner. This assumes that + /// the entities coming into the operation are already ordered. + /// + [WithProperties] + public partial class LinkSerialEntities : NitrideOperationBase + { + /// + /// The callback function that sets the previous and next + /// + public LinkPreviousNextHandler? UpdatePreviousNext { get; set; } + + /// + public override IEnumerable Run(IEnumerable input) + { + // We pull all the entities into a list so we can walk through them + // more than once along with index access. + var list = input.ToList(); + + // Go through the list and assign each entity in order. + this.CheckNotNull(x => this.UpdatePreviousNext); + + for (int i = 0; i < list.Count; i++) + { + Entity entity = list[i]; + Entity? previous = i > 0 ? list[i - 1] : null; + Entity? next = i < list.Count - 1 ? list[i + 1] : null; + + list[i] = this.UpdatePreviousNext!(entity, previous, next); + } + + // Return the resulting list. + return list; + } + } +} diff --git a/src/Nitride/Entities/README.md b/src/Nitride/Entities/README.md new file mode 100644 index 0000000..17f320b --- /dev/null +++ b/src/Nitride/Entities/README.md @@ -0,0 +1,188 @@ +# Entities + +Nitride is based on an Entity Component System (ECS) in the way it handles the +various input documents, images, feeds, and other parts that make up a website. +Implementing it this way makes it easier to create a distinction between the +different entities (much like Statiq.Web uses the DocumentType) +but allows for adding new components along the way without having the C# +limitations of a sealed enumeration or needing to implement a Javascript-style +enum for identification. Instead, if an entity needs to be identified as being +Markdown, an image, or a database query, it just adds a component to represent +that information. + +The basic entity is just a simple object with an internal identifier. These +entities are also immutable. Functions that appear to manipulate actually clone, +make the change, and then return the results. + +```c# +var entity = new Entity(); +Console.WriteLine("Entity Id: {0}", entity.Id); +``` + +## Components + +By itself, an entity doesn't have any meaning or purpose. These are described by +a generic collection of components that are added to the entity. Each component +has a type and then an instance of that type. These are added to the entity with +the `Add` command. If a type is not given, it is assumed to be the same type as +the parameter, but a base class or interface can be given to allow different +types to be stored in a specific component. + +In effect, the type of the component is the key. Having two different types, +even with the same object, would be considered two distinct objects. + +```c# +string mimeType = "text/plain"; +Entity entity = new Entity(); +Assert.Equal(0, entity.Count); + +Entity newEntity = entity.Add(mimeType); +Assert.Equal(0, entity.Count); +Assert.Equal(1, newEntity.Count); +Assert.Equal(entity.Id, newEntity.Id); +Assert.Equal(entity, newEntity); + +newEntity = newEntity.Add(mimeType); +Assert.Equal(2, newEntity.Count); +``` + +The basic operations for entity components are: + +- `Add(component)`: Adds a component as the given type. If there is + already a component there, an exception will be thrown. +- `Add(component)`: As `Add(component)` but the `TType` is the same as + `component.GetType()`. +- `Remove()`: Removes any component of the given type, if exists. If + there is no such component, then nothing happens. +- `Remove(component)`: Same as `Remove` with the component given + determining the `TType`. +- `Set(component)`: Adds or updates a component of the given type. +- `Set(component)`: Same as `Set` with the component given determining + the `TType`. +- `Copy()`: Creates a copy of the entity and assigns it a new identifier. +- `ExactCopy()`: Creates a copy of the entity with the same identifier. + +As above, all of these return a new entity (or the same one if no change is made +to the entity). + +### Query Components + +- `bool Has()`: Returns a value indicating whether the entity has the + given component type. +- `TType Get()`: Returns the value of the registered component. If there + is no such object, this will throw an exception. +- `TType? GetOptional()`: Returns the value of the registered component. + If there is no such object, this will return the default value. +- `bool TryGet(out TType component)`: Attempt to get the component. If it + cannot be retrieved, then this will return `false` and `component` is + undefined. + +## Collections + +To keep with the patterns of C#, working with collection of entities uses normal +LINQ operations. For example, to combine two sets of entities together, +the `Union` LINQ command can be used: + +```c# +IEnumerable entities1; +IEnumerable entities2; +IEnumerable all = entities1.Union(entities2); +``` + +To work with the ECS, additional extension methods have been written that allow +for filtering or working with those entities. + +### HasComponents + +The `HasComponents` is a set of overrides that checks to see if the given entity +has the requisite components. If they don't, then that entity is filtered out. + +```c# +IEnumerable entities; + +var filtered1 = entities.HasComponents(); +var filtered2 = entities.HasComponents(); +var filtered3 = entities.HasComponents(); +``` + +### NotComponents + +`NotComponents` is effectively the reverse of `HasComponents` in that if the +entity has the given components, they are filtered out. This also allows up to +three different components. + +This also allows the developer to ask for an entity that has two components but +not have a different of two with: + +```c# +IEnumerable entities; +var filtered = entities + .HasComponents() + .NotComonents(); +``` + +### ForComponents + +`ForComponents` allows for a lambda to be performed on entities that have the +given components while passing all the entities on through the function. This is +much like the `ForEach` combined with `Select` in that the changed or updated +entity will be passed on. + +```c# +var entities = new Entities[] +{ + new Entity().Add("value1"), + new Entity().Add(2), + new Entity().Add(3).Add("value2"), +}; +var filtered = entities + .ForComponents((entity, value) => entity.Set(value + "!")); + +Assert.Equal( + new[] { + "value1!", + null, + "value2!", + }, + filtered.Select(x => x.GetOptional())); +``` + +There are also three overloads allowing up to three components to be pulled out +with the lambda. + +### SetComponents, AddComponents, RemoveComponents + +`SetComponents` (as the corresponding `AddComponents`, and `RemoveComponents`) +basically perform the same operation on the entire list. They also have the +three overloads to allow one to three components be manipulated in a single +call. + +```c# +IEnumerable entities; +var updated = entities + .AddComponents(mimeType) + .AddComponents(mimeType) + .RemoveComponents() + .SetComponents(mimeType) + .SetComponent(mimeType); +``` + +### MergeEntities + +`MergeComponents` combines multiple entities together if they have the same `Id` +field. The two sides of the comparison are the presence of a specific component. + +```c# +IEnumerable entities; +var combined = entities + .MergeEntities( + (entity1, c1, entity2, c2) => entity1.Set(c2)); +``` + +## Files, Paths, and Content + +Entities do not have an integral concept of being a file or having contents from +the disk or anywhere else. Much of this is implemented as components from the +Nitride.IO assembly which uses [Zio](https://github.com/xoofx/zio) +for the underlying library, but can be easily replaced with a different IO +layer (or even the straight System.IO). diff --git a/src/Nitride/ExpressionHelper.cs b/src/Nitride/ExpressionHelper.cs new file mode 100644 index 0000000..96be6bc --- /dev/null +++ b/src/Nitride/ExpressionHelper.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace Nitride +{ + /// + /// Helper methods for getting the names of properties. + /// + public static class ExpressionHelper + { + public static string GetMemberName( + Expression> expression) + { + return GetMemberName(expression.Body); + } + + public static IEnumerable GetMemberNames( + params Expression>[] expressions) + { + return expressions + .Select(x => GetMemberName(x.Body)); + } + + public static IEnumerable GetMemberNames( + this T instance, + params Expression>[] expressions) + { + return GetMemberNames(expressions); + } + + private static string GetMemberName(Expression expression) + { + if (expression == null) + { + throw new ArgumentException(nameof(expression)); + } + + if (expression is MemberExpression memberExpression) + { + return memberExpression.Member.Name; + } + + if (expression is MethodCallExpression methodCallExpression) + { + return methodCallExpression.Method.Name; + } + + if (expression is UnaryExpression unaryExpression) + { + return GetMemberName(unaryExpression); + } + + throw new ArgumentException(nameof(expression)); + } + + private static string GetMemberName(UnaryExpression unaryExpression) + { + if (unaryExpression.Operand is MethodCallExpression + methodCallExpression) + { + return methodCallExpression.Method.Name; + } + + return ((MemberExpression)unaryExpression.Operand).Member.Name; + } + } +} diff --git a/src/Nitride/INitrideOperation.cs b/src/Nitride/INitrideOperation.cs new file mode 100644 index 0000000..c1d83a7 --- /dev/null +++ b/src/Nitride/INitrideOperation.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Gallium; + +namespace Nitride +{ + public interface INitrideOperation + { + /// + /// Runs the input entities through the operation and returns the results. + /// + /// + /// + IEnumerable Run(IEnumerable input); + } +} diff --git a/src/Nitride/Nitride.csproj b/src/Nitride/Nitride.csproj new file mode 100644 index 0000000..1c4e8d7 --- /dev/null +++ b/src/Nitride/Nitride.csproj @@ -0,0 +1,40 @@ + + + + net5.0 + enable + + + + A static site generator written using Gallium ECS. + + + + + + + + + + + + + + + + + + + + + True + + + + + Analyzer + False + + + + diff --git a/src/Nitride/NitrideBuilder.cs b/src/Nitride/NitrideBuilder.cs new file mode 100644 index 0000000..00dc5c7 --- /dev/null +++ b/src/Nitride/NitrideBuilder.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; +using Zio; +using Zio.FileSystems; + +namespace Nitride +{ + /// + /// A class that implements a builder pattern for gathering all the + /// components of a static website. Once everything is build, then calling + /// `Build()` will generate the resulting website. + /// + public class NitrideBuilder + { + private readonly string[] arguments; + + private readonly List> + configureContainerCallbacks; + + /// + /// An event that is called after the container is built but before + /// the application runs. + /// + private readonly List> + configureSiteCallbacks; + + private NitrideLoggingBuilder loggingBuilder; + + public NitrideBuilder(string[] arguments) + { + this.arguments = arguments; + this.loggingBuilder = new NitrideLoggingBuilder(); + this.configureSiteCallbacks = + new List>(); + this.configureContainerCallbacks = + new List>(); + } + + /// + /// Gets or sets the builder used to set up logging. + /// + /// + public NitrideLoggingBuilder LoggingBuilder + { + get => this.loggingBuilder; + set => this.loggingBuilder = + value ?? throw new ArgumentNullException(nameof(value)); + } + + /// + /// Gets or sets the input directory to automatically register as the + /// source of the files. If this is not set, then no Zio.IFileSystem + /// will be registered and it will have to be done manually. + /// + public DirectoryInfo? RootDirectory { get; set; } + + /// + /// Generates or builds the resulting website based on the given + /// command. + /// + /// The task once completed. + public async Task BuildAsync() + { + await Host + .CreateDefaultBuilder(this.arguments) + .UseSerilog() + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureServices(this.ConfigureServices) + .ConfigureContainer(this.ConfigureContainer) + .RunConsoleAsync(); + + return 0; + } + + /// + /// Allows for configuration of the Autofac container to register + /// additional types, pipelines, and modules. + /// + /// The callback to configure the container. + /// The builder to chain operations. + public NitrideBuilder ConfigureContainer( + Action callback) + { + this.configureContainerCallbacks.Add(callback); + return this; + } + + /// + /// Overrides the logging configuration for customization. + /// + /// + /// The builder to chain methods. + public NitrideBuilder ConfigureLogging( + Func callback) + { + this.loggingBuilder.Callback = callback; + return this; + } + + /// + /// Registers a callback to be called after the container is built but + /// before the application runs. + /// + /// The callback to register. + /// The builder for chaining. + public NitrideBuilder ConfigureSite( + Action callback) + { + this.configureSiteCallbacks.Add(callback); + return this; + } + + /// + /// Sets the root directory to a common value by creating a + /// IFileSystem (from Zio) of the root directory and registering it. + /// This will be used for both input and output. + /// + /// + /// The path to the directory that represents "/" while + /// building. + /// + /// The builder to chain calls. + public NitrideBuilder WithRootDirectory(DirectoryInfo directory) + { + this.RootDirectory = directory; + return this; + } + + private void ConfigureContainer(ContainerBuilder builder) + { + // We want to get logging up and running as soon as possible. We + // also hook up the logging to the process exit in an attempt to + // make sure the logger is properly flushed before exiting. + ILogger logger = this.loggingBuilder + .Setup(builder) + .ForContext(); + + AppDomain.CurrentDomain.ProcessExit += + (_, _) => Log.CloseAndFlush(); + + // Hook up the rest of the modules. + builder.RegisterModule(); + + // Set up our file system. + this.RegisterRootDirectory(logger, builder); + + // Finish up the registration by running our events. + foreach (var callback in this.configureSiteCallbacks) + { + builder.RegisterBuildCallback(scope => callback(this, scope)); + } + + foreach (var configureContainer in this.configureContainerCallbacks) + { + configureContainer.Invoke(builder); + } + } + + private void ConfigureServices(IServiceCollection services) + { + services.AddAutofac(); + services.AddHostedService(); + } + + private void RegisterRootDirectory( + ILogger logger, + ContainerBuilder builder) + { + if (this.RootDirectory == null) + { + logger.Verbose("No root directory is registered"); + return; + } + + logger.Debug( + "Setting root directory to {Path}", + this.RootDirectory.FullName); + + var rootFileSystem = new PhysicalFileSystem(); + var subFileSystem = new SubFileSystem( + rootFileSystem, + this.RootDirectory.FullName); + + builder.RegisterInstance(subFileSystem) + .As() + .SingleInstance(); + } + } +} diff --git a/src/Nitride/NitrideLoggingBuilder.cs b/src/Nitride/NitrideLoggingBuilder.cs new file mode 100644 index 0000000..53a8c66 --- /dev/null +++ b/src/Nitride/NitrideLoggingBuilder.cs @@ -0,0 +1,81 @@ +using System; +using Autofac; +using Serilog; +using Serilog.Core; +using Serilog.Events; + +namespace Nitride +{ + /// + /// The internal builder for setting up logging. + /// + public class NitrideLoggingBuilder + { + public NitrideLoggingBuilder() + { + this.LevelSwitch = new LoggingLevelSwitch(); + } + + /// + /// Used when the user uses .ConfigureLogging() to configure the logger + /// instead of overriding the function. + /// + public Func? Callback { get; set; } + + /// + /// Gets the level switch used to control the logging verbosity from + /// the command-line. + /// + public virtual LoggingLevelSwitch LevelSwitch { get; } + + /// + /// Sets up logging and registers it under Serilog.ILogger in the + /// container. + /// + /// The Autofac builder for the container. + /// The logger configured during the setup. + public virtual ILogger Setup(ContainerBuilder builder) + { + // Figure out how we are going to configure the logger. + var configuration = new LoggerConfiguration(); + + // Create the logger and register it into the builder. + ILogger logger = this.Callback?.Invoke(configuration) + ?? this.CreateLogger(configuration); + + builder + .RegisterInstance(logger) + .As() + .SingleInstance(); + builder + .RegisterInstance(this.LevelSwitch) + .AsSelf() + .SingleInstance(); + + return logger; + } + + /// + /// Creates a Serilog.ILogger and returns the resulting logger to be + /// used within the system. This is one of the more common places to + /// customize logging. + /// + /// + /// + protected virtual ILogger CreateLogger( + LoggerConfiguration configuration) + { + const string Template = + "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] " + + "({SourceContext}) {Message}" + + "{NewLine}{Exception}"; + + return configuration + .MinimumLevel.ControlledBy(this.LevelSwitch) + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .Enrich.FromLogContext() + .WriteTo.Console(outputTemplate: Template) + .CreateLogger(); + } + } +} diff --git a/src/Nitride/NitrideModule.cs b/src/Nitride/NitrideModule.cs new file mode 100644 index 0000000..4677ec6 --- /dev/null +++ b/src/Nitride/NitrideModule.cs @@ -0,0 +1,29 @@ +using Autofac; +using Nitride.Entities; +using Nitride.Pipelines; + +namespace Nitride +{ + public class NitrideModule : Module + { + /// + protected override void Load(ContainerBuilder builder) + { + builder + .RegisterAssemblyTypes(this.GetType().Assembly) + .Except() + .Except() + .AsSelf() + .AsImplementedInterfaces() + .SingleInstance(); + + builder + .RegisterType() + .AsSelf(); + + builder + .RegisterGeneric(typeof(CreateIndexEntities<>)) + .As(typeof(CreateIndexEntities<>)); + } + } +} diff --git a/src/Nitride/NitrideModuleBase.cs b/src/Nitride/NitrideModuleBase.cs new file mode 100644 index 0000000..390530f --- /dev/null +++ b/src/Nitride/NitrideModuleBase.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Autofac; +using Nitride.Registration; +using Module = Autofac.Module; + +namespace Nitride +{ + /// + /// Common functionality for Nitride modules. + /// + public abstract class NitrideModuleBase : Module + { + private static readonly HashSet Initialized = new(); + + /// + protected sealed override void Load(ContainerBuilder builder) + { + // We need to allow a module to be registered multiple times because + // some modules will force inclusion of their requirements which the + // user may also add. + Type type = this.GetType(); + Assembly assembly = type.Assembly; + string typeKey = type.FullName!; + + if (Initialized.Contains(typeKey)) + { + return; + } + + Initialized.Add(typeKey); + + // Register the common types. + builder + .RegisterAssemblyTypes(assembly) + .Where(CanRegister) + .Where(IsNotSingleton) + .AsSelf() + .AsImplementedInterfaces(); + + builder + .RegisterAssemblyTypes(assembly) + .Where(CanRegister) + .Where(IsSingleton) + .AsSelf() + .AsImplementedInterfaces() + .SingleInstance(); + + this.Register(builder); + } + + /// + /// Perform additional registrations after the common one. + /// + /// The builder to configure. + protected virtual void Register(ContainerBuilder builder) + { + } + + private static bool CanRegister(Type x) + { + return x.GetCustomAttribute() == null; + } + + private static bool IsNotSingleton(Type x) + { + return x.GetCustomAttribute() == null; + } + + private static bool IsSingleton(Type x) + { + return !IsNotSingleton(x); + } + } +} diff --git a/src/Nitride/NitrideOperationBase.cs b/src/Nitride/NitrideOperationBase.cs new file mode 100644 index 0000000..29a8074 --- /dev/null +++ b/src/Nitride/NitrideOperationBase.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Gallium; + +namespace Nitride +{ + /// + /// Contains common functionality useful for Nitride operations. + /// + public abstract class NitrideOperationBase : INitrideOperation + { + /// + /// A method that makes sure a property is set with a useful message. + /// If the value is not null, then no exception is thrown. + /// + /// The name of the property. + /// The object to check for null. + /// Thrown if the parameter is null. + public void CheckNotNull(string name, object? parameter) + { + if (parameter == null) + { + throw new InvalidOperationException( + this.GetType().Name + + " did not have the " + + name + + " property set before calling Run(). Set this via the " + + name + + "property or by calling Set" + + name + + "."); + } + } + + /// + public abstract IEnumerable Run(IEnumerable input); + } +} diff --git a/src/Nitride/NitrideOperationBaseExtensions.cs b/src/Nitride/NitrideOperationBaseExtensions.cs new file mode 100644 index 0000000..3949852 --- /dev/null +++ b/src/Nitride/NitrideOperationBaseExtensions.cs @@ -0,0 +1,21 @@ +using System; +using System.Linq.Expressions; + +namespace Nitride +{ + public static class NitrideOperationBaseExtensions + { + public static void CheckNotNull( + this TType instance, + Expression> expression) + where TType : NitrideOperationBase + { + // We can't implement this inside the class because of C# + // limitations. + string name = ExpressionHelper.GetMemberName(expression); + object? value = expression.Compile()(instance); + + instance.CheckNotNull(name, value); + } + } +} diff --git a/src/Nitride/NitrideOperationExtensions.cs b/src/Nitride/NitrideOperationExtensions.cs new file mode 100644 index 0000000..080e609 --- /dev/null +++ b/src/Nitride/NitrideOperationExtensions.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Gallium; + +namespace Nitride +{ + /// + /// Extension methods to run a Nitride operation inline with code. + /// + public static class NitrideOperationExtensions + { + /// + /// Runs the given configured operation against the input and returns + /// the results. + /// + /// The entities to perform the operation against. + /// The operation to run. + /// The results of the operation. + public static IEnumerable Run( + this IEnumerable input, + INitrideOperation operation) + { + return operation.Run(input); + } + } +} diff --git a/src/Nitride/NitrideService.cs b/src/Nitride/NitrideService.cs new file mode 100644 index 0000000..f5c1723 --- /dev/null +++ b/src/Nitride/NitrideService.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.CommandLine.Parsing; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using Nitride.Commands; +using Serilog; +using Serilog.Core; +using Serilog.Events; + +namespace Nitride +{ + /// + /// Implements the command-line shell for generating the static site. + /// + public class NitrideService : IHostedService + { + private readonly IList commands; + + private readonly IHostApplicationLifetime lifetime; + + private readonly Option logEventLevelOption; + + private readonly ILogger logger; + + private readonly LoggingLevelSwitch loggingLevelSwitch; + + private int exitCode; + + public NitrideService( + ILogger logger, + IHostApplicationLifetime lifetime, + IList commands, + LoggingLevelSwitch loggingLevelSwitch) + { + this.lifetime = lifetime; + this.commands = commands; + this.loggingLevelSwitch = loggingLevelSwitch; + this.logger = logger.ForContext(); + + this.logEventLevelOption = new Option( + "--log-level", + () => LogEventLevel.Information, + "Controls the verbosity of the output"); + } + + /// + public Task StartAsync(CancellationToken cancellationToken) + { + this.lifetime.ApplicationStarted + .Register( + () => + { + Task.Run( + async () => { await this.RunAsync(); }, + cancellationToken); + }); + + return Task.CompletedTask; + } + + /// + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + private RootCommand CreateRootCommand() + { + // Create the root command and add in the top-level commands + // underneath it. + var root = new RootCommand(); + + foreach (var command in this.commands) + { + root.AddCommand((Command)command); + } + + // Add the universal options. + root.AddGlobalOption(this.logEventLevelOption); + + // Return the resulting container. + return root; + } + + private async Task RunAsync() + { + try + { + // Build the command tree. + RootCommand root = this.CreateRootCommand(); + string[] args = Environment.GetCommandLineArgs(); + + // Parse the results so we can pull out our globals. + ParseResult results = root.Parse(args); + LogEventLevel logEventLevel = results + .ValueForOption(this.logEventLevelOption); + + this.loggingLevelSwitch.MinimumLevel = logEventLevel; + + // Execute the command. + this.logger.Verbose("Running the command-line arguments"); + this.exitCode = await root.InvokeAsync(args); + } + catch (Exception exception) + { + this.logger.Error( + exception, + "Unhandled exception!"); + } + finally + { + // Stop the application once the work is done. + this.lifetime.StopApplication(); + } + } + } +} diff --git a/src/Nitride/Pipelines/IPipeline.cs b/src/Nitride/Pipelines/IPipeline.cs new file mode 100644 index 0000000..8dc069e --- /dev/null +++ b/src/Nitride/Pipelines/IPipeline.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Gallium; + +namespace Nitride.Pipelines +{ + /// + /// Implements the basic signature for a pipeline, a distinct unit of + /// processing that reads, manipulates, and writes data. + /// + public interface IPipeline + { + /// + /// Gets the dependencies for the pipeline. + /// + IEnumerable GetDependencies(); + + /// + /// Performs various operations such as reading, writing, and + /// transformation on the given entities before returning a new + /// collection, which may or may not include some of the original + /// entities. + /// + /// The entities to process. + /// The resulting entities after the process runs. + Task> RunAsync(IEnumerable entities); + } +} diff --git a/src/Nitride/Pipelines/PipelineBase.cs b/src/Nitride/Pipelines/PipelineBase.cs new file mode 100644 index 0000000..889fce7 --- /dev/null +++ b/src/Nitride/Pipelines/PipelineBase.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Gallium; + +namespace Nitride.Pipelines +{ + /// + /// A basic pipeline that is configured through properties and methods. + /// + public abstract class PipelineBase : IPipeline + { + private readonly List dependencies; + + protected PipelineBase() + { + this.dependencies = new List(); + } + + public PipelineBase AddDependency(IPipeline pipeline) + { + this.dependencies.Add(pipeline); + return this; + } + + /// + public IEnumerable GetDependencies() + { + return this.dependencies; + } + + /// + public abstract Task> RunAsync( + IEnumerable entities); + + /// + public override string ToString() + { + return this.GetType().Name; + } + } +} diff --git a/src/Nitride/Pipelines/PipelineManager.cs b/src/Nitride/Pipelines/PipelineManager.cs new file mode 100644 index 0000000..5cf2974 --- /dev/null +++ b/src/Nitride/Pipelines/PipelineManager.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Humanizer; +using Serilog; + +namespace Nitride.Pipelines +{ + /// + /// A manager class for all of the pipelines. This class is responsible for + /// hooking everything up and handling the ordering of pipelines as they + /// are run. + /// + public class PipelineManager + { + private readonly PipelineRunner.Factory createEntry; + + private readonly ILogger logger; + + private List entries; + + private bool isSetup; + + private ICollection pipelines; + + public PipelineManager( + ILogger logger, + IEnumerable pipelines, + PipelineRunner.Factory createEntry) + { + this.createEntry = createEntry; + this.logger = logger.ForContext(); + this.pipelines = new HashSet(pipelines); + this.entries = null!; + } + + public ICollection Pipelines + { + get => this.pipelines; + set => this.pipelines = + value ?? throw new ArgumentNullException(nameof(value)); + } + + /// + /// Runs all of the pipelines in the appropriate order while running + /// across multiple threads. + /// + /// A task with zero for success or otherwise an error code. + public Task RunAsync() + { + // Make sure everything is setup. + DateTime started = DateTime.UtcNow; + + if (!this.Setup()) + { + return Task.FromResult(1); + } + + // Go through all the entries and start each one. We gather the + // resulting tasks and then wait for all of them to end. + this.logger.Verbose( + "Starting {Count:l}", + "pipeline".ToQuantity(this.pipelines.Count)); + + Task[] tasks = this.entries + .Select(x => Task.Run(async () => await x.RunAsync())) + .ToArray(); + TimeSpan report = TimeSpan.FromSeconds(15); + + while (!Task.WaitAll(tasks, report)) + { + List? waiting = this + .entries.Where(x => !x.IsFinished) + .ToList(); + + this.logger.Debug( + "Waiting for {Count:l} to finish running", + "pipeline".ToQuantity(waiting.Count)); + + IOrderedEnumerable< + IGrouping> states = + waiting + .GroupBy(x => x.State, x => x) + .OrderBy(x => (int)x.Key); + + foreach (var state in states) + { + List statePipelines = state + .OrderBy(x => x.Pipeline.ToString()) + .ToList(); + + this.logger.Verbose( + "Waiting for {Count:l} in {State}: {List:l}", + "pipeline".ToQuantity(statePipelines.Count), + state.Key, + string.Join( + ", ", + state.Key == PipelineRunnerState.Started + ? statePipelines + .Select( + x => + $"{x.Pipeline} ({x.ElapsedFromState})") + : statePipelines + .Select(x => x.Pipeline.ToString()))); + } + } + + // Figure out our return code. + bool hasErrors = this.entries + .Any(x => x.State == PipelineRunnerState.Errored); + + this.logger.Information( + "Completed in {Elapsed}", + DateTime.UtcNow - started); + + return Task.FromResult(hasErrors ? 2 : 0); + } + + /// + /// Performs the final initialization and preparation for the pipelines + /// and get them ready for deploying. + /// + private bool Setup() + { + // If we've already set up ourselves, then we do nothing. + if (this.isSetup) + { + return true; + } + + // If we don't have any pipelines, then we can't process. + if (this.pipelines.Count == 0) + { + this.logger.Error( + "There are no registered pipelines run, use" + + " ConfigureContainer to include IPipeline instances"); + + return false; + } + + this.logger.Verbose( + "Setting up {Count:l}", + "pipeline".ToQuantity(this.pipelines.Count)); + + // Wrap all the pipelines into entries. We do this before the next + // step so we can have the entries depend on the entries. + this.entries = this.pipelines + .Select(x => this.createEntry(x)) + .ToList(); + + // Go through and connect the pipelines together. + foreach (var entry in this.entries) + { + List dependencies = entry.Pipeline + .GetDependencies() + .ToList(); + + foreach (var dependency in dependencies) + { + // Get the entry for the dependency. + PipelineRunner dependencyPipeline = this.entries + .Single(x => x.Pipeline == dependency); + + // Set up the bi-directional connection. + entry.Incoming.Add(dependencyPipeline); + dependencyPipeline.Outgoing.Add(entry); + } + } + + // Loop through all the entries and tell them we are done providing + // and they can set up internal threads other structures. + foreach (var entry in this.entries) + { + entry.Initialize(); + } + + // We have run successfully. + this.isSetup = true; + + return true; + } + } +} diff --git a/src/Nitride/Pipelines/PipelineRunner.cs b/src/Nitride/Pipelines/PipelineRunner.cs new file mode 100644 index 0000000..c938aea --- /dev/null +++ b/src/Nitride/Pipelines/PipelineRunner.cs @@ -0,0 +1,376 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Gallium; +using Humanizer; +using Serilog; + +namespace Nitride.Pipelines +{ + /// + /// A wrapper class to handle a pipeline along with various methods for + /// tracking the operation of the pipeline and thread coordination. + /// + /// + /// This is intended to only be used within a PipelineManager and there + /// should be little reason to use or extend this class. + /// + public class PipelineRunner + { + /// + /// The manual reset event used to coordinate thread operations. + /// + private readonly ManualResetEventSlim blockDependencies; + + /// + /// A manual reset event to tell the thread when consumers are done. + /// + private readonly ManualResetEventSlim consumersDone; + + private readonly ILogger logger; + + private DateTime changed; + + private bool signaledDoneWithInputs; + + private DateTime started; + + /// + /// Contains the number of consumers we're currently waiting to finish + /// processing. + /// + private int waitingOnConsumers; + + public PipelineRunner( + ILogger logger, + IPipeline pipeline) + { + this.Pipeline = pipeline + ?? throw new ArgumentNullException(nameof(pipeline)); + this.Incoming = new List(); + this.Outgoing = new List(); + this.Outputs = new List(); + this.logger = logger.ForContext(); + this.blockDependencies = new ManualResetEventSlim(false); + this.consumersDone = new ManualResetEventSlim(false); + this.started = DateTime.Now; + this.changed = DateTime.Now; + } + + /// + /// Public factory method for creating a new pipeline manager entry. + /// + public delegate PipelineRunner Factory(IPipeline pipeline); + + public TimeSpan ElapsedFromInitialized => DateTime.Now - this.started; + + public TimeSpan ElapsedFromState => DateTime.Now - this.changed; + + /// + /// A collection of incoming entries that produce data for the pipeline. + /// + public ICollection Incoming { get; } + + /// + /// Gets a value indicating whether the output of this entry is not + /// used by any other pipeline. + /// + public bool IsFinal => this.Outgoing.Count == 0; + + /// + /// Gets a value indicating whether this pipeline is done running. + /// + public bool IsFinished => this.State + is PipelineRunnerState.Finalized + or PipelineRunnerState.Errored; + + /// + /// Gets a value indicating whether this entry is a starting one + /// that consumes no data. + /// + public bool IsStarting => this.Incoming.Count == 0; + + /// + /// The collection of outgoing entries that consume the results of + /// the pipeline in this entry. + /// + public ICollection Outgoing { get; } + + /// + /// Contains the list of all the outputs from this pipeline. This is + /// only ensured to be valid after the pipeline is in the `Providing` + /// state. + /// + public List Outputs { get; } + + /// + /// The pipeline associated with the entry. + /// + public IPipeline Pipeline { get; } + + /// + /// Gets the current state of the pipeline. + /// + public PipelineRunnerState State { get; private set; } + + /// + /// A method that tells the pipeline that one of the dependencies has + /// completed consuming the input. + /// + public void ConsumerDoneWithOutputs() + { + int current = Interlocked.Decrement(ref this.waitingOnConsumers); + + this.logger.Verbose( + "{Pipeline:l}: Consumer signalled, waiting for {Count:n0}", + this.Pipeline, + current); + + if (current == 0) + { + this.consumersDone.Set(); + } + } + + /// + /// Initializes the runner after all external properties have been + /// set and configured. + /// + public void Initialize() + { + this.ChangeState(PipelineRunnerState.Initialized); + } + + /// + /// Executes the pipeline, including waiting for any or all + /// dependencies. + /// + public async Task RunAsync() + { + try + { + // Make sure we have a valid state. + switch (this.State) + { + case PipelineRunnerState.Initialized: + case PipelineRunnerState.Finalized: + break; + + default: + this.logger.Error( + "{Pipeline:l}: Pipeline cannot be started in a {State}" + + " state (not Initialized or Finalized)", + this.Pipeline, + this.State); + break; + } + + // Prepare ourselves for running. We have a start/stop state because + // this may be non-zero time. + this.started = DateTime.Now; + this.changed = DateTime.Now; + this.ChangeState(PipelineRunnerState.Preparing); + this.signaledDoneWithInputs = false; + this.ChangeState(PipelineRunnerState.Prepared); + + // Go through the incoming and wait for each of the manual resets + // on the dependency pipelines. + if (this.WaitForDependencies()) + { + this.SignalDoneWithInputs(); + return; + } + + // Grab the outputs from the incoming. They will be populated + // because we have waited for the reset events. + this.ChangeState(PipelineRunnerState.Started); + List input = this.GatherDependencyOutputs(); + + // Run the pipeline. This may not be resolved until we gather + // the output below. + await this.RunPipeline(input); + + // At this point, we are completely done with our inputs, so signal + // to them in case they have to clean up any of their structures. + this.SignalDoneWithInputs(); + + // If we have outgoing runners, provide them data until they are + // done. + this.SendToDependants(); + + // Finalize ourselves. + this.ChangeState(PipelineRunnerState.Finalized); + } + catch (Exception exception) + { + // Report the exception. + this.logger.Error( + exception, + "{Pipeline:l}: There was an exception running pipeline", + this.Pipeline); + + // Change our state and then release any pipeline waiting for us + // so they can pick up the error and fail themselves. + this.ChangeState(PipelineRunnerState.Errored); + this.blockDependencies.Set(); + this.SignalDoneWithInputs(); + } + } + + /// + /// A method to block the call until this runner is done processing and + /// is ready to provide output. + /// + public void WaitUntilProviding() + { + this.blockDependencies.Wait(); + } + + /// + /// Changes the state of the pipeline into a new state. + /// + /// The state to change the pipeline into. + private void ChangeState(PipelineRunnerState newState) + { + this.logger.Verbose( + "{Pipeline:l}: Switching from state {Old} to {New} (elapsed {Elapsed}, duration {Duration})", + this.Pipeline, + this.State, + newState, + this.ElapsedFromInitialized, + this.ElapsedFromState); + this.changed = DateTime.Now; + this.State = newState; + } + + private List GatherDependencyOutputs() + { + if (this.Incoming.Count <= 0) + { + return new List(); + } + + // Report that we are gathering our outputs. + this.logger.Verbose( + "{Pipeline:l}: Gathering outputs from {Count:n0} dependencies", + this.Pipeline, + this.Incoming.Count); + + List input = this.Incoming + .SelectMany(x => x.Outputs) + .ToList(); + + this.logger.Debug( + "{Pipeline:l}: Got {Count:l} from dependencies", + this.Pipeline, + "entity".ToQuantity(input.Count, "N0")); + + return input; + } + + private async Task RunPipeline(List input) + { + IEnumerable + output = await this.Pipeline.RunAsync(input); + + // Gather all the output. + this.logger.Debug( + "{Pipeline:l}: Gathering output", + this.Pipeline); + this.Outputs.Clear(); + this.Outputs.AddRange(output); + } + + private void SendToDependants() + { + if (this.Outgoing.Count <= 0) + { + return; + } + + // Make sure our internal wait for the consumers it set. + this.logger.Verbose( + "{Pipeline:l}: Setting up internal thread controls", + this.Pipeline); + this.waitingOnConsumers = this.Outgoing.Count; + this.consumersDone.Reset(); + + // Report how many files we're sending out and then use manual + // reset and the semaphore to control the threads. + this.logger.Debug( + "{Pipeline:l}: Output {Count:l} from pipeline", + this.Pipeline, + "entity".ToQuantity(this.Outputs.Count, "N0")); + + // Release our manual reset to allow operations to continue. + this.ChangeState(PipelineRunnerState.Providing); + this.logger.Verbose( + "{Pipeline:l}: Release manual reset for consumers", + this.Pipeline); + this.blockDependencies.Set(); + + // Wait until all consumers have finished processing. + this.consumersDone.Wait(); + } + + private void SignalDoneWithInputs() + { + if (this.Incoming.Count <= 0 || this.signaledDoneWithInputs) + { + return; + } + + this.signaledDoneWithInputs = true; + + this.logger.Debug( + "{Pipeline:l}: Signaling {Count:n0} dependencies done", + this.Pipeline, + this.Incoming.Count); + + foreach (var dependency in this.Incoming) + { + dependency.ConsumerDoneWithOutputs(); + } + } + + private bool WaitForDependencies() + { + if (this.Incoming.Count <= 0) + { + return false; + } + + // Wait for the dependencies to run first. + this.ChangeState(PipelineRunnerState.Waiting); + this.logger.Verbose( + "{Pipeline:l}: Waiting for {Count:l} to complete", + this.Pipeline, + "dependency".ToQuantity(this.Incoming.Count)); + + foreach (var dependency in this.Incoming) + { + dependency.WaitUntilProviding(); + } + + // Check for any error state in the dependency, if we have one, + // then we need to stop ourselves. + bool hasError = this.Incoming + .Any(x => x.State == PipelineRunnerState.Errored); + + if (!hasError) + { + return false; + } + + this.logger.Error( + "{Pipeline:l}: There was an exception in an dependency", + this.Pipeline); + this.ChangeState(PipelineRunnerState.Errored); + this.blockDependencies.Set(); + + return true; + } + } +} diff --git a/src/Nitride/Pipelines/PipelineRunnerState.cs b/src/Nitride/Pipelines/PipelineRunnerState.cs new file mode 100644 index 0000000..3d67e03 --- /dev/null +++ b/src/Nitride/Pipelines/PipelineRunnerState.cs @@ -0,0 +1,72 @@ +namespace Nitride.Pipelines +{ + /// + /// Describes the state of the pipelines which is used both for reporting + /// purposes but also to allow the pipelines to respond to changes in their + /// own state, such as unloading output elements. + /// + public enum PipelineRunnerState + { + /// + /// Indicates that the runner is setting up and not ready for any use. + /// + Initializing, + + /// + /// Indicates that the runner has been initialized. + /// + Initialized, + + /// + /// Indicates that the pipeline is prepare for a new run. This is done + /// when the system determines it needs to run. + /// + Preparing, + + /// + /// Indicates that the pipeline has finished preparing. + /// + Prepared, + + /// + /// Indicates that the runner is waiting for dependencies to run. + /// + Waiting, + + /// + /// Indicates that the pipeline has started processing by a call to + /// `RunAsync`. + /// + Started, + + /// + /// Indicates that the pipeline is providing data to any dependencies. + /// If the pipeline has no dependencies, then this will never be called. + /// + Providing, + + /// + /// Indicates that all the dependencies on this pipeline has finished + /// running (state `Finished`) and the pipeline can clean up any + /// memory elements. + /// + Provided, + + /// + /// Indicates that the pipeline is done running and the system is + /// shutting down. + /// + Finalizing, + + /// + /// Indicates that the pipeline has been completely cleaned up and + /// finished. It will never be used again. + /// + Finalized, + + /// + /// Indicates that there was an error while running the pipeline. + /// + Errored, + } +} diff --git a/src/Nitride/Pipelines/README.md b/src/Nitride/Pipelines/README.md new file mode 100644 index 0000000..9b3ba7a --- /dev/null +++ b/src/Nitride/Pipelines/README.md @@ -0,0 +1,191 @@ +# Pipelines + +A pipeline is a set of operations that take an input of entities, performs +various operations and transformations on them, and then returns a resulting +list of entities which may or may not be the original ones. For pipelines that +read files from the disk, the input may be empty. The output from the final +pipelines may never be used. + +A simple pipeline may: + +1. Load all the Markdown files to a disk. +2. Convert the files into HTML. +3. Write them out to a different location. + +A pipeline implements the `IPipeline` interface or extends the convenience +class `Pipeline`. + +```c# +using Nitride.Pipelines; + +public class LoadFilesPipeline : Pipeline {} +``` + +## Dependencies + +Pipelines can be chained from another pipeline or from multiple pipelines. This +chaining may be for organization purposes or the output from one pipeline may +end up being fed into multiple pipelines. A pipeline may have 0-n pipelines it +depends on. + +```c# +var loadPipeline = new Pipeline(); +var htmlPipeline = new Pipeline().AddDependency(loadPipeline); +var geminiPipeline = new GeminiPipeline(loadPipeline); + +public class GeminiPipeline : Pipeline +{ + public GeminiPipeline(Pipeline loadPipeline) + { + this.AddDependency(loadPipeline); + } +} +``` + +Since Nitride is built around dependency injection, the constructor is the place +where the dependencies are typically set up. + +```c# +ContainerBuilder builder; + +builder.RegisterInstance().AsSelf(); +builder.RegisterInstance().AsSelf(); + +IContainer container = builder.Build(); + +var loadPipeline = new Pipeline(); +var geminiPipeline = container.Resolve(); + +public class GeminiPipeline : Pipeline +{ + public GeminiPipeline(LoadPipeline loadPipeline) + { + this.AddDependency(loadPipeline); + } +} +``` + +With the dependencies, pipelines are assumed to be directional, acyclic graph +(DAG). This means that there are no circular dependencies and the code can +determine the "entry" pipelines that will feed into the others until the +processes are complete. + +The DAG is also used to determine what is rebuilt during development. Only +pipelines affected (including dependencies) by a change will be re-run to keep +the process running as quickly as possible. + +### Processing + +The primary purpose of the pipeline is to process the entites. This method is +rather simple: + +```c# +public async Task> RunAsync( + IEnumerable entities) +{ + return entities; +} +``` + +(For purposes of this document, `async` is added to all the methods even if the +example would be better suited without it and using `Task.FromResult()` +instead.) + +### Identifying Source Pipeline + +Because of how entities are passed around, a pipeline that depends on two other +ones may have the same entity in both streams. Without any alteration, this will +result in duplicate entities with no ability to determine which entity came from +which pipeline. + +To mark an entity as being processed by a pipeline, a simple component can be +added as needed using the `AddComponents` extension method on the collection to +add the pipeline or some other indicator. + +```c# +public class ExamplePipeline : Pipeline +{ + public async Task> RunAsync(IEnumerable entities) + { + return entities + .AddComponents(this); + } +} +``` + +With the entity identified with the pipeline as a component, special processing +can be easily used. In addition, the `MergeEntities` can be used to pull +entities of the same identifier together. + +```c# +public class Pipeline1 : Pipeline +{ + public async Task> RunAsync(IEnumerable entities) + { + return LoadFileEntities(); + } +} + +public class Pipeline2 : Pipeline +{ + public Pipeline2(Pipeline1 pipeline) + { + this.AddDependency(pipeline); + } + + public async Task> RunAsync(IEnumerable entities) + { + return entities + .AddComponents(this); + } +} + +public class Pipeline3 : Pipeline +{ + public Pipeline3(Pipeline1 pipeline) + { + this.AddDependency(pipeline); + } + + public async Task> RunAsync(IEnumerable entities) + { + return entities + .AddComponents(this); + } +} + +public class Pipeline4 : Pipeline +{ + public Pipeline4(Pipeline2 pipeline2, Pipeline3 pipeline3) + { + this.AddDependency(pipeline2); + this.AddDependency(pipeline3); + } + + public async Task> RunAsync(IEnumerable entities) + { + return entities + .ForComponents((entity, pipeline2) => ...) + .ForComponents((entity, pipeline3) => ...) + .MergeComponents( + (entity1, entity2) => entity1.Merge(entity2)); + } +} +``` + +## Concurrency + +Pipelines will run in multiple threads, but will wait on their dependencies. +This means two pipelines with separate inputs will run at the same time, but a +pipeline that depends on one or more other pipelines will wait until their +dependencies have finished running before starting. + +Inside a pipeline, the code determines what operations are done concurrently. +Using PLINQ or various await methods can be used in this case. However, even if +a pipeline is synchronized, the process is always treated as async and will be +awaited. + +## Inspiration + +The concept of a pipeline has been inspired by both Statiq and also work done on +CobblestoneJS (the gather, prepare, and process approach). diff --git a/src/Nitride/ROADMAP.md b/src/Nitride/ROADMAP.md new file mode 100644 index 0000000..b5b2761 --- /dev/null +++ b/src/Nitride/ROADMAP.md @@ -0,0 +1,9 @@ +# Project Roadmap + +## Immediate + +- Switch the various operations to be async + - ReadFiles + - WriteFiles +- Implement mime type determination +- Implement a convert to text content based on mime type diff --git a/src/Nitride/Registration/NoRegistrationAttribute.cs b/src/Nitride/Registration/NoRegistrationAttribute.cs new file mode 100644 index 0000000..63b1b9f --- /dev/null +++ b/src/Nitride/Registration/NoRegistrationAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Nitride.Registration +{ + [AttributeUsage(AttributeTargets.Class)] + public class NoRegistrationAttribute : Attribute + { + } +} diff --git a/src/Nitride/Registration/SingletonAttribute.cs b/src/Nitride/Registration/SingletonAttribute.cs new file mode 100644 index 0000000..46612be --- /dev/null +++ b/src/Nitride/Registration/SingletonAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Nitride.Registration +{ + [AttributeUsage(AttributeTargets.Class)] + public class SingletonAttribute : Attribute + { + } +} diff --git a/src/Nitride/WithPropertiesAttribute.cs b/src/Nitride/WithPropertiesAttribute.cs new file mode 100644 index 0000000..ea7a325 --- /dev/null +++ b/src/Nitride/WithPropertiesAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace Nitride +{ + /// + /// A marker attribute that indicates that the source generator should + /// automatically add `Set*` methods for every public property in the class. + /// The class must be `partial` for this to work. + /// + [AttributeUsage(AttributeTargets.Class)] + public class WithPropertiesAttribute : Attribute + { + } +}