diff --git a/src/Our.Umbraco.FullTextSearch.SchemaGenerator/AppSettings.cs b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/AppSettings.cs
new file mode 100644
index 0000000..8c8a923
--- /dev/null
+++ b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/AppSettings.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Our.Umbraco.FullTextSearch.Options;
+
+namespace Our.Umbraco.FullTextSearch.SchemaGenerator
+{
+ internal class AppSettings
+ {
+ public UmbracoDefinition Umbraco { get; set; }
+
+ ///
+ /// Configuration of settings
+ ///
+ internal class UmbracoDefinition
+ {
+ ///
+ /// FullTextSearch settings
+ ///
+ public FullTextSearchOptions FullTextSearch { get; set; }
+
+ }
+ }
+
+}
diff --git a/src/Our.Umbraco.FullTextSearch.SchemaGenerator/Options.cs b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/Options.cs
new file mode 100644
index 0000000..3c0aa26
--- /dev/null
+++ b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/Options.cs
@@ -0,0 +1,12 @@
+using CommandLine;
+
+namespace Our.Umbraco.FullTextSearch.SchemaGenerator
+{
+ internal class Options
+ {
+ [Option('o', "outputFile", Required = false,
+ HelpText = "",
+ Default = "Our.Umbraco.FullTextSearch\\appsettings-schema.umbraco-fulltextsearch.json")]
+ public string OutputFile { get; set; }
+ }
+}
diff --git a/src/Our.Umbraco.FullTextSearch.SchemaGenerator/Our.Umbraco.FullTextSearch.SchemaGenerator.csproj b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/Our.Umbraco.FullTextSearch.SchemaGenerator.csproj
new file mode 100644
index 0000000..bc2a752
--- /dev/null
+++ b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/Our.Umbraco.FullTextSearch.SchemaGenerator.csproj
@@ -0,0 +1,27 @@
+
+
+
+ Exe
+ net7.0
+
+
+
+
+
+
+
+
+
+
+
+
+ bin\Release\$(TargetFramework)\Our.Umbraco.FullTextSearch.SchemaGenerator.xml
+
+
+
+
+
+
+
+
+
diff --git a/src/Our.Umbraco.FullTextSearch.SchemaGenerator/Program.cs b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/Program.cs
new file mode 100644
index 0000000..64f053b
--- /dev/null
+++ b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/Program.cs
@@ -0,0 +1,46 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using CommandLine;
+
+using NPoco.fastJSON;
+
+namespace Our.Umbraco.FullTextSearch.SchemaGenerator
+{
+ ///
+ /// Generate the JSON Schema file for Full Text Search.
+ /// just like in the Umbraco Core - https://github.com/umbraco/Umbraco-CMS/tree/v9/contrib/src/JsonSchema
+ /// #h5yr Kevin Jump!
+ ///
+ internal class Program
+ {
+ public static async Task Main(string[] args)
+ {
+ try
+ {
+ await Parser.Default.ParseArguments(args)
+ .WithParsedAsync(Execute);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ throw;
+ }
+ }
+
+ private static async Task Execute(Options options)
+ {
+ var generator = new SchemaGenerator();
+
+ var schema = generator.Generate();
+
+ var path = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, options.OutputFile));
+ Console.WriteLine("Path to use {0}", path);
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+ Console.WriteLine("Ensured directory exists");
+ await File.WriteAllTextAsync(path, schema);
+
+ Console.WriteLine("File written at {0}", path);
+ }
+ }
+}
diff --git a/src/Our.Umbraco.FullTextSearch.SchemaGenerator/SchemaGenerator.cs b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/SchemaGenerator.cs
new file mode 100644
index 0000000..3c7368f
--- /dev/null
+++ b/src/Our.Umbraco.FullTextSearch.SchemaGenerator/SchemaGenerator.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Serialization;
+
+using NJsonSchema.Generation;
+
+namespace Our.Umbraco.FullTextSearch.SchemaGenerator
+{
+ internal class SchemaGenerator
+ {
+ private readonly JsonSchemaGenerator _schemaGenerator;
+
+ public SchemaGenerator()
+ {
+ _schemaGenerator = new JsonSchemaGenerator(
+ new FullTextSearchSchemaGeneratorSettings());
+ }
+
+ public string Generate()
+ {
+ var schema = GenerateFullTextSearchSchema();
+ return schema.ToString();
+ }
+
+ private JObject GenerateFullTextSearchSchema()
+ {
+ var schema = _schemaGenerator.Generate(typeof(AppSettings));
+ return JsonConvert.DeserializeObject(schema.ToJson());
+ }
+
+ }
+
+ internal class FullTextSearchSchemaGeneratorSettings : JsonSchemaGeneratorSettings
+ {
+ public FullTextSearchSchemaGeneratorSettings()
+ {
+ AlwaysAllowAdditionalObjectProperties = true;
+ SerializerSettings = new JsonSerializerSettings()
+ {
+ ContractResolver = new WritablePropertiesOnlyResolver(),
+ };
+ DefaultReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull;
+ SchemaNameGenerator = new NamespacePrefixedSchemaNameGenerator();
+ SerializerSettings.Converters.Add(new StringEnumConverter());
+ IgnoreObsoleteProperties = true;
+ GenerateExamples = true;
+ }
+
+ private class WritablePropertiesOnlyResolver : DefaultContractResolver
+ {
+ protected override IList CreateProperties(Type type, MemberSerialization memberSerialization)
+ {
+ IList props = base.CreateProperties(type, memberSerialization);
+ var result = props.Where(p => p.Writable).ToList();
+ result.ForEach(x => x.PropertyName = ToPascalCase(x.PropertyName));
+ return result;
+ }
+
+ private string ToPascalCase(string str)
+ {
+ if (!string.IsNullOrEmpty(str))
+ {
+ return char.ToUpperInvariant(str[0]) + str.Substring(1);
+ }
+
+ return str;
+
+ }
+ }
+ }
+
+ internal class NamespacePrefixedSchemaNameGenerator : DefaultSchemaNameGenerator
+ {
+ public override string Generate(Type type) => type.Namespace.Replace(".", string.Empty) + base.Generate(type);
+ }
+}
diff --git a/src/Our.Umbraco.FullTextSearch.sln b/src/Our.Umbraco.FullTextSearch.sln
index 6095cc5..6f0fdc6 100644
--- a/src/Our.Umbraco.FullTextSearch.sln
+++ b/src/Our.Umbraco.FullTextSearch.sln
@@ -31,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Our.Umbraco.FullTextSearch.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Our.Umbraco.FullTextSearch.Testsite13", "Testsites\Our.Umbraco.FullTextSearch.Testsite13\Our.Umbraco.FullTextSearch.Testsite13.csproj", "{9D899317-F4E7-4966-A03B-85FFA9B80E3C}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Our.Umbraco.FullTextSearch.SchemaGenerator", "Our.Umbraco.FullTextSearch.SchemaGenerator\Our.Umbraco.FullTextSearch.SchemaGenerator.csproj", "{560727BD-EFD0-4D19-ADB7-706C504E6E86}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -61,6 +63,10 @@ Global
{9D899317-F4E7-4966-A03B-85FFA9B80E3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D899317-F4E7-4966-A03B-85FFA9B80E3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D899317-F4E7-4966-A03B-85FFA9B80E3C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {560727BD-EFD0-4D19-ADB7-706C504E6E86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {560727BD-EFD0-4D19-ADB7-706C504E6E86}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {560727BD-EFD0-4D19-ADB7-706C504E6E86}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {560727BD-EFD0-4D19-ADB7-706C504E6E86}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Our.Umbraco.FullTextSearch/Options/FullTextSearchOptions.cs b/src/Our.Umbraco.FullTextSearch/Options/FullTextSearchOptions.cs
index 1ecb490..6d9a198 100644
--- a/src/Our.Umbraco.FullTextSearch/Options/FullTextSearchOptions.cs
+++ b/src/Our.Umbraco.FullTextSearch/Options/FullTextSearchOptions.cs
@@ -6,23 +6,56 @@ namespace Our.Umbraco.FullTextSearch.Options;
public class FullTextSearchOptions
{
+ ///
+ /// Indexing the full text content is by default enabled, but you can disable it by setting `Enabled` to false.
+ ///
[JsonProperty("enabled")]
public bool Enabled { get; set; } = true;
+
+ ///
+ /// The `DefaultTitleField` node contains the name of the field containing the title of the page in the index. The default value is `nodeName`. You can also override this when searching.
+ ///
[JsonProperty("defaultTitleField")]
public string DefaultTitleField { get; set; } = "nodeName";
+
[Obsolete("Use RenderingActiveKey instead")]
[JsonProperty("indexingActiveKey")]
public string IndexingActiveKey { get; set; } = "FullTextRenderingActive";
+
+ ///
+ /// When rendering, FullTextSearch adds the value of `RenderingActiveKey` as the value of a Request header named `X-Umbraco-FullTextSearch`, so you can use that to send different content to the renderer. The default value is FullTextRenderingActive. You can also use the `IsRenderingActive` helper method, in your views, to determine whether or not FullTextSearch is rendering the page. You can use this to exclude parts of the views from the content being rendered/indexed.
+ ///
[JsonProperty("renderingActiveKey")]
public string RenderingActiveKey { get; set; } = "FullTextRenderingActive";
+
+ ///
+ /// By default, all nodes with a template will be cached and indexed. You can control which nodes are being indexed, by adding the aliases of the disallowed content type aliases here.
+ ///
[JsonProperty("disallowedContentTypeAliases")]
public List DisallowedContentTypeAliases { get; set; } = new List();
+
+
+ ///
+ /// By default, all nodes with a template will be cached and indexed. You can control which nodes are being indexed, by adding the aliases of the properties containing a true/false editor, to control whether or not to include a node. A true value means it will be disallowed.
+ ///
[JsonProperty("disallowedPropertyAliases")]
public List DisallowedPropertyAliases { get; set; } = new List();
+
+ ///
+ /// Add specific Xpaths to remove from the rendered content. Using this, you can ie. remove scripts (`//script`) or the head area ('//head') of the page.
+ ///
[JsonProperty("xPathsToRemove")]
public List XPathsToRemove { get; set; } = new List();
+
+ ///
+ /// Field name to use in ExternalIndex for rendered full text content of pages.
+ ///
[JsonProperty("fullTextContentField")]
public string FullTextContentField { get; set; } = "FullTextContent";
+
+ ///
+ /// Field name to use for Full Text Searchs path field, used for determining hierarchy between pages.
+ ///
[JsonProperty("fullTextPathField")]
public string FullTextPathField { get; set; } = "FullTextPath";
diff --git a/src/Our.Umbraco.FullTextSearch/appsettings-schema.umbraco-fulltextsearch.json b/src/Our.Umbraco.FullTextSearch/appsettings-schema.umbraco-fulltextsearch.json
new file mode 100644
index 0000000..1026168
--- /dev/null
+++ b/src/Our.Umbraco.FullTextSearch/appsettings-schema.umbraco-fulltextsearch.json
@@ -0,0 +1,67 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "OurUmbracoFullTextSearchSchemaGeneratorAppSettings",
+ "type": "object",
+ "properties": {
+ "Umbraco": {
+ "$ref": "#/definitions/OurUmbracoFullTextSearchSchemaGeneratorUmbracoDefinition"
+ }
+ },
+ "definitions": {
+ "OurUmbracoFullTextSearchSchemaGeneratorUmbracoDefinition": {
+ "type": "object",
+ "description": "Configuration of settings",
+ "properties": {
+ "FullTextSearch": {
+ "description": "FullTextSearch settings",
+ "oneOf": [
+ {
+ "$ref": "#/definitions/OurUmbracoFullTextSearchOptionsFullTextSearchOptions"
+ }
+ ]
+ }
+ }
+ },
+ "OurUmbracoFullTextSearchOptionsFullTextSearchOptions": {
+ "type": "object",
+ "properties": {
+ "Enabled": {
+ "type": "boolean"
+ },
+ "DefaultTitleField": {
+ "type": "string"
+ },
+ "RenderingActiveKey": {
+ "type": "string"
+ },
+ "DisallowedContentTypeAliases": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "DisallowedPropertyAliases": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "XPathsToRemove": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "FullTextContentField": {
+ "type": "string"
+ },
+ "FullTextPathField": {
+ "type": "string"
+ },
+ "HighlightPattern": {
+ "type": "string"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Our.Umbraco.FullTextSearch/buildTransitive/Our.Umbraco.FullTextSearch.props b/src/Our.Umbraco.FullTextSearch/buildTransitive/Our.Umbraco.FullTextSearch.props
new file mode 100644
index 0000000..06db5c0
--- /dev/null
+++ b/src/Our.Umbraco.FullTextSearch/buildTransitive/Our.Umbraco.FullTextSearch.props
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file