diff --git a/commands/gen.go b/commands/gen.go
index 1c536184000..df21ec5929a 100644
--- a/commands/gen.go
+++ b/commands/gen.go
@@ -21,24 +21,49 @@ import (
"os"
"path"
"path/filepath"
+ "reflect"
+ "regexp"
+ "runtime"
"slices"
"strings"
+ "unicode"
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/styles"
"github.com/bep/simplecobra"
"github.com/gohugoio/hugo/common/hugo"
+ "github.com/gohugoio/hugo/config/allconfig"
"github.com/gohugoio/hugo/docshelper"
"github.com/gohugoio/hugo/helpers"
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/hugolib"
+ "github.com/gohugoio/hugo/hugolib/segments"
+ "github.com/gohugoio/hugo/langs"
+ "github.com/gohugoio/hugo/markup/asciidocext/asciidocext_config"
+ "github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
+ "github.com/gohugoio/hugo/markup/highlight"
+ "github.com/gohugoio/hugo/markup/tableofcontents"
+ "github.com/gohugoio/hugo/media"
+ "github.com/gohugoio/hugo/navigation"
+ "github.com/gohugoio/hugo/output"
"github.com/gohugoio/hugo/parser"
+ "github.com/gohugoio/hugo/resources/images"
+ "github.com/gohugoio/hugo/resources/page"
+ "github.com/gohugoio/hugo/resources/page/pagemeta"
+ "github.com/invopop/jsonschema"
"github.com/spf13/cobra"
"github.com/spf13/cobra/doc"
"gopkg.in/yaml.v2"
)
+// Schema generation statistics
+type schemaStats struct {
+ schemasGenerated int
+ totalProperties int
+ documentationLinks int
+}
+
func newGenCommand() *genCommand {
var (
// Flags.
@@ -184,13 +209,13 @@ url: %s
prepender := func(filename string) string {
name := filepath.Base(filename)
base := strings.TrimSuffix(name, path.Ext(name))
- url := "/docs/reference/commands/" + strings.ToLower(base) + "/"
+ url := "/commands/" + strings.ToLower(base) + "/"
return fmt.Sprintf(gendocFrontmatterTemplate, strings.Replace(base, "_", " ", -1), base, url)
}
linkHandler := func(name string) string {
base := strings.TrimSuffix(name, path.Ext(name))
- return "/docs/reference/commands/" + strings.ToLower(base) + "/"
+ return "/commands/" + strings.ToLower(base) + "/"
}
r.Println("Generating Hugo command-line documentation in", gendocdir, "...")
doc.GenMarkdownTreeCustom(cd.CobraCommand.Root(), gendocdir, prepender, linkHandler)
@@ -260,12 +285,414 @@ url: %s
}
}
+ newJSONSchema := func() simplecobra.Commander {
+ var schemaDir string
+ return &simpleCommand{
+ name: "jsonschemas",
+ short: "Generate JSON Schema for Hugo config and page structures",
+ long: `Generate a JSON Schema for Hugo configuration options and page structures using reflection.`,
+ run: func(ctx context.Context, cd *simplecobra.Commandeer, r *rootCommand, args []string) error {
+ // This function generates JSON Schema for Hugo configuration
+ // It creates individual schema files for each configuration section
+
+ // Initialize statistics tracking
+ var stats schemaStats
+ // and a main schema file that includes RootConfig properties and
+ // references to the section schemas.
+ // Go comments are used as descriptions in the schema.
+
+ // Create the output directory if it doesn't exist
+ if err := os.MkdirAll(schemaDir, 0755); err != nil {
+ return fmt.Errorf("failed to create schema directory: %w", err)
+ }
+
+ camel := func(s string) string {
+ if s == "" {
+ return ""
+ }
+ return strings.ToLower(s[:1]) + s[1:]
+ }
+
+ camelType := func(t reflect.Type) string {
+ name := t.Name()
+ if name == "" {
+ return ""
+ }
+ return strings.ToLower(name[:1]) + name[1:]
+ }
+
+ // Create a reflector to use Go comments as descriptions
+ rf := jsonschema.Reflector{
+ KeyNamer: camel,
+ Namer: camelType,
+ RequiredFromJSONSchemaTags: true, // Don't mark fields as required
+ DoNotReference: true, // Expand references into full definitions
+ ExpandedStruct: true, // Include all struct fields in the schema
+ AllowAdditionalProperties: true, // Allow additional properties not in the schema
+ FieldNameTag: "json", // Use json tags for field names
+ }
+
+ // Use AddGoComments to include Go comments in the schema as descriptions
+ // We need to find the Hugo source directory to read Go comments
+ // Use runtime to get the current file's directory as a reference to Hugo source
+ _, currentFile, _, _ := runtime.Caller(0)
+ hugoSourceDir := filepath.Dir(filepath.Dir(currentFile)) // Go up one level from commands/ to hugo/
+
+ // Change to the Hugo source directory to make relative paths work
+ originalWd, _ := os.Getwd()
+ os.Chdir(hugoSourceDir)
+ defer os.Chdir(originalWd)
+
+ if err := rf.AddGoComments("github.com/gohugoio/hugo", "."); err != nil {
+ return fmt.Errorf("failed to add Go comments: %w", err)
+ }
+
+ // Crawl documentation files to extract URLs for linking
+ r.Println("Setting up documentation URL generator...")
+
+ // Dynamically discover configuration sections from the Config struct
+ configSections := discoverConfigSections()
+
+ // Generate individual schema files for each section
+ for name, fieldInfo := range configSections {
+
+ // Declare schema variable early
+ var schema *jsonschema.Schema
+ var schemaErr error
+
+ // Handle the 4 map types using additionalProperties pattern instead of wrapper structs
+ switch name {
+ case "taxonomies":
+ // Taxonomies map[string]string - create schema with additionalProperties
+ schema = &jsonschema.Schema{
+ Type: "object",
+ Description: "Taxonomy configuration. Maps singular taxonomy name to plural form.",
+ AdditionalProperties: &jsonschema.Schema{
+ Type: "string",
+ Description: "The plural form of the taxonomy",
+ },
+ }
+ case "languages":
+ // Languages map[string]langs.LanguageConfig - create schema with additionalProperties
+ // This includes both the basic language config and all localized settings
+ languageConfigSchema := rf.Reflect(langs.LanguageConfig{})
+ languageConfigSchema.Version = "https://json-schema.org/draft-07/schema"
+ cleanupSubSchema(languageConfigSchema)
+
+ // Add all the localized configuration settings that can be defined per language
+ // These are the same configuration sections that can be localized
+ if languageConfigSchema.Properties == nil {
+ languageConfigSchema.Properties = jsonschema.NewProperties()
+ }
+
+ // Add references to all localizable configuration sections
+ localizableConfigs := map[string]string{
+ "baseURL": "string",
+ "buildDrafts": "boolean",
+ "buildExpired": "boolean",
+ "buildFuture": "boolean",
+ "canonifyURLs": "boolean",
+ "capitalizeListTitles": "boolean",
+ "contentDir": "string",
+ "copyright": "string",
+ "disableAliases": "boolean",
+ "disableHugoGeneratorInject": "boolean",
+ "disableKinds": "array",
+ "disableLiveReload": "boolean",
+ "disablePathToLower": "boolean",
+ "enableEmoji": "boolean",
+ "hasCJKLanguage": "boolean",
+ "mainSections": "array",
+ "pluralizeListTitles": "boolean",
+ "refLinksErrorLevel": "string",
+ "refLinksNotFoundURL": "string",
+ "relativeURLs": "boolean",
+ "removePathAccents": "boolean",
+ "renderSegments": "array",
+ "sectionPagesMenu": "string",
+ "staticDir": "array",
+ "summaryLength": "integer",
+ "timeZone": "string",
+ "titleCaseStyle": "string",
+ }
+
+ // Add simple properties that have primitive types
+ for propName, propType := range localizableConfigs {
+ propSchema := createPrimitiveSchema(propType)
+ languageConfigSchema.Properties.Set(propName, propSchema)
+ }
+
+ // Add references to complex configuration sections that can be localized
+ complexConfigs := []string{
+ "frontmatter", "markup", "mediatypes", "menus", "outputformats",
+ "outputs", "page", "pagination", "params", "permalinks", "privacy",
+ "related", "security", "services", "sitemap", "taxonomies",
+ }
+
+ for _, configName := range complexConfigs {
+ languageConfigSchema.Properties.Set(configName, &jsonschema.Schema{
+ Ref: fmt.Sprintf("http://gohugo.io/jsonschemas/hugo-config-%s.schema.json", configName),
+ })
+ }
+
+ schema = &jsonschema.Schema{
+ Type: "object",
+ Description: "Language configuration. Maps language code to language configuration.",
+ AdditionalProperties: languageConfigSchema,
+ }
+ case "permalinks":
+ // Permalinks map[string]map[string]string - create schema with additionalProperties
+ schema = &jsonschema.Schema{
+ Type: "object",
+ Description: "Permalink configuration. Maps content kind (page, section, term, taxonomy) to permalink patterns.",
+ AdditionalProperties: &jsonschema.Schema{
+ Type: "object",
+ Description: "Permalink patterns for this content kind",
+ AdditionalProperties: &jsonschema.Schema{
+ Type: "string",
+ Description: "The permalink pattern for this section",
+ },
+ },
+ }
+ case "outputs":
+ // Outputs map[string][]string - create schema with additionalProperties
+ schema = &jsonschema.Schema{
+ Type: "object",
+ Description: "Output format configuration. Maps page kind to list of output formats.",
+ AdditionalProperties: &jsonschema.Schema{
+ Type: "array",
+ Description: "List of output formats for this page kind",
+ Items: &jsonschema.Schema{
+ Type: "string",
+ Description: "Output format name",
+ },
+ },
+ }
+ case "markup":
+ // Generate markup schema with nested definitions for goldmark, highlight, tableOfContents, asciidocExt
+ // Due to a bug in jsonschema reflection with the markup_config.Config struct,
+ // we'll manually create the schema structure
+
+ // Create definitions for nested structs
+ markupRf := jsonschema.Reflector{
+ KeyNamer: camel,
+ Namer: camelType,
+ RequiredFromJSONSchemaTags: true,
+ DoNotReference: true,
+ ExpandedStruct: true,
+ AllowAdditionalProperties: true,
+ }
+
+ // Add Go comments to the markup reflector
+ if err := markupRf.AddGoComments("github.com/gohugoio/hugo", "."); err != nil {
+ r.Printf("Warning: failed to add Go comments for markup reflector: %v\n", err)
+ }
+
+ // Create the main markup schema manually
+ schema = &jsonschema.Schema{
+ Type: "object",
+ Description: "Configuration for markup processing",
+ Properties: jsonschema.NewProperties(),
+ }
+
+ // Add properties manually based on markup_config.Config struct
+
+ schema.Properties.Set("defaultMarkdownHandler", &jsonschema.Schema{
+ Type: "string",
+ Description: "Default markdown handler for md/markdown extensions. Default is 'goldmark'.",
+ })
+
+ schema.Properties.Set("highlight", &jsonschema.Schema{
+ Ref: "#/$defs/highlight",
+ Description: "Configuration for syntax highlighting.",
+ })
+
+ schema.Properties.Set("tableOfContents", &jsonschema.Schema{
+ Ref: "#/$defs/tableOfContents",
+ Description: "Table of contents configuration.",
+ })
+
+ schema.Properties.Set("goldmark", &jsonschema.Schema{
+ Ref: "#/$defs/goldmark",
+ Description: "Configuration for the Goldmark markdown engine.",
+ })
+
+ schema.Properties.Set("asciidocExt", &jsonschema.Schema{
+ Ref: "#/$defs/asciidocExt",
+ Description: "Configuration for the Asciidoc external markdown engine.",
+ })
+
+ // Create definitions for nested structs
+ schema.Definitions = make(jsonschema.Definitions)
+
+ // Add goldmark definition
+ goldmarkSchema := markupRf.Reflect(goldmark_config.Config{})
+ cleanupSubSchema(goldmarkSchema)
+ schema.Definitions["goldmark"] = goldmarkSchema
+
+ // Add highlight definition
+ highlightSchema := markupRf.Reflect(highlight.Config{})
+ cleanupSubSchema(highlightSchema)
+ schema.Definitions["highlight"] = highlightSchema
+
+ // Add tableOfContents definition
+ tocSchema := markupRf.Reflect(tableofcontents.Config{})
+ cleanupSubSchema(tocSchema)
+ schema.Definitions["tableOfContents"] = tocSchema
+
+ // Add asciidocExt definition
+ asciidocSchema := markupRf.Reflect(asciidocext_config.Config{})
+ cleanupSubSchema(asciidocSchema)
+ schema.Definitions["asciidocExt"] = asciidocSchema
+ default:
+ // Create a zero value instance of the type for reflection
+ var instance interface{}
+ // Handle other types appropriately
+ switch fieldInfo.Type.Kind() {
+ case reflect.Map:
+ // For other maps, create an empty map
+ instance = make(map[string]interface{})
+ case reflect.Slice:
+ // For slices, create an empty slice
+ instance = make([]interface{}, 0)
+ case reflect.Chan:
+ // Skip channels as they can't be properly serialized
+ continue
+ case reflect.Func:
+ // Skip functions as they can't be properly serialized
+ continue
+ case reflect.Interface:
+ // Skip interfaces as they can't be properly reflected
+ continue
+ default:
+ // For structs and other types, use reflect.New
+ instance = reflect.New(fieldInfo.Type).Interface()
+ }
+
+ // Use a defer function to catch panics and continue with the next section
+ func() {
+ defer func() {
+ if r := recover(); r != nil {
+ schemaErr = fmt.Errorf("panic during reflection: %v", r)
+ }
+ }()
+ schema = rf.Reflect(instance)
+ }()
+ }
+
+ if schemaErr != nil {
+ continue
+ }
+ schema.ID = jsonschema.ID(fmt.Sprintf("https://gohugo.io/jsonschemas/hugo-config-%s.schema.json", name))
+ schema.Version = "https://json-schema.org/draft-07/schema"
+
+ // Clear all required fields
+ schema.Required = nil
+
+ // Remove required fields from nested objects by working directly with the schema
+ removeRequiredFromSchema(schema)
+
+ // Transform enums to oneOf patterns following SchemaStore recommendations
+ transformEnumsToOneOf(schema)
+
+ // Add documentation links to schema descriptions
+ addDocumentationLinksToSchema(schema, name, []string{})
+
+ filename := filepath.Join(schemaDir, fmt.Sprintf("hugo-config-%s.schema.json", name))
+ f, err := os.Create(filename)
+ if err != nil {
+ return fmt.Errorf("failed to create schema file %s: %w", filename, err)
+ }
+
+ enc := json.NewEncoder(f)
+ enc.SetIndent("", " ")
+ if err := enc.Encode(schema); err != nil {
+ f.Close()
+ return fmt.Errorf("failed to encode schema for %s: %w", name, err)
+ }
+ f.Close()
+ r.Printf("Wrote %s\n", filename)
+
+ // Update statistics
+ stats.schemasGenerated++
+ stats.totalProperties += countSchemaProperties(schema)
+ stats.documentationLinks += countDocumentationLinks(schema)
+ }
+
+ // Generate the main hugo.schema.json that combines RootConfig and references other schemas
+
+ // For the main schema, we'll directly reflect the RootConfig
+ rootConfigSchema := rf.Reflect(allconfig.RootConfig{})
+
+ // Set the main schema metadata directly on the schema object
+ rootConfigSchema.ID = jsonschema.ID("https://gohugo.io/jsonschemas/hugo-config.schema.json")
+ rootConfigSchema.Version = "https://json-schema.org/draft-07/schema"
+ rootConfigSchema.Title = "Hugo Configuration Schema"
+ rootConfigSchema.Description = "JSON Schema for Hugo configuration files"
+ rootConfigSchema.Type = "object"
+
+ // Remove any required fields throughout the schema
+ rootConfigSchema.Required = nil
+ removeRequiredFromSchema(rootConfigSchema)
+
+ // Add documentation links to root config schema
+ addDocumentationLinksToSchema(rootConfigSchema, "rootconfig", []string{})
+
+ // Make sure we have a properties object
+ if rootConfigSchema.Properties == nil {
+ rootConfigSchema.Properties = jsonschema.NewProperties()
+ }
+
+ // Add references to section schemas
+ for name := range configSections {
+ rootConfigSchema.Properties.Set(camel(name), &jsonschema.Schema{
+ Ref: fmt.Sprintf("http://gohugo.io/jsonschemas/hugo-config-%s.schema.json", name),
+ })
+ }
+
+ // Create the main hugo.schema.json
+ filename := filepath.Join(schemaDir, "hugo-config.schema.json")
+ f, err := os.Create(filename)
+ if err != nil {
+ return fmt.Errorf("failed to create main schema file: %w", err)
+ }
+ defer f.Close()
+
+ enc := json.NewEncoder(f)
+ enc.SetIndent("", " ")
+ if err := enc.Encode(rootConfigSchema); err != nil {
+ return fmt.Errorf("failed to encode main schema: %w", err)
+ }
+ r.Printf("Wrote %s\n", filename)
+
+ // Update statistics for main config schema
+ stats.schemasGenerated++
+ stats.totalProperties += countSchemaProperties(rootConfigSchema)
+ stats.documentationLinks += countDocumentationLinks(rootConfigSchema)
+
+ // Generate Page schemas
+ if err := generatePageSchemas(rf, schemaDir, r, &stats); err != nil {
+ return fmt.Errorf("failed to generate page schemas: %w", err)
+ }
+
+ // Print generation statistics
+ printSchemaStats(stats, r)
+
+ return nil
+ },
+ withc: func(cmd *cobra.Command, r *rootCommand) {
+ cmd.PersistentFlags().StringVarP(&schemaDir, "dir", "", "/tmp/hugo-schemas", "output directory for schema files")
+ },
+ }
+ }
+
return &genCommand{
commands: []simplecobra.Commander{
newChromaStyles(),
newGen(),
newMan(),
newDocsHelper(),
+ newJSONSchema(),
},
}
}
@@ -301,3 +728,1022 @@ func (c *genCommand) PreRun(cd, runner *simplecobra.Commandeer) error {
c.rootCmd = cd.Root.Command.(*rootCommand)
return nil
}
+
+type configFieldInfo struct {
+ Type reflect.Type
+ Tag reflect.StructTag
+}
+
+// canReflectType checks if a type can be safely reflected for JSON schema generation
+func canReflectType(t reflect.Type) bool {
+ // Skip invalid types
+ if t == nil {
+ return false
+ }
+
+ // Skip interface types as they can't be properly reflected
+ if t.Kind() == reflect.Interface {
+ return false
+ }
+
+ // Skip function types
+ if t.Kind() == reflect.Func {
+ return false
+ }
+
+ // Skip channel types
+ if t.Kind() == reflect.Chan {
+ return false
+ }
+
+ // Skip unsafe pointer types
+ if t.Kind() == reflect.UnsafePointer {
+ return false
+ }
+
+ // Check for problematic type names that indicate complex generics
+ typeName := t.String()
+ return !strings.Contains(typeName, "ConfigNamespace")
+}
+
+// cleanupSubSchema performs standard cleanup on a schema for use as a definition
+func cleanupSubSchema(schema *jsonschema.Schema) {
+ schema.Required = nil
+ removeRequiredFromSchema(schema)
+ schema.Version = "https://json-schema.org/draft-07/schema"
+ schema.ID = ""
+}
+
+// createPrimitiveSchema creates a simple schema for primitive types
+func createPrimitiveSchema(typeName string) *jsonschema.Schema {
+ switch typeName {
+ case "string":
+ return &jsonschema.Schema{Type: "string"}
+ case "boolean":
+ return &jsonschema.Schema{Type: "boolean"}
+ case "integer":
+ return &jsonschema.Schema{Type: "integer"}
+ case "array":
+ return &jsonschema.Schema{
+ Type: "array",
+ Items: &jsonschema.Schema{Type: "string"},
+ }
+ default:
+ return &jsonschema.Schema{Type: "string"} // fallback
+ }
+}
+
+// removeRequiredFromSchema removes "required" fields from the schema and all nested schemas
+func removeRequiredFromSchema(schema *jsonschema.Schema) {
+ if schema == nil {
+ return
+ }
+
+ // Clear the required field
+ schema.Required = nil
+
+ // Recursively remove required from properties
+ if schema.Properties != nil {
+ for pair := schema.Properties.Oldest(); pair != nil; pair = pair.Next() {
+ removeRequiredFromSchema(pair.Value)
+ }
+ }
+
+ // Recursively remove required from pattern properties
+ if schema.PatternProperties != nil {
+ for _, propSchema := range schema.PatternProperties {
+ removeRequiredFromSchema(propSchema)
+ }
+ }
+
+ // Recursively remove required from additional properties
+ if schema.AdditionalProperties != nil {
+ removeRequiredFromSchema(schema.AdditionalProperties)
+ }
+
+ // Recursively remove required from items (for arrays)
+ if schema.Items != nil {
+ removeRequiredFromSchema(schema.Items)
+ }
+
+ // Recursively remove required from all conditional schemas
+ for _, condSchema := range schema.AllOf {
+ removeRequiredFromSchema(condSchema)
+ }
+ for _, condSchema := range schema.AnyOf {
+ removeRequiredFromSchema(condSchema)
+ }
+ for _, condSchema := range schema.OneOf {
+ removeRequiredFromSchema(condSchema)
+ }
+
+ // Remove required from not schema
+ if schema.Not != nil {
+ removeRequiredFromSchema(schema.Not)
+ }
+
+ // Remove required from definitions
+ if schema.Definitions != nil {
+ for _, defSchema := range schema.Definitions {
+ removeRequiredFromSchema(defSchema)
+ }
+ }
+}
+
+func discoverConfigSections() map[string]configFieldInfo {
+ sections := make(map[string]configFieldInfo)
+
+ // Map schema names to actual field names in the Config struct
+ // These are the fields that have `mapstructure:"-"` tags and represent configuration sections
+ sectionMappings := getSectionMappings()
+
+ configType := reflect.TypeOf(allconfig.Config{})
+
+ for schemaName, fieldName := range sectionMappings {
+ if field, found := configType.FieldByName(fieldName); found {
+ // Only include fields that have the mapstructure:"-" tag, indicating they are configuration sections
+ if tag := field.Tag.Get("mapstructure"); tag == "-" {
+ fieldType := field.Type
+
+ // Handle ConfigNamespace types by using the specific config types directly
+ if strings.Contains(fieldType.String(), "ConfigNamespace") {
+ configType := getConfigNamespaceConfigType(schemaName)
+ if configType != nil {
+ sections[schemaName] = configFieldInfo{
+ Type: configType,
+ Tag: field.Tag,
+ }
+ }
+ continue
+ }
+
+ // For pointer types, get the underlying type
+ if fieldType.Kind() == reflect.Ptr {
+ fieldType = fieldType.Elem()
+ }
+
+ // Skip types that can't be safely reflected
+ if !canReflectType(fieldType) {
+ continue
+ }
+
+ sections[schemaName] = configFieldInfo{
+ Type: fieldType,
+ Tag: field.Tag,
+ }
+ }
+ }
+ }
+
+ return sections
+}
+
+// getConfigNamespaceConfigType returns the specific config type for ConfigNamespace fields
+// instead of trying to extract from generics which causes reflection issues
+func getConfigNamespaceConfigType(schemaName string) reflect.Type {
+ switch schemaName {
+ case "menus":
+ // For menus, use the MenuConfig struct directly instead of a map
+ return reflect.TypeOf(navigation.MenuConfig{})
+
+ case "outputformats":
+ // For output formats, use the OutputFormatConfig struct directly
+ return reflect.TypeOf(output.OutputFormatConfig{})
+
+ case "mediatypes":
+ // For media types, use the MediaTypeConfig struct directly
+ return reflect.TypeOf(media.MediaTypeConfig{})
+
+ case "contenttypes":
+ // For content types, use the ContentTypeConfig struct directly
+ return reflect.TypeOf(media.ContentTypeConfig{})
+
+ case "imaging":
+ // For imaging, use the ImagingConfig struct directly
+ return reflect.TypeOf(images.ImagingConfig{})
+
+ case "cascade":
+ // For cascade, use the PageMatcherParamsConfig struct directly
+ return reflect.TypeOf(page.PageMatcherParamsConfig{})
+
+ case "segments":
+ // For segments, use the SegmentConfig struct directly
+ return reflect.TypeOf(segments.SegmentConfig{})
+ }
+
+ return nil
+}
+
+// generatePageSchemas creates a JSON schema for Hugo page front matter
+func generatePageSchemas(rf jsonschema.Reflector, schemaDir string, r *rootCommand, stats *schemaStats) error {
+ // Generate a single schema for Hugo page front matter
+ schema := rf.Reflect(pagemeta.PageConfig{})
+
+ // Set schema metadata
+ schema.ID = jsonschema.ID("https://gohugo.io/jsonschemas/hugo-page.schema.json")
+ schema.Version = "https://json-schema.org/draft-07/schema"
+ schema.Title = "Hugo Page Front Matter Schema"
+ schema.Description = "JSON Schema for Hugo page front matter structure"
+
+ // Clear required fields
+ schema.Required = nil
+
+ // Remove required fields from nested schemas
+ removeRequiredFromSchema(schema)
+
+ // Add documentation URLs to front matter properties
+ addDocumentationLinksToSchema(schema, "page-frontmatter", []string{})
+
+ // Add flexible date definitions
+ addFlexibleDateDefinitions(schema)
+
+ // Remove the content property as it represents the file content after frontmatter, not a frontmatter field
+ if schema.Properties != nil {
+ schema.Properties.Delete("content")
+ }
+
+ // Write schema file
+ filename := filepath.Join(schemaDir, "hugo-page.schema.json")
+ f, err := os.Create(filename)
+ if err != nil {
+ return fmt.Errorf("failed to create page schema file %s: %w", filename, err)
+ }
+ defer f.Close()
+
+ enc := json.NewEncoder(f)
+ enc.SetIndent("", " ")
+ if err := enc.Encode(schema); err != nil {
+ return fmt.Errorf("failed to encode page schema: %w", err)
+ }
+
+ r.Printf("Wrote page schema %s\n", filename)
+
+ // Update statistics for page schema
+ stats.schemasGenerated++
+ stats.totalProperties += countSchemaProperties(schema)
+ stats.documentationLinks += countDocumentationLinks(schema)
+
+ return nil
+}
+
+// addFlexibleDateDefinitions adds flexible date definitions to the page schema
+func addFlexibleDateDefinitions(schema *jsonschema.Schema) {
+ if schema.Properties == nil {
+ return
+ }
+
+ // Initialize $defs if not present
+ if schema.Definitions == nil {
+ schema.Definitions = jsonschema.Definitions{}
+ }
+
+ // Create a shared flexible date definition
+ flexibleDateDef := &jsonschema.Schema{
+ OneOf: []*jsonschema.Schema{
+ {
+ Type: "string",
+ Format: "date-time",
+ Description: "RFC3339 date-time format (e.g., 2017-01-02T15:04:05Z07:00)",
+ },
+ {
+ Type: "string",
+ Format: "date",
+ Description: "Date only format (e.g., 2017-01-02)",
+ },
+ {
+ Type: "string",
+ Pattern: "^\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}$",
+ Description: "Date with time format (e.g., 2017-01-02 15:04:05)",
+ },
+ {
+ Type: "string",
+ Pattern: "^\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}$",
+ Description: "Date with hour:minute format (e.g., 2017-01-02 15:04)",
+ },
+ },
+ Description: "Hugo date field supporting multiple formats",
+ }
+
+ // Add the definition to $defs
+ schema.Definitions["flexibleDate"] = flexibleDateDef
+
+ // Apply flexible date schema to date-related properties using $ref
+ dateProperties := []string{"date", "publishDate", "expiryDate", "lastmod"}
+ for _, propName := range dateProperties {
+ if propSchema, exists := schema.Properties.Get(propName); exists {
+ // Preserve the original description and documentation URL
+ originalDesc := propSchema.Description
+
+ // Replace with $ref to shared definition
+ *propSchema = jsonschema.Schema{
+ Ref: "#/$defs/flexibleDate",
+ Description: originalDesc,
+ }
+ }
+ }
+}
+
+// transformEnumsToOneOf converts enum arrays to oneOf patterns following SchemaStore recommendations
+// This transforms { "enum": ["foo", "bar"] } into { "oneOf": [{"const": "foo"}, {"const": "bar"}] }
+// It also handles anyOf patterns that contain enums
+func transformEnumsToOneOf(schema *jsonschema.Schema) {
+ if schema == nil {
+ return
+ }
+
+ // Transform enum to oneOf if present
+ if len(schema.Enum) > 0 {
+ var oneOfSchemas []*jsonschema.Schema
+ for _, enumValue := range schema.Enum {
+ oneOfSchemas = append(oneOfSchemas, &jsonschema.Schema{
+ Const: enumValue,
+ })
+ }
+ schema.OneOf = oneOfSchemas
+ schema.Enum = nil // Clear the enum field
+ }
+
+ // Transform enums within anyOf patterns
+ if schema.AnyOf != nil {
+ for _, anyOfSchema := range schema.AnyOf {
+ if len(anyOfSchema.Enum) > 0 {
+ var oneOfSchemas []*jsonschema.Schema
+ for _, enumValue := range anyOfSchema.Enum {
+ oneOfSchemas = append(oneOfSchemas, &jsonschema.Schema{
+ Const: enumValue,
+ })
+ }
+ anyOfSchema.OneOf = oneOfSchemas
+ anyOfSchema.Enum = nil // Clear the enum field
+ }
+ }
+ }
+
+ // Recursively transform properties
+ if schema.Properties != nil {
+ for pair := schema.Properties.Oldest(); pair != nil; pair = pair.Next() {
+ transformEnumsToOneOf(pair.Value)
+ }
+ }
+
+ // Recursively transform pattern properties
+ if schema.PatternProperties != nil {
+ for _, propSchema := range schema.PatternProperties {
+ transformEnumsToOneOf(propSchema)
+ }
+ }
+
+ // Recursively transform additional properties
+ if schema.AdditionalProperties != nil {
+ transformEnumsToOneOf(schema.AdditionalProperties)
+ }
+
+ // Recursively transform items (for arrays)
+ if schema.Items != nil {
+ transformEnumsToOneOf(schema.Items)
+ }
+
+ // Recursively transform all conditional schemas
+ for _, condSchema := range schema.AllOf {
+ transformEnumsToOneOf(condSchema)
+ }
+ for _, condSchema := range schema.AnyOf {
+ transformEnumsToOneOf(condSchema)
+ }
+ for _, condSchema := range schema.OneOf {
+ transformEnumsToOneOf(condSchema)
+ }
+
+ // Transform not schema
+ if schema.Not != nil {
+ transformEnumsToOneOf(schema.Not)
+ }
+
+ // Transform definitions
+ if schema.Definitions != nil {
+ for _, defSchema := range schema.Definitions {
+ transformEnumsToOneOf(defSchema)
+ }
+ }
+}
+
+// addDocumentationLinksToSchema enhances schema descriptions with documentation URLs
+// using anchor links extracted from the built Hugo documentation
+func addDocumentationLinksToSchema(schema *jsonschema.Schema, sectionName string, propertyPath []string) {
+ if schema == nil {
+ return
+ }
+
+ // Add documentation to properties
+ if schema.Properties != nil {
+ for pair := schema.Properties.Oldest(); pair != nil; pair = pair.Next() {
+ propName := pair.Key
+ propSchema := pair.Value
+
+ // Build the current property path
+ currentPath := append(propertyPath, propName)
+
+ // Generate documentation URL for this property
+ docURL := generateDocumentationURL(sectionName, currentPath)
+ if docURL != "" {
+ if propSchema.Description != "" {
+ // Append URL to existing Go comment description
+ propSchema.Description = propSchema.Description + " \n" + docURL
+ } else {
+ // Add URL as description if no Go comment exists
+ propSchema.Description = docURL
+ }
+ }
+
+ // Recursively process nested schemas
+ addDocumentationLinksToSchema(propSchema, sectionName, currentPath)
+ }
+ }
+
+ // Process additional properties
+ if schema.AdditionalProperties != nil {
+ addDocumentationLinksToSchema(schema.AdditionalProperties, sectionName, propertyPath)
+ }
+
+ // Process array items
+ if schema.Items != nil {
+ addDocumentationLinksToSchema(schema.Items, sectionName, propertyPath)
+ }
+
+ // Process conditional schemas
+ for _, condSchema := range schema.AllOf {
+ addDocumentationLinksToSchema(condSchema, sectionName, propertyPath)
+ }
+ for _, condSchema := range schema.AnyOf {
+ addDocumentationLinksToSchema(condSchema, sectionName, propertyPath)
+ }
+ for _, condSchema := range schema.OneOf {
+ addDocumentationLinksToSchema(condSchema, sectionName, propertyPath)
+ }
+
+ // Process not schema
+ if schema.Not != nil {
+ addDocumentationLinksToSchema(schema.Not, sectionName, propertyPath)
+ }
+
+ // Process definitions with appropriate section context
+ // This ensures that properties within definitions get proper documentation links
+ if schema.Definitions != nil {
+ for defName, defSchema := range schema.Definitions {
+ // For markup definitions, use the specific subsection name for better URL generation
+ defSectionName := sectionName
+ if sectionName == "markup" {
+ switch defName {
+ case "goldmark":
+ defSectionName = "goldmark"
+ case "highlight":
+ defSectionName = "highlight"
+ case "tableOfContents":
+ defSectionName = "tableofcontents"
+ case "asciidocExt":
+ defSectionName = "asciidocext"
+ }
+ }
+ addDocumentationLinksToSchema(defSchema, defSectionName, []string{})
+ }
+ }
+}
+
+var sectionAnchors map[string]map[string]string
+var docAnchors map[string]string
+
+// generateDocumentationURL generates a documentation URL based on the section and property path
+func generateDocumentationURL(sectionName string, propertyPath []string) string {
+ if len(propertyPath) == 0 {
+ return ""
+ }
+
+ // Base URL for Hugo configuration documentation
+ baseURL := "https://gohugo.io/configuration"
+
+ // For root config properties, use the all.md page with extracted anchors
+ if sectionName == "rootconfig" && len(propertyPath) > 0 {
+ // Initialize anchors cache once, only for root config
+ if docAnchors == nil {
+ docAnchors = extractAnchorsFromHTML()
+ }
+
+ propertyName := propertyPath[len(propertyPath)-1]
+
+ // Check if we have an anchor for this property
+ if anchorID, exists := docAnchors[propertyName]; exists {
+ return baseURL + "/all/#" + anchorID
+ }
+
+ // Fallback: generate anchor from property name (lowercase)
+ return baseURL + "/all/#" + strings.ToLower(propertyName)
+ }
+
+ // Special case for frontmatter config: all properties are date-related and should link to #dates
+ if sectionName == "frontmatter" {
+ return baseURL + "/front-matter/#dates"
+ }
+
+ // Special case for page front-matter: use content management documentation with anchor extraction
+ if sectionName == "page-frontmatter" {
+ baseURL = "https://gohugo.io/content-management/front-matter"
+
+ // Initialize section anchors cache for content-management front-matter
+ if sectionAnchors == nil {
+ sectionAnchors = make(map[string]map[string]string)
+ }
+
+ // Extract anchors from content-management front-matter if not cached
+ if _, exists := sectionAnchors["content-frontmatter"]; !exists {
+ // Extract anchors from content-management/front-matter page
+ anchors := make(map[string]string)
+
+ // Try different base directories
+ baseDirs := []string{"docs/public", "public-docs", "."}
+ for _, baseDir := range baseDirs {
+ path := filepath.Join(baseDir, "content-management", "front-matter", "index.html")
+ if content, err := os.ReadFile(path); err == nil {
+ re := regexp.MustCompile(`id="([^"]+)"`)
+ matches := re.FindAllStringSubmatch(string(content), -1)
+ for _, match := range matches {
+ if len(match) > 1 {
+ anchorID := match[1]
+ // Map anchor ID to itself for exact matches
+ anchors[anchorID] = anchorID
+ // Also map lowercase for case-insensitive matching
+ anchors[strings.ToLower(anchorID)] = anchorID
+ }
+ }
+ break
+ }
+ }
+ sectionAnchors["content-frontmatter"] = anchors
+ }
+
+ // Use the same logic as standard sections for nested properties
+ if len(propertyPath) > 0 {
+ if anchors, exists := sectionAnchors["content-frontmatter"]; exists {
+ // First try: just the property name (most specific)
+ propertyName := propertyPath[len(propertyPath)-1]
+ if anchorID, found := anchors[propertyName]; found {
+ return baseURL + "#" + anchorID
+ }
+
+ // Second try: property name in lowercase
+ if anchorID, found := anchors[strings.ToLower(propertyName)]; found {
+ return baseURL + "#" + anchorID
+ }
+
+ // Third try: exact concatenated paths for known patterns
+ if len(propertyPath) > 1 {
+ fullPath := strings.ToLower(strings.Join(propertyPath, ""))
+ if anchorID, found := anchors[fullPath]; found {
+ return baseURL + "#" + anchorID
+ }
+ }
+
+ // Fourth try: work backwards through the property path to find parent section anchors
+ // For sitemap.changeFreq, try: sitemap
+ for i := len(propertyPath) - 2; i >= 0; i-- {
+ parentName := propertyPath[i]
+ if anchorID, found := anchors[parentName]; found {
+ return baseURL + "#" + anchorID
+ }
+ if anchorID, found := anchors[strings.ToLower(parentName)]; found {
+ return baseURL + "#" + anchorID
+ }
+ }
+ }
+ }
+
+ // Fallback to base URL for page front-matter
+ return baseURL
+ }
+
+ // Initialize section anchors cache
+ if sectionAnchors == nil {
+ sectionAnchors = make(map[string]map[string]string)
+ }
+
+ // Map section names to their documentation URLs
+ sectionURL := getSectionDocumentationURL(baseURL, sectionName)
+
+ // Map some section names to their parent section for anchor extraction
+ parentSection := sectionName
+ if sectionName == "goldmark" || sectionName == "asciidocext" || sectionName == "highlight" || sectionName == "tableofcontents" {
+ parentSection = "markup"
+ }
+
+ // For section-specific properties, try to find actual anchors from the HTML
+ if len(propertyPath) > 0 {
+ // Get anchors for this section if not already cached
+ if _, exists := sectionAnchors[parentSection]; !exists {
+ sectionAnchors[parentSection] = extractSectionAnchors(parentSection)
+ }
+
+ // Try different anchor patterns based on property path
+ if anchors, exists := sectionAnchors[parentSection]; exists {
+ // Special case mappings for properties that don't follow standard naming
+ propertyName := propertyPath[len(propertyPath)-1]
+ if parentSection == "markup" && propertyName == "defaultMarkdownHandler" {
+ return sectionURL + "#default-handler"
+ }
+
+ // First try: just the property name (most specific)
+ if anchorID, found := anchors[propertyName]; found {
+ return sectionURL + "#" + anchorID
+ }
+
+ // Second try: property name in lowercase
+ if anchorID, found := anchors[strings.ToLower(propertyName)]; found {
+ return sectionURL + "#" + anchorID
+ }
+
+ // Third try: exact concatenated paths for known patterns (e.g., "rendererhardwraps" for renderer.hardWraps)
+ if len(propertyPath) > 1 {
+ fullPath := strings.ToLower(strings.Join(propertyPath, ""))
+ if anchorID, found := anchors[fullPath]; found {
+ return sectionURL + "#" + anchorID
+ }
+ }
+
+ // Fourth try: work backwards through the property path to find parent section anchors
+ // For extensions.typographer.disable, try: typographer, extensions
+ for i := len(propertyPath) - 2; i >= 0; i-- {
+ parentName := propertyPath[i]
+ if anchorID, found := anchors[parentName]; found {
+ return sectionURL + "#" + anchorID
+ }
+ if anchorID, found := anchors[strings.ToLower(parentName)]; found {
+ return sectionURL + "#" + anchorID
+ }
+ }
+ }
+
+ // Fallback: for nested properties, use full property path concatenation
+ if len(propertyPath) > 1 {
+ // For nested properties like renderer.unsafe, use concatenated path: rendererunsafe
+ fullPath := strings.ToLower(strings.Join(propertyPath, ""))
+ return sectionURL + "#" + fullPath
+ } else {
+ // For top-level properties, use kebab-case
+ anchor := camelToKebab(propertyPath[0])
+ return sectionURL + "#" + anchor
+ }
+ }
+
+ return sectionURL
+}
+
+// camelToKebab converts camelCase strings to kebab-case
+func camelToKebab(s string) string {
+ var result strings.Builder
+ for i, r := range s {
+ if i > 0 && unicode.IsUpper(r) {
+ result.WriteRune('-')
+ }
+ result.WriteRune(unicode.ToLower(r))
+ }
+ return result.String()
+}
+
+// extractAnchorsFromHTML extracts anchor IDs from the built Hugo documentation
+func extractAnchorsFromHTML() map[string]string {
+ anchors := make(map[string]string)
+
+ // Try different possible locations for the built docs using systematic approach
+ possiblePaths := getRootConfigDocPaths()
+
+ var htmlFile string
+ for _, path := range possiblePaths {
+ if _, err := os.Stat(path); err == nil {
+ htmlFile = path
+ break
+ }
+ }
+
+ if htmlFile == "" {
+ fmt.Printf("Warning: Could not find built documentation HTML file\n")
+ return anchors
+ }
+
+ content, err := os.ReadFile(htmlFile)
+ if err != nil {
+ fmt.Printf("Warning: Could not read documentation HTML file: %v\n", err)
+ return anchors
+ }
+
+ // Extract anchor IDs using regex
+ // Look for id="propertyname" patterns in dt elements
+ re := regexp.MustCompile(`
]+id="([^"]+)"[^>]*>([^<]+)`)
+ matches := re.FindAllStringSubmatch(string(content), -1)
+
+ for _, match := range matches {
+ if len(match) >= 3 {
+ anchorID := match[1]
+ propertyName := strings.TrimSpace(match[2])
+
+ // Skip non-property anchors (like "settings")
+ if anchorID != "settings" && propertyName != "" {
+ // Map both the original property name and lowercase version to the anchor
+ anchors[propertyName] = anchorID
+ anchors[strings.ToLower(propertyName)] = anchorID
+ }
+ }
+ }
+
+ fmt.Printf("Found %d configuration property anchors in documentation\n", len(anchors)/2)
+ return anchors
+}
+
+// getSectionPaths returns the possible HTML file paths for a given section
+func getSectionPaths(sectionName string) []string {
+ // Handle special cases where section name doesn't match directory name
+ dirName := sectionName
+ switch sectionName {
+ case "outputformats":
+ dirName = "output-formats"
+ case "mediatypes":
+ dirName = "media-types"
+ case "related":
+ dirName = "related-content"
+ case "frontmatter":
+ dirName = "front-matter"
+ }
+
+ // Try multiple possible base directories in order of preference
+ baseDirs := []string{
+ "docs/public", // Most likely location for built docs
+ "public-docs", // Alternative location
+ "../public-docs", // If running from subdirectory
+ "public", // Alternative name
+ }
+
+ var paths []string
+ for _, baseDir := range baseDirs {
+ path := filepath.Join(baseDir, "configuration", dirName, "index.html")
+ paths = append(paths, path)
+ }
+
+ return paths
+}
+
+// extractSectionAnchors extracts anchor IDs from a specific section's documentation page
+func extractSectionAnchors(sectionName string) map[string]string {
+ anchors := make(map[string]string)
+
+ // Get section paths using the getSectionPaths function
+ paths := getSectionPaths(sectionName)
+ if len(paths) == 0 {
+ return anchors
+ }
+
+ var htmlFile string
+ for _, path := range paths {
+ if _, err := os.Stat(path); err == nil {
+ htmlFile = path
+ break
+ }
+ }
+
+ if htmlFile == "" {
+ return anchors
+ }
+
+ content, err := os.ReadFile(htmlFile)
+ if err != nil {
+ return anchors
+ }
+
+ // Extract all anchor IDs from heading elements and definition lists
+ // Look for both and patterns
+ reHeadings := regexp.MustCompile(`]+id="([^"]+)"[^>]*>([^<]+)`)
+ reDefs := regexp.MustCompile(`]+id="([^"]+)"[^>]*>([^<]+)`)
+
+ // Extract from headings
+ matches := reHeadings.FindAllStringSubmatch(string(content), -1)
+ for _, match := range matches {
+ if len(match) >= 3 {
+ anchorID := match[1]
+ headingText := strings.TrimSpace(match[2])
+
+ if anchorID != "" && headingText != "" {
+ anchors[headingText] = anchorID
+ }
+ }
+ }
+
+ // Extract from definition terms
+ matches = reDefs.FindAllStringSubmatch(string(content), -1)
+ for _, match := range matches {
+ if len(match) >= 3 {
+ anchorID := match[1]
+ termText := strings.TrimSpace(match[2])
+
+ if anchorID != "" && termText != "" {
+ anchors[termText] = anchorID
+ }
+ }
+ }
+
+ return anchors
+}
+
+// getSectionDocumentationURL returns the documentation URL for a given section
+func getSectionDocumentationURL(baseURL, sectionName string) string {
+ // Handle special cases where section name doesn't match directory name
+ dirName := sectionName
+ switch sectionName {
+ case "outputformats":
+ dirName = "output-formats"
+ case "mediatypes":
+ dirName = "media-types"
+ case "related":
+ dirName = "related-content"
+ case "httpcache":
+ dirName = "http-cache"
+ case "frontmatter":
+ dirName = "front-matter"
+ case "highlight", "goldmark", "tableofcontents", "asciidocext":
+ // These are all subsections of markup
+ dirName = "markup"
+ }
+
+ // Simple systematic approach: baseURL already contains /configuration, just add /dirName/
+ return baseURL + "/" + dirName + "/"
+}
+
+// getSectionMappings returns a map of schema names to Config struct field names
+// These are the fields that have `mapstructure:"-"` tags and represent configuration sections
+func getSectionMappings() map[string]string {
+ return map[string]string{
+ "build": "Build",
+ "caches": "Caches",
+ "httpcache": "HTTPCache",
+ "markup": "Markup",
+ "outputs": "Outputs",
+ "deployment": "Deployment",
+ "module": "Module",
+ "frontmatter": "Frontmatter",
+ "minify": "Minify",
+ "permalinks": "Permalinks",
+ "taxonomies": "Taxonomies",
+ "sitemap": "Sitemap",
+ "related": "Related",
+ "server": "Server",
+ "pagination": "Pagination",
+ "page": "Page",
+ "privacy": "Privacy",
+ "security": "Security",
+ "services": "Services",
+ "params": "Params",
+ "languages": "Languages",
+ "uglyurls": "UglyURLs",
+ // ConfigNamespace types - now supported:
+ "contenttypes": "ContentTypes",
+ "mediatypes": "MediaTypes",
+ "imaging": "Imaging",
+ "outputformats": "OutputFormats",
+ "cascade": "Cascade",
+ "segments": "Segments",
+ "menus": "Menus",
+ }
+}
+
+// getRootConfigDocPaths returns the possible HTML file paths for the root configuration documentation
+func getRootConfigDocPaths() []string {
+ // Try multiple possible base directories in order of preference
+ baseDirs := []string{
+ "docs/public", // Most likely location for built docs
+ "public-docs", // Alternative location
+ "../public-docs", // If running from subdirectory
+ "public", // Alternative name
+ }
+
+ var paths []string
+ for _, baseDir := range baseDirs {
+ path := filepath.Join(baseDir, "configuration", "all", "index.html")
+ paths = append(paths, path)
+ }
+
+ return paths
+}
+
+// countSchemaProperties recursively counts all properties in a schema
+func countSchemaProperties(schema *jsonschema.Schema) int {
+ if schema == nil {
+ return 0
+ }
+
+ count := 0
+
+ // Count direct properties
+ if schema.Properties != nil {
+ count += schema.Properties.Len()
+
+ // Recursively count nested properties
+ for pair := schema.Properties.Oldest(); pair != nil; pair = pair.Next() {
+ count += countSchemaProperties(pair.Value)
+ }
+ }
+
+ // Count properties in definitions
+ if schema.Definitions != nil {
+ for _, defSchema := range schema.Definitions {
+ count += countSchemaProperties(defSchema)
+ }
+ }
+
+ // Count properties in array items
+ if schema.Items != nil {
+ count += countSchemaProperties(schema.Items)
+ }
+
+ // Count properties in additional properties
+ if schema.AdditionalProperties != nil {
+ count += countSchemaProperties(schema.AdditionalProperties)
+ }
+
+ // Count properties in conditional schemas
+ for _, condSchema := range schema.AnyOf {
+ count += countSchemaProperties(condSchema)
+ }
+ for _, condSchema := range schema.OneOf {
+ count += countSchemaProperties(condSchema)
+ }
+ for _, condSchema := range schema.AllOf {
+ count += countSchemaProperties(condSchema)
+ }
+ if schema.Not != nil {
+ count += countSchemaProperties(schema.Not)
+ }
+
+ return count
+}
+
+// countDocumentationLinks recursively counts all documentation links in a schema
+func countDocumentationLinks(schema *jsonschema.Schema) int {
+ if schema == nil {
+ return 0
+ }
+
+ count := 0
+
+ // Check if this schema has a documentation link in its description
+ if schema.Description != "" && strings.Contains(schema.Description, "https://gohugo.io") {
+ count++
+ }
+
+ // Count links in direct properties
+ if schema.Properties != nil {
+ for pair := schema.Properties.Oldest(); pair != nil; pair = pair.Next() {
+ count += countDocumentationLinks(pair.Value)
+ }
+ }
+
+ // Count links in definitions
+ if schema.Definitions != nil {
+ for _, defSchema := range schema.Definitions {
+ count += countDocumentationLinks(defSchema)
+ }
+ }
+
+ // Count links in array items
+ if schema.Items != nil {
+ count += countDocumentationLinks(schema.Items)
+ }
+
+ // Count links in additional properties
+ if schema.AdditionalProperties != nil {
+ count += countDocumentationLinks(schema.AdditionalProperties)
+ }
+
+ // Count links in conditional schemas
+ for _, condSchema := range schema.AnyOf {
+ count += countDocumentationLinks(condSchema)
+ }
+ for _, condSchema := range schema.OneOf {
+ count += countDocumentationLinks(condSchema)
+ }
+ for _, condSchema := range schema.AllOf {
+ count += countDocumentationLinks(condSchema)
+ }
+ if schema.Not != nil {
+ count += countDocumentationLinks(schema.Not)
+ }
+
+ return count
+}
+
+// printSchemaStats prints a summary of schema generation statistics
+func printSchemaStats(stats schemaStats, r *rootCommand) {
+ r.Println()
+ r.Println("Schema Generation Summary:")
+ r.Printf(" Schemas generated: %d\n", stats.schemasGenerated)
+ r.Printf(" Total properties: %d\n", stats.totalProperties)
+ r.Printf(" Documentation links: %d\n", stats.documentationLinks)
+ if stats.totalProperties > 0 {
+ coverage := float64(stats.documentationLinks) / float64(stats.totalProperties) * 100
+ r.Printf(" Documentation coverage: %.1f%%\n", coverage)
+ }
+}
diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go
index 0db0be1d8d5..8985fcab87f 100644
--- a/config/allconfig/allconfig.go
+++ b/config/allconfig/allconfig.go
@@ -669,7 +669,7 @@ type RootConfig struct {
// When using ref or relref to resolve page links and a link cannot be resolved, it will be logged with this log level.
// Valid values are ERROR (default) or WARNING. Any ERROR will fail the build (exit -1).
- RefLinksErrorLevel string
+ RefLinksErrorLevel string `jsonschema:"enum=ERROR,enum=WARNING"`
// This will create a menu with all the sections as menu items and all the sections’ pages as “shadow-members”.
SectionPagesMenu string
@@ -692,7 +692,7 @@ type RootConfig struct {
// Set titleCaseStyle to specify the title style used by the title template function and the automatic section titles in Hugo.
// It defaults to AP Stylebook for title casing, but you can also set it to Chicago or Go (every word starts with a capital letter).
- TitleCaseStyle string
+ TitleCaseStyle string `jsonschema:"enum=ap,enum=chicago,enum=go,enum=firstupper,enum=none"`
// The editor used for opening up new content.
NewContentEditor string
diff --git a/config/commonConfig.go b/config/commonConfig.go
index 9470786724f..2fe9062adc9 100644
--- a/config/commonConfig.go
+++ b/config/commonConfig.go
@@ -98,7 +98,7 @@ var defaultBuild = BuildConfig{
type BuildConfig struct {
// When to use the resource file cache.
// One of never, fallback, always. Default is fallback
- UseResourceCacheWhen string
+ UseResourceCacheWhen string `jsonschema:"enum=never,enum=fallback,enum=always"`
// When enabled, will collect and write a hugo_stats.json with some build
// related aggregated data (e.g. CSS class names).
@@ -208,7 +208,7 @@ func DecodeBuildConfig(cfg Provider) BuildConfig {
// SitemapConfig configures the sitemap to be generated.
type SitemapConfig struct {
// The page change frequency.
- ChangeFreq string
+ ChangeFreq string `jsonschema:"enum=always,enum=hourly,enum=daily,enum=weekly,enum=monthly,enum=yearly,enum=never"`
// The priority of the page.
Priority float64
// The sitemap filename.
@@ -498,10 +498,10 @@ type Pagination struct {
// PageConfig configures the behavior of pages.
type PageConfig struct {
// Sort order for Page.Next and Page.Prev. Default "desc" (the default page sort order in Hugo).
- NextPrevSortOrder string
+ NextPrevSortOrder string `jsonschema:"enum=asc,enum=desc"`
// Sort order for Page.NextInSection and Page.PrevInSection. Default "desc".
- NextPrevInSectionSortOrder string
+ NextPrevInSectionSortOrder string `jsonschema:"enum=asc,enum=desc"`
}
func (c *PageConfig) CompileConfig(loggers.Logger) error {
diff --git a/docs/content/en/commands/hugo_gen.md b/docs/content/en/commands/hugo_gen.md
index ae11a032129..1be0ffd5c8d 100644
--- a/docs/content/en/commands/hugo_gen.md
+++ b/docs/content/en/commands/hugo_gen.md
@@ -39,5 +39,6 @@ Generate documentation for your project using Hugo's documentation engine, inclu
* [hugo](/commands/hugo/) - Build your site
* [hugo gen chromastyles](/commands/hugo_gen_chromastyles/) - Generate CSS stylesheet for the Chroma code highlighter
* [hugo gen doc](/commands/hugo_gen_doc/) - Generate Markdown documentation for the Hugo CLI
+* [hugo gen jsonschemas](/commands/hugo_gen_jsonschemas/) - Generate JSON Schema for Hugo config and page structures
* [hugo gen man](/commands/hugo_gen_man/) - Generate man pages for the Hugo CLI
diff --git a/docs/content/en/commands/hugo_gen_jsonschemas.md b/docs/content/en/commands/hugo_gen_jsonschemas.md
new file mode 100644
index 00000000000..8ce5a639bba
--- /dev/null
+++ b/docs/content/en/commands/hugo_gen_jsonschemas.md
@@ -0,0 +1,45 @@
+---
+title: "hugo gen jsonschemas"
+slug: hugo_gen_jsonschemas
+url: /commands/hugo_gen_jsonschemas/
+---
+## hugo gen jsonschemas
+
+Generate JSON Schema for Hugo config and page structures
+
+### Synopsis
+
+Generate a JSON Schema for Hugo configuration options and page structures using reflection.
+
+```
+hugo gen jsonschemas [flags] [args]
+```
+
+### Options
+
+```
+ --dir string output directory for schema files (default "/tmp/hugo-schemas")
+ -h, --help help for jsonschemas
+```
+
+### Options inherited from parent commands
+
+```
+ --clock string set the clock used by Hugo, e.g. --clock 2021-11-06T22:30:00.00+09:00
+ --config string config file (default is hugo.yaml|json|toml)
+ --configDir string config dir (default "config")
+ -d, --destination string filesystem path to write files to
+ -e, --environment string build environment
+ --ignoreVendorPaths string ignores any _vendor for module paths matching the given Glob pattern
+ --logLevel string log level (debug|info|warn|error)
+ --noBuildLock don't create .hugo_build.lock file
+ --quiet build in quiet mode
+ -M, --renderToMemory render to memory (mostly useful when running the server)
+ -s, --source string filesystem path to read files relative from
+ --themesDir string filesystem path to themes directory
+```
+
+### SEE ALSO
+
+* [hugo gen](/commands/hugo_gen/) - Generate documentation and syntax highlighting styles
+
diff --git a/docs/content/en/jsonschemas/hugo-config-build.schema.json b/docs/content/en/jsonschemas/hugo-config-build.schema.json
new file mode 100644
index 00000000000..5b69d7ea56a
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-build.schema.json
@@ -0,0 +1,67 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-build.schema.json",
+ "properties": {
+ "useResourceCacheWhen": {
+ "oneOf": [
+ {
+ "const": "never"
+ },
+ {
+ "const": "fallback"
+ },
+ {
+ "const": "always"
+ }
+ ],
+ "type": "string",
+ "description": "When to use the resource file cache.\nOne of never, fallback, always. Default is fallback \nhttps://gohugo.io/configuration/build/#useresourcecachewhen"
+ },
+ "buildStats": {
+ "properties": {
+ "enable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/build/#enable"
+ },
+ "disableTags": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/build/#disabletags"
+ },
+ "disableClasses": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/build/#disableclasses"
+ },
+ "disableIDs": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/build/#disableids"
+ }
+ },
+ "type": "object",
+ "description": "When enabled, will collect and write a hugo_stats.json with some build\nrelated aggregated data (e.g. CSS class names).\nNote that this was a bool \u003c= v0.115.0. \nhttps://gohugo.io/configuration/build/#buildstats"
+ },
+ "noJSConfigInAssets": {
+ "type": "boolean",
+ "description": "Can be used to toggle off writing of the IntelliSense /assets/jsconfig.js\nfile. \nhttps://gohugo.io/configuration/build/#nojsconfiginassets"
+ },
+ "cacheBusters": {
+ "items": {
+ "properties": {
+ "source": {
+ "type": "string",
+ "description": "Trigger for files matching this regexp. \nhttps://gohugo.io/configuration/build/#source"
+ },
+ "target": {
+ "type": "string",
+ "description": "Cache bust targets matching this regexp.\nThis regexp can contain group matches (e.g. $1) from the source regexp. \nhttps://gohugo.io/configuration/build/#target"
+ }
+ },
+ "type": "object",
+ "description": "CacheBuster configures cache busting for assets."
+ },
+ "type": "array",
+ "description": "Can used to control how the resource cache gets evicted on rebuilds. \nhttps://gohugo.io/configuration/build/#cachebusters"
+ }
+ },
+ "type": "object",
+ "description": "BuildConfig holds some build related configuration."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-cascade.schema.json b/docs/content/en/jsonschemas/hugo-config-cascade.schema.json
new file mode 100644
index 00000000000..61ecb950f59
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-cascade.schema.json
@@ -0,0 +1,37 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-cascade.schema.json",
+ "properties": {
+ "params": {
+ "type": "object",
+ "description": "Apply Params to all Pages matching Target. \nhttps://gohugo.io/configuration/cascade/#params"
+ },
+ "fields": {
+ "type": "object",
+ "description": "Fields holds all fields but Params. \nhttps://gohugo.io/configuration/cascade/#fields"
+ },
+ "target": {
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "A Glob pattern matching the content path below /content.\nExpects Unix-styled slashes.\nNote that this is the virtual path, so it starts at the mount root\nwith a leading \"/\". \nhttps://gohugo.io/configuration/cascade/#path"
+ },
+ "kind": {
+ "type": "string",
+ "description": "A Glob pattern matching the Page's Kind(s), e.g. \"{home,section}\" \nhttps://gohugo.io/configuration/cascade/#kind"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A Glob pattern matching the Page's language, e.g. \"{en,sv}\". \nhttps://gohugo.io/configuration/cascade/#lang"
+ },
+ "environment": {
+ "type": "string",
+ "description": "A Glob pattern matching the Page's Environment, e.g. \"{production,development}\". \nhttps://gohugo.io/configuration/cascade/#environment"
+ }
+ },
+ "type": "object",
+ "description": "Target is the PageMatcher that this config applies to. \nhttps://gohugo.io/configuration/cascade/#target"
+ }
+ },
+ "type": "object"
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-contenttypes.schema.json b/docs/content/en/jsonschemas/hugo-config-contenttypes.schema.json
new file mode 100644
index 00000000000..34efb11c516
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-contenttypes.schema.json
@@ -0,0 +1,6 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-contenttypes.schema.json",
+ "properties": {},
+ "type": "object"
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-deployment.schema.json b/docs/content/en/jsonschemas/hugo-config-deployment.schema.json
new file mode 100644
index 00000000000..091d2dbe738
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-deployment.schema.json
@@ -0,0 +1,114 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-deployment.schema.json",
+ "properties": {
+ "targets": {
+ "items": {
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/deployment/#name"
+ },
+ "uRL": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/deployment/#url"
+ },
+ "cloudFrontDistributionID": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/deployment/#cloudfrontdistributionid"
+ },
+ "googleCloudCDNOrigin": {
+ "type": "string",
+ "description": "GoogleCloudCDNOrigin specifies the Google Cloud project and CDN origin to\ninvalidate when deploying this target. It is specified as \u003cproject\u003e/\u003corigin\u003e. \nhttps://gohugo.io/configuration/deployment/#googlecloudcdnorigin"
+ },
+ "include": {
+ "type": "string",
+ "description": "Optional patterns of files to include/exclude for this target.\nParsed using github.com/gobwas/glob. \nhttps://gohugo.io/configuration/deployment/#include"
+ },
+ "exclude": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/deployment/#exclude"
+ },
+ "stripIndexHTML": {
+ "type": "boolean",
+ "description": "If true, any local path matching \u003cdir\u003e/index.html will be mapped to the\nremote path \u003cdir\u003e/. This does not affect the top-level index.html file,\nsince that would result in an empty path. \nhttps://gohugo.io/configuration/deployment/#stripindexhtml"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/deployment/#targets"
+ },
+ "matchers": {
+ "items": {
+ "properties": {
+ "pattern": {
+ "type": "string",
+ "description": "Pattern is the string pattern to match against paths.\nMatching is done against paths converted to use / as the path separator. \nhttps://gohugo.io/configuration/deployment/#pattern"
+ },
+ "cacheControl": {
+ "type": "string",
+ "description": "CacheControl specifies caching attributes to use when serving the blob.\nhttps://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control \nhttps://gohugo.io/configuration/deployment/#cachecontrol"
+ },
+ "contentEncoding": {
+ "type": "string",
+ "description": "ContentEncoding specifies the encoding used for the blob's content, if any.\nhttps://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding \nhttps://gohugo.io/configuration/deployment/#contentencoding"
+ },
+ "contentType": {
+ "type": "string",
+ "description": "ContentType specifies the MIME type of the blob being written.\nhttps://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type \nhttps://gohugo.io/configuration/deployment/#contenttype"
+ },
+ "gzip": {
+ "type": "boolean",
+ "description": "Gzip determines whether the file should be gzipped before upload.\nIf so, the ContentEncoding field will automatically be set to \"gzip\". \nhttps://gohugo.io/configuration/deployment/#gzip"
+ },
+ "force": {
+ "type": "boolean",
+ "description": "Force indicates that matching files should be re-uploaded. Useful when\nother route-determined metadata (e.g., ContentType) has changed. \nhttps://gohugo.io/configuration/deployment/#force-1"
+ }
+ },
+ "type": "object",
+ "description": "Matcher represents configuration to be applied to files whose paths match a specified pattern."
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/deployment/#matchers"
+ },
+ "order": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/deployment/#order"
+ },
+ "target": {
+ "type": "string",
+ "description": "Usually set via flags.\nTarget deployment Name; defaults to the first one. \nhttps://gohugo.io/configuration/deployment/#target"
+ },
+ "confirm": {
+ "type": "boolean",
+ "description": "Show a confirm prompt before deploying. \nhttps://gohugo.io/configuration/deployment/#confirm"
+ },
+ "dryRun": {
+ "type": "boolean",
+ "description": "DryRun will try the deployment without any remote changes. \nhttps://gohugo.io/configuration/deployment/#dryrun"
+ },
+ "force": {
+ "type": "boolean",
+ "description": "Force will re-upload all files. \nhttps://gohugo.io/configuration/deployment/#force-1"
+ },
+ "invalidateCDN": {
+ "type": "boolean",
+ "description": "Invalidate the CDN cache listed in the deployment target. \nhttps://gohugo.io/configuration/deployment/#invalidatecdn"
+ },
+ "maxDeletes": {
+ "type": "integer",
+ "description": "MaxDeletes is the maximum number of files to delete. \nhttps://gohugo.io/configuration/deployment/#maxdeletes"
+ },
+ "workers": {
+ "type": "integer",
+ "description": "Number of concurrent workers to use when uploading files. \nhttps://gohugo.io/configuration/deployment/#workers"
+ }
+ },
+ "type": "object",
+ "description": "DeployConfig is the complete configuration for deployment."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-frontmatter.schema.json b/docs/content/en/jsonschemas/hugo-config-frontmatter.schema.json
new file mode 100644
index 00000000000..a499a48e18a
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-frontmatter.schema.json
@@ -0,0 +1,35 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-frontmatter.schema.json",
+ "properties": {
+ "date": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Controls how the Date is set from front matter. \nhttps://gohugo.io/configuration/front-matter/#dates"
+ },
+ "lastmod": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Controls how the Lastmod is set from front matter. \nhttps://gohugo.io/configuration/front-matter/#dates"
+ },
+ "publishDate": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Controls how the PublishDate is set from front matter. \nhttps://gohugo.io/configuration/front-matter/#dates"
+ },
+ "expiryDate": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Controls how the ExpiryDate is set from front matter. \nhttps://gohugo.io/configuration/front-matter/#dates"
+ }
+ },
+ "type": "object"
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-httpcache.schema.json b/docs/content/en/jsonschemas/hugo-config-httpcache.schema.json
new file mode 100644
index 00000000000..ed74cc1c95d
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-httpcache.schema.json
@@ -0,0 +1,76 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-httpcache.schema.json",
+ "properties": {
+ "cache": {
+ "properties": {
+ "for": {
+ "properties": {
+ "excludes": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Excludes holds a list of glob patterns that will be excluded. \nhttps://gohugo.io/configuration/http-cache/#cacheforexcludes"
+ },
+ "includes": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Includes holds a list of glob patterns that will be included. \nhttps://gohugo.io/configuration/http-cache/#cacheforincludes"
+ }
+ },
+ "type": "object",
+ "description": "Enable HTTP cache behavior (RFC 9111) for these resources. \nhttps://gohugo.io/configuration/http-cache/#cachefor"
+ }
+ },
+ "type": "object",
+ "description": "Configures the HTTP cache behavior (RFC 9111).\nWhen this is not enabled for a resource, Hugo will go straight to the file cache. \nhttps://gohugo.io/configuration/http-cache/#cache"
+ },
+ "polls": {
+ "items": {
+ "properties": {
+ "for": {
+ "properties": {
+ "excludes": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Excludes holds a list of glob patterns that will be excluded. \nhttps://gohugo.io/configuration/http-cache/#pollsforexcludes"
+ },
+ "includes": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Includes holds a list of glob patterns that will be included. \nhttps://gohugo.io/configuration/http-cache/#pollsforincludes"
+ }
+ },
+ "type": "object",
+ "description": "What remote resources to apply this configuration to. \nhttps://gohugo.io/configuration/http-cache/#pollsfor"
+ },
+ "disable": {
+ "type": "boolean",
+ "description": "Disable polling for this configuration. \nhttps://gohugo.io/configuration/http-cache/#pollsdisable"
+ },
+ "low": {
+ "type": "integer",
+ "description": "Low is the lower bound for the polling interval.\nThis is the starting point when the resource has recently changed,\nif that resource stops changing, the polling interval will gradually increase towards High. \nhttps://gohugo.io/configuration/http-cache/#pollslow"
+ },
+ "high": {
+ "type": "integer",
+ "description": "High is the upper bound for the polling interval.\nThis is the interval used when the resource is stable. \nhttps://gohugo.io/configuration/http-cache/#pollshigh"
+ }
+ },
+ "type": "object",
+ "description": "PollConfig holds the configuration for polling remote resources to detect changes in watch mode."
+ },
+ "type": "array",
+ "description": "Polls holds a list of configurations for polling remote resources to detect changes in watch mode.\nThis can be disabled for some resources, typically if they are known to not change. \nhttps://gohugo.io/configuration/http-cache/#polls"
+ }
+ },
+ "type": "object",
+ "description": "Config holds the configuration for the HTTP cache."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-imaging.schema.json b/docs/content/en/jsonschemas/hugo-config-imaging.schema.json
new file mode 100644
index 00000000000..601068d13e0
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-imaging.schema.json
@@ -0,0 +1,50 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-imaging.schema.json",
+ "properties": {
+ "quality": {
+ "type": "integer",
+ "description": "Default image quality setting (1-100). Only used for JPEG images. \nhttps://gohugo.io/configuration/imaging/#quality"
+ },
+ "resampleFilter": {
+ "type": "string",
+ "description": "Resample filter to use in resize operations. \nhttps://gohugo.io/configuration/imaging/#resamplefilter"
+ },
+ "hint": {
+ "type": "string",
+ "description": "Hint about what type of image this is.\nCurrently only used when encoding to Webp.\nDefault is \"photo\".\nValid values are \"picture\", \"photo\", \"drawing\", \"icon\", or \"text\". \nhttps://gohugo.io/configuration/imaging/#hint"
+ },
+ "anchor": {
+ "type": "string",
+ "description": "The anchor to use in Fill. Default is \"smart\", i.e. Smart Crop. \nhttps://gohugo.io/configuration/imaging/#anchor"
+ },
+ "bgColor": {
+ "type": "string",
+ "description": "Default color used in fill operations (e.g. \"fff\" for white). \nhttps://gohugo.io/configuration/imaging/#bgcolor"
+ },
+ "exif": {
+ "properties": {
+ "includeFields": {
+ "type": "string",
+ "description": "Regexp matching the Exif fields you want from the (massive) set of Exif info\navailable. As we cache this info to disk, this is for performance and\ndisk space reasons more than anything.\nIf you want it all, put \".*\" in this config setting.\nNote that if neither this or ExcludeFields is set, Hugo will return a small\ndefault set. \nhttps://gohugo.io/configuration/imaging/#includefields"
+ },
+ "excludeFields": {
+ "type": "string",
+ "description": "Regexp matching the Exif fields you want to exclude. This may be easier to use\nthan IncludeFields above, depending on what you want. \nhttps://gohugo.io/configuration/imaging/#excludefields"
+ },
+ "disableDate": {
+ "type": "boolean",
+ "description": "Hugo extracts the \"photo taken\" date/time into .Date by default.\nSet this to true to turn it off. \nhttps://gohugo.io/configuration/imaging/#disabledate"
+ },
+ "disableLatLong": {
+ "type": "boolean",
+ "description": "Hugo extracts the \"photo taken where\" (GPS latitude and longitude) into\n.Long and .Lat. Set this to true to turn it off. \nhttps://gohugo.io/configuration/imaging/#disablelatlong"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/imaging/#exif"
+ }
+ },
+ "type": "object",
+ "description": "ImagingConfig contains default image processing configuration."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-languages.schema.json b/docs/content/en/jsonschemas/hugo-config-languages.schema.json
new file mode 100644
index 00000000000..5b881ae96b2
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-languages.schema.json
@@ -0,0 +1,229 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-languages.schema.json",
+ "additionalProperties": {
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "properties": {
+ "languageName": {
+ "type": "string",
+ "description": "The language name, e.g. \"English\". \nhttps://gohugo.io/configuration/languages/#languagename"
+ },
+ "languageCode": {
+ "type": "string",
+ "description": "The language code, e.g. \"en-US\". \nhttps://gohugo.io/configuration/languages/#languagecode"
+ },
+ "title": {
+ "type": "string",
+ "description": "The language title. When set, this will\noverride site.Title for this language. \nhttps://gohugo.io/configuration/languages/#title"
+ },
+ "languageDirection": {
+ "oneOf": [
+ {
+ "const": "ltr"
+ },
+ {
+ "const": "rtl"
+ }
+ ],
+ "type": "string",
+ "description": "The language direction, e.g. \"ltr\" or \"rtl\". \nhttps://gohugo.io/configuration/languages/#languagedirection"
+ },
+ "weight": {
+ "type": "integer",
+ "description": "The language weight. When set to a non-zero value, this will\nbe the main sort criteria for the language. \nhttps://gohugo.io/configuration/languages/#weight"
+ },
+ "disabled": {
+ "type": "boolean",
+ "description": "Set to true to disable this language. \nhttps://gohugo.io/configuration/languages/#disabled"
+ },
+ "mainSections": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/languages/#main-sections"
+ },
+ "titleCaseStyle": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/languages/#title-case-style"
+ },
+ "buildDrafts": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#build-drafts"
+ },
+ "canonifyURLs": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#canonify-u-r-ls"
+ },
+ "disableLiveReload": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#disable-live-reload"
+ },
+ "refLinksNotFoundURL": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/languages/#ref-links-not-found-u-r-l"
+ },
+ "removePathAccents": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#remove-path-accents"
+ },
+ "sectionPagesMenu": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/languages/#section-pages-menu"
+ },
+ "staticDir": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/languages/#static-dir"
+ },
+ "timeZone": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/languages/#time-zone"
+ },
+ "buildExpired": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#build-expired"
+ },
+ "copyright": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/languages/#copyright"
+ },
+ "disableHugoGeneratorInject": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#disable-hugo-generator-inject"
+ },
+ "enableEmoji": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#enable-emoji"
+ },
+ "hasCJKLanguage": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#has-c-j-k-language"
+ },
+ "refLinksErrorLevel": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/languages/#ref-links-error-level"
+ },
+ "relativeURLs": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#relative-u-r-ls"
+ },
+ "summaryLength": {
+ "type": "integer",
+ "description": "https://gohugo.io/configuration/languages/#summary-length"
+ },
+ "baseURL": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/languages/#base-u-r-l"
+ },
+ "buildFuture": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#build-future"
+ },
+ "disableKinds": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/languages/#disable-kinds"
+ },
+ "disablePathToLower": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#disable-path-to-lower"
+ },
+ "pluralizeListTitles": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#pluralize-list-titles"
+ },
+ "renderSegments": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/languages/#render-segments"
+ },
+ "capitalizeListTitles": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#capitalize-list-titles"
+ },
+ "contentDir": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/languages/#content-dir"
+ },
+ "disableAliases": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/languages/#disable-aliases"
+ },
+ "frontmatter": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-frontmatter.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#frontmatter"
+ },
+ "markup": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-markup.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#markup"
+ },
+ "mediatypes": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-mediatypes.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#mediatypes"
+ },
+ "menus": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-menus.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#menus"
+ },
+ "outputformats": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-outputformats.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#outputformats"
+ },
+ "outputs": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-outputs.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#outputs"
+ },
+ "page": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-page.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#page"
+ },
+ "pagination": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-pagination.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#pagination"
+ },
+ "params": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-params.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#params"
+ },
+ "permalinks": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-permalinks.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#permalinks"
+ },
+ "privacy": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-privacy.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#privacy"
+ },
+ "related": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-related.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#related"
+ },
+ "security": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-security.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#security"
+ },
+ "services": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-services.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#services"
+ },
+ "sitemap": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-sitemap.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#sitemap"
+ },
+ "taxonomies": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-taxonomies.schema.json",
+ "description": "https://gohugo.io/configuration/languages/#taxonomies"
+ }
+ },
+ "type": "object",
+ "description": "LanguageConfig holds the configuration for a single language."
+ },
+ "type": "object",
+ "description": "Language configuration. Maps language code to language configuration."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-markup.schema.json b/docs/content/en/jsonschemas/hugo-config-markup.schema.json
new file mode 100644
index 00000000000..0145efb9aab
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-markup.schema.json
@@ -0,0 +1,521 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-markup.schema.json",
+ "$defs": {
+ "asciidocExt": {
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "properties": {
+ "backend": {
+ "oneOf": [
+ {
+ "const": "html5"
+ },
+ {
+ "const": "html5s"
+ },
+ {
+ "const": "xhtml5"
+ },
+ {
+ "const": "docbook5"
+ },
+ {
+ "const": "docbook45"
+ },
+ {
+ "const": "manpage"
+ }
+ ],
+ "type": "string",
+ "description": "https://gohugo.io/configuration/markup/#backend"
+ },
+ "extensions": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "attributes": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#attributes"
+ },
+ "noHeaderOrFooter": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#noheaderorfooter"
+ },
+ "safeMode": {
+ "oneOf": [
+ {
+ "const": "unsafe"
+ },
+ {
+ "const": "safe"
+ },
+ {
+ "const": "server"
+ },
+ {
+ "const": "secure"
+ }
+ ],
+ "type": "string",
+ "description": "https://gohugo.io/configuration/markup/#safemode"
+ },
+ "sectionNumbers": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#sectionnumbers"
+ },
+ "verbose": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#verbose"
+ },
+ "trace": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#trace"
+ },
+ "failureLevel": {
+ "oneOf": [
+ {
+ "const": "fatal"
+ },
+ {
+ "const": "warn"
+ }
+ ],
+ "type": "string",
+ "description": "https://gohugo.io/configuration/markup/#failurelevel"
+ },
+ "workingFolderCurrent": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#workingfoldercurrent"
+ },
+ "preserveTOC": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#preservetoc"
+ }
+ },
+ "type": "object",
+ "description": "Config configures asciidoc."
+ },
+ "goldmark": {
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "properties": {
+ "renderer": {
+ "properties": {
+ "hardWraps": {
+ "type": "boolean",
+ "description": "Whether softline breaks should be rendered as '\u003cbr\u003e' \nhttps://gohugo.io/configuration/markup/#rendererhardwraps"
+ },
+ "xHTML": {
+ "type": "boolean",
+ "description": "XHTML instead of HTML5. \nhttps://gohugo.io/configuration/markup/#rendererxhtml"
+ },
+ "unsafe": {
+ "type": "boolean",
+ "description": "Allow raw HTML etc. \nhttps://gohugo.io/configuration/markup/#rendererunsafe"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#renderer"
+ },
+ "parser": {
+ "properties": {
+ "autoHeadingID": {
+ "type": "boolean",
+ "description": "Enables custom heading ids and\nauto generated heading ids. \nhttps://gohugo.io/configuration/markup/#parserautoheadingid"
+ },
+ "autoDefinitionTermID": {
+ "type": "boolean",
+ "description": "Enables auto definition term ids. \nhttps://gohugo.io/configuration/markup/#parserautodefinitiontermid"
+ },
+ "autoIDType": {
+ "oneOf": [
+ {
+ "const": "github"
+ },
+ {
+ "const": "github-ascii"
+ },
+ {
+ "const": "blackfriday"
+ }
+ ],
+ "type": "string",
+ "description": "The strategy to use when generating IDs.\nAvailable options are \"github\", \"github-ascii\", and \"blackfriday\".\nDefault is \"github\", which will create GitHub-compatible anchor names. \nhttps://gohugo.io/configuration/markup/#parserautoidtype"
+ },
+ "attribute": {
+ "properties": {
+ "title": {
+ "type": "boolean",
+ "description": "Enables custom attributes for titles. \nhttps://gohugo.io/configuration/markup/#parserattributetitle"
+ },
+ "block": {
+ "type": "boolean",
+ "description": "Enables custom attributes for blocks. \nhttps://gohugo.io/configuration/markup/#parserattributeblock"
+ }
+ },
+ "type": "object",
+ "description": "Enables custom attributes. \nhttps://gohugo.io/configuration/markup/#parserattribute"
+ },
+ "wrapStandAloneImageWithinParagraph": {
+ "type": "boolean",
+ "description": "Whether to wrap stand-alone images within a paragraph or not. \nhttps://gohugo.io/configuration/markup/#parserwrapstandaloneimagewithinparagraph"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#parser"
+ },
+ "extensions": {
+ "properties": {
+ "typographer": {
+ "properties": {
+ "disable": {
+ "type": "boolean",
+ "description": "Whether to disable typographer. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "leftSingleQuote": {
+ "type": "string",
+ "description": "Value used for left single quote. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "rightSingleQuote": {
+ "type": "string",
+ "description": "Value used for right single quote. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "leftDoubleQuote": {
+ "type": "string",
+ "description": "Value used for left double quote. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "rightDoubleQuote": {
+ "type": "string",
+ "description": "Value used for right double quote. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "enDash": {
+ "type": "string",
+ "description": "Value used for en dash. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "emDash": {
+ "type": "string",
+ "description": "Value used for em dash. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "ellipsis": {
+ "type": "string",
+ "description": "Value used for ellipsis. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "leftAngleQuote": {
+ "type": "string",
+ "description": "Value used for left angle quote. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "rightAngleQuote": {
+ "type": "string",
+ "description": "Value used for right angle quote. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "apostrophe": {
+ "type": "string",
+ "description": "Value used for apostrophe. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "footnote": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "definitionList": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "extras": {
+ "properties": {
+ "delete": {
+ "properties": {
+ "enable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "insert": {
+ "properties": {
+ "enable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "mark": {
+ "properties": {
+ "enable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "subscript": {
+ "properties": {
+ "enable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "superscript": {
+ "properties": {
+ "enable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "passthrough": {
+ "properties": {
+ "enable": {
+ "type": "boolean",
+ "description": "Whether to enable the extension \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "delimiters": {
+ "properties": {
+ "inline": {
+ "items": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "type": "array",
+ "description": "The delimiters to use for inline passthroughs. Each entry in the list\nis a size-2 list of strings, where the first string is the opening delimiter\nand the second string is the closing delimiter, e.g.,\n\n[[\"$\", \"$\"], [\"\\\\(\", \"\\\\)\"]] \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "block": {
+ "items": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "type": "array",
+ "description": "The delimiters to use for block passthroughs. Same format as Inline. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "The delimiters to use for inline and block passthroughs. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "table": {
+ "type": "boolean",
+ "description": "GitHub flavored markdown \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "strikethrough": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "linkify": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "linkifyProtocol": {
+ "oneOf": [
+ {
+ "const": "http"
+ },
+ {
+ "const": "https"
+ }
+ ],
+ "type": "string",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "taskList": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "cJK": {
+ "properties": {
+ "enable": {
+ "type": "boolean",
+ "description": "Whether to enable CJK support. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "eastAsianLineBreaks": {
+ "type": "boolean",
+ "description": "Whether softline breaks between east asian wide characters should be ignored. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "eastAsianLineBreaksStyle": {
+ "oneOf": [
+ {
+ "const": "simple"
+ },
+ {
+ "const": "css3draft"
+ }
+ ],
+ "type": "string",
+ "description": "Styles of Line Breaking of EastAsianLineBreaks: \"simple\" or \"css3draft\" \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "escapedSpace": {
+ "type": "boolean",
+ "description": "Whether a '\\' escaped half-space(0x20) should not be rendered. \nhttps://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#extensions-1"
+ },
+ "duplicateResourceFiles": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#duplicateresourcefiles"
+ },
+ "renderHooks": {
+ "properties": {
+ "image": {
+ "properties": {
+ "enableDefault": {
+ "type": "boolean",
+ "description": "Enable the default image render hook.\nWe need to know if it is set or not, hence the pointer. \nhttps://gohugo.io/configuration/markup/#renderhooksimageenabledefault"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#renderhooksimage"
+ },
+ "link": {
+ "properties": {
+ "enableDefault": {
+ "type": "boolean",
+ "description": "Disable the default image render hook.\nWe need to know if it is set or not, hence the pointer. \nhttps://gohugo.io/configuration/markup/#renderhookslinkenabledefault"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#renderhookslink"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/markup/#render-hooks"
+ }
+ },
+ "type": "object",
+ "description": "Config configures Goldmark."
+ },
+ "highlight": {
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "properties": {
+ "style": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/markup/#style"
+ },
+ "codeFences": {
+ "type": "boolean",
+ "description": "Enable syntax highlighting of fenced code blocks. \nhttps://gohugo.io/configuration/markup/#codefences"
+ },
+ "wrapperClass": {
+ "type": "string",
+ "description": "The class or classes to use for the outermost element of the highlighted code. \nhttps://gohugo.io/configuration/markup/#wrapperclass"
+ },
+ "noClasses": {
+ "type": "boolean",
+ "description": "Use inline CSS styles. \nhttps://gohugo.io/configuration/markup/#noclasses"
+ },
+ "lineNos": {
+ "type": "boolean",
+ "description": "When set, line numbers will be printed. \nhttps://gohugo.io/configuration/markup/#linenos"
+ },
+ "lineNumbersInTable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#linenumbersintable"
+ },
+ "anchorLineNos": {
+ "type": "boolean",
+ "description": "When set, add links to line numbers \nhttps://gohugo.io/configuration/markup/#anchorlinenos"
+ },
+ "lineAnchors": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/markup/#lineanchors"
+ },
+ "lineNoStart": {
+ "type": "integer",
+ "description": "Start the line numbers from this value (default is 1). \nhttps://gohugo.io/configuration/markup/#linenostart"
+ },
+ "hl_Lines": {
+ "type": "string",
+ "description": "A space separated list of line numbers, e.g. “3-8 10-20”. \nhttps://gohugo.io/configuration/markup/#hl_lines"
+ },
+ "hl_inline": {
+ "type": "boolean",
+ "description": "If set, the markup will not be wrapped in any container. \nhttps://gohugo.io/configuration/markup/#hl_inline"
+ },
+ "tabWidth": {
+ "type": "integer",
+ "description": "TabWidth sets the number of characters for a tab. Defaults to 4. \nhttps://gohugo.io/configuration/markup/#tabwidth"
+ },
+ "guessSyntax": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/markup/#guesssyntax"
+ }
+ },
+ "type": "object"
+ },
+ "tableOfContents": {
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "properties": {
+ "startLevel": {
+ "type": "integer",
+ "description": "Heading start level to include in the table of contents, starting\nat h1 (inclusive).\n\u003cdocsmeta\u003e{ \"identifiers\": [\"h1\"] }\u003c/docsmeta\u003e \nhttps://gohugo.io/configuration/markup/#startlevel"
+ },
+ "endLevel": {
+ "type": "integer",
+ "description": "Heading end level, inclusive, to include in the table of contents.\nDefault is 3, a value of -1 will include everything. \nhttps://gohugo.io/configuration/markup/#endlevel"
+ },
+ "ordered": {
+ "type": "boolean",
+ "description": "Whether to produce a ordered list or not. \nhttps://gohugo.io/configuration/markup/#ordered"
+ }
+ },
+ "type": "object"
+ }
+ },
+ "properties": {
+ "defaultMarkdownHandler": {
+ "type": "string",
+ "description": "Default markdown handler for md/markdown extensions. Default is 'goldmark'. \nhttps://gohugo.io/configuration/markup/#default-handler"
+ },
+ "highlight": {
+ "$ref": "#/$defs/highlight",
+ "description": "Configuration for syntax highlighting. \nhttps://gohugo.io/configuration/markup/#highlight"
+ },
+ "tableOfContents": {
+ "$ref": "#/$defs/tableOfContents",
+ "description": "Table of contents configuration. \nhttps://gohugo.io/configuration/markup/#table-of-contents"
+ },
+ "goldmark": {
+ "$ref": "#/$defs/goldmark",
+ "description": "Configuration for the Goldmark markdown engine. \nhttps://gohugo.io/configuration/markup/#goldmark"
+ },
+ "asciidocExt": {
+ "$ref": "#/$defs/asciidocExt",
+ "description": "Configuration for the Asciidoc external markdown engine. \nhttps://gohugo.io/configuration/markup/#asciidoc-ext"
+ }
+ },
+ "type": "object",
+ "description": "Configuration for markup processing"
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-mediatypes.schema.json b/docs/content/en/jsonschemas/hugo-config-mediatypes.schema.json
new file mode 100644
index 00000000000..be31445ffb5
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-mediatypes.schema.json
@@ -0,0 +1,19 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-mediatypes.schema.json",
+ "properties": {
+ "suffixes": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "The file suffixes used for this media type. \nhttps://gohugo.io/configuration/media-types/#suffixes"
+ },
+ "delimiter": {
+ "type": "string",
+ "description": "Delimiter used before suffix. \nhttps://gohugo.io/configuration/media-types/#delimiter"
+ }
+ },
+ "type": "object",
+ "description": "Hold the configuration for a given media type."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-menus.schema.json b/docs/content/en/jsonschemas/hugo-config-menus.schema.json
new file mode 100644
index 00000000000..d75f6549e7a
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-menus.schema.json
@@ -0,0 +1,48 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-menus.schema.json",
+ "properties": {
+ "identifier": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/menus/#identifier"
+ },
+ "parent": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/menus/#parent"
+ },
+ "name": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/menus/#name"
+ },
+ "pre": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/menus/#pre"
+ },
+ "post": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/menus/#post"
+ },
+ "uRL": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/menus/#url"
+ },
+ "pageRef": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/menus/#pageref"
+ },
+ "weight": {
+ "type": "integer",
+ "description": "https://gohugo.io/configuration/menus/#weight"
+ },
+ "title": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/menus/#title"
+ },
+ "params": {
+ "type": "object",
+ "description": "User defined params. \nhttps://gohugo.io/configuration/menus/#params"
+ }
+ },
+ "type": "object",
+ "description": "MenuConfig holds the configuration for a menu."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-minify.schema.json b/docs/content/en/jsonschemas/hugo-config-minify.schema.json
new file mode 100644
index 00000000000..b62f9339f47
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-minify.schema.json
@@ -0,0 +1,166 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-minify.schema.json",
+ "properties": {
+ "minifyOutput": {
+ "type": "boolean",
+ "description": "Whether to minify the published output (the HTML written to /public). \nhttps://gohugo.io/configuration/minify/#minify-output"
+ },
+ "disableHTML": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#disable-h-t-m-l"
+ },
+ "disableCSS": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#disable-c-s-s"
+ },
+ "disableJS": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#disable-j-s"
+ },
+ "disableJSON": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#disable-j-s-o-n"
+ },
+ "disableSVG": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#disable-s-v-g"
+ },
+ "disableXML": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#disable-x-m-l"
+ },
+ "tdewolff": {
+ "properties": {
+ "hTML": {
+ "properties": {
+ "keepComments": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtmlkeepcomments"
+ },
+ "keepConditionalComments": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtmlkeepconditionalcomments"
+ },
+ "keepSpecialComments": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtmlkeepspecialcomments"
+ },
+ "keepDefaultAttrVals": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtmlkeepdefaultattrvals"
+ },
+ "keepDocumentTags": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtmlkeepdocumenttags"
+ },
+ "keepEndTags": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtmlkeependtags"
+ },
+ "keepQuotes": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtmlkeepquotes"
+ },
+ "keepWhitespace": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtmlkeepwhitespace"
+ },
+ "templateDelims": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "maxItems": 2,
+ "minItems": 2,
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtmltemplatedelims"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffhtml"
+ },
+ "cSS": {
+ "properties": {
+ "keepCSS2": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffcsskeepcss2"
+ },
+ "precision": {
+ "type": "integer",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffcssprecision"
+ },
+ "inline": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffcssinline"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffcss"
+ },
+ "jS": {
+ "properties": {
+ "precision": {
+ "type": "integer",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffjsprecision"
+ },
+ "keepVarNames": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffjskeepvarnames"
+ },
+ "version": {
+ "type": "integer",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffjsversion"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffjs"
+ },
+ "jSON": {
+ "properties": {
+ "precision": {
+ "type": "integer",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffjsonprecision"
+ },
+ "keepNumbers": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffjsonkeepnumbers"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffjson"
+ },
+ "sVG": {
+ "properties": {
+ "keepComments": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffsvgkeepcomments"
+ },
+ "precision": {
+ "type": "integer",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffsvgprecision"
+ },
+ "inline": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffsvginline"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffsvg"
+ },
+ "xML": {
+ "properties": {
+ "keepWhitespace": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffxmlkeepwhitespace"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/minify/#tdewolffxml"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/minify/#tdewolff"
+ }
+ },
+ "type": "object"
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-module.schema.json b/docs/content/en/jsonschemas/hugo-config-module.schema.json
new file mode 100644
index 00000000000..3a14d0c667b
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-module.schema.json
@@ -0,0 +1,160 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-module.schema.json",
+ "properties": {
+ "mounts": {
+ "items": {
+ "properties": {
+ "source": {
+ "type": "string",
+ "description": "Relative path in source repo, e.g. \"scss\". \nhttps://gohugo.io/configuration/module/#source"
+ },
+ "target": {
+ "type": "string",
+ "description": "Relative target path, e.g. \"assets/bootstrap/scss\". \nhttps://gohugo.io/configuration/module/#target"
+ },
+ "lang": {
+ "type": "string",
+ "description": "Any file in this mount will be associated with this language. \nhttps://gohugo.io/configuration/module/#lang"
+ },
+ "includeFiles": {
+ "description": "Include only files matching the given Glob patterns (string or slice). \nhttps://gohugo.io/configuration/module/#includefiles"
+ },
+ "excludeFiles": {
+ "description": "Exclude all files matching the given Glob patterns (string or slice). \nhttps://gohugo.io/configuration/module/#excludefiles"
+ },
+ "disableWatch": {
+ "type": "boolean",
+ "description": "Disable watching in watch mode for this mount. \nhttps://gohugo.io/configuration/module/#disablewatch"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array",
+ "description": "File system mounts. \nhttps://gohugo.io/configuration/module/#mounts"
+ },
+ "imports": {
+ "items": {
+ "properties": {
+ "path": {
+ "type": "string",
+ "description": "Module path \nhttps://gohugo.io/configuration/module/#path"
+ },
+ "ignoreConfig": {
+ "type": "boolean",
+ "description": "Ignore any config in config.toml (will still follow imports). \nhttps://gohugo.io/configuration/module/#ignoreconfig"
+ },
+ "ignoreImports": {
+ "type": "boolean",
+ "description": "Do not follow any configured imports. \nhttps://gohugo.io/configuration/module/#ignoreimports"
+ },
+ "noMounts": {
+ "type": "boolean",
+ "description": "Do not mount any folder in this import. \nhttps://gohugo.io/configuration/module/#nomounts"
+ },
+ "noVendor": {
+ "type": "boolean",
+ "description": "Never vendor this import (only allowed in main project). \nhttps://gohugo.io/configuration/module/#novendor-1"
+ },
+ "disable": {
+ "type": "boolean",
+ "description": "Turn off this module. \nhttps://gohugo.io/configuration/module/#disable"
+ },
+ "mounts": {
+ "items": {
+ "properties": {
+ "source": {
+ "type": "string",
+ "description": "Relative path in source repo, e.g. \"scss\". \nhttps://gohugo.io/configuration/module/#source"
+ },
+ "target": {
+ "type": "string",
+ "description": "Relative target path, e.g. \"assets/bootstrap/scss\". \nhttps://gohugo.io/configuration/module/#target"
+ },
+ "lang": {
+ "type": "string",
+ "description": "Any file in this mount will be associated with this language. \nhttps://gohugo.io/configuration/module/#lang"
+ },
+ "includeFiles": {
+ "description": "Include only files matching the given Glob patterns (string or slice). \nhttps://gohugo.io/configuration/module/#includefiles"
+ },
+ "excludeFiles": {
+ "description": "Exclude all files matching the given Glob patterns (string or slice). \nhttps://gohugo.io/configuration/module/#excludefiles"
+ },
+ "disableWatch": {
+ "type": "boolean",
+ "description": "Disable watching in watch mode for this mount. \nhttps://gohugo.io/configuration/module/#disablewatch"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array",
+ "description": "File mounts. \nhttps://gohugo.io/configuration/module/#importsmounts"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array",
+ "description": "Module imports. \nhttps://gohugo.io/configuration/module/#imports"
+ },
+ "params": {
+ "type": "object",
+ "description": "Meta info about this module (license information etc.). \nhttps://gohugo.io/configuration/module/#params"
+ },
+ "hugoVersion": {
+ "properties": {
+ "min": {
+ "type": "string",
+ "description": "The minimum Hugo version that this module works with. \nhttps://gohugo.io/configuration/module/#min"
+ },
+ "max": {
+ "type": "string",
+ "description": "The maximum Hugo version that this module works with. \nhttps://gohugo.io/configuration/module/#max"
+ },
+ "extended": {
+ "type": "boolean",
+ "description": "Set if the extended version is needed. \nhttps://gohugo.io/configuration/module/#extended"
+ }
+ },
+ "type": "object",
+ "description": "Will be validated against the running Hugo version. \nhttps://gohugo.io/configuration/module/#hugo-version"
+ },
+ "noVendor": {
+ "type": "string",
+ "description": "Optional Glob pattern matching module paths to skip when vendoring, e.g. “github.com/**” \nhttps://gohugo.io/configuration/module/#novendor-1"
+ },
+ "vendorClosest": {
+ "type": "boolean",
+ "description": "When enabled, we will pick the vendored module closest to the module\nusing it.\nThe default behavior is to pick the first.\nNote that there can still be only one dependency of a given module path,\nso once it is in use it cannot be redefined. \nhttps://gohugo.io/configuration/module/#vendorclosest"
+ },
+ "replacements": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "A comma separated (or a slice) list of module path to directory replacement mapping,\ne.g. github.com/bep/my-theme -\u003e ../..,github.com/bep/shortcodes -\u003e /some/path.\nThis is mostly useful for temporary locally development of a module, and then it makes sense to set it as an\nOS environment variable, e.g: env HUGO_MODULE_REPLACEMENTS=\"github.com/bep/my-theme -\u003e ../..\".\nAny relative path is relate to themesDir, and absolute paths are allowed. \nhttps://gohugo.io/configuration/module/#replacements"
+ },
+ "proxy": {
+ "type": "string",
+ "description": "Defines the proxy server to use to download remote modules. Default is direct, which means “git clone” and similar.\nConfigures GOPROXY when running the Go command for module operations. \nhttps://gohugo.io/configuration/module/#proxy"
+ },
+ "noProxy": {
+ "type": "string",
+ "description": "Comma separated glob list matching paths that should not use the proxy configured above.\nConfigures GONOPROXY when running the Go command for module operations. \nhttps://gohugo.io/configuration/module/#noproxy"
+ },
+ "private": {
+ "type": "string",
+ "description": "Comma separated glob list matching paths that should be treated as private.\nConfigures GOPRIVATE when running the Go command for module operations. \nhttps://gohugo.io/configuration/module/#private"
+ },
+ "auth": {
+ "type": "string",
+ "description": "Configures GOAUTH when running the Go command for module operations.\nThis is a semicolon-separated list of authentication commands for go-import and HTTPS module mirror interactions.\nThis is useful for private repositories.\nSee `go help goauth` for more information. \nhttps://gohugo.io/configuration/module/#auth"
+ },
+ "workspace": {
+ "type": "string",
+ "description": "Defaults to \"off\".\nSet to a work file, e.g. hugo.work, to enable Go \"Workspace\" mode.\nCan be relative to the working directory or absolute.\nRequires Go 1.18+.\nNote that this can also be set via OS env, e.g. export HUGO_MODULE_WORKSPACE=/my/hugo.work. \nhttps://gohugo.io/configuration/module/#workspace"
+ }
+ },
+ "type": "object",
+ "description": "Config holds a module config."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-outputformats.schema.json b/docs/content/en/jsonschemas/hugo-config-outputformats.schema.json
new file mode 100644
index 00000000000..ad38f22d6d0
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-outputformats.schema.json
@@ -0,0 +1,60 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-outputformats.schema.json",
+ "properties": {
+ "mediaType": {
+ "type": "string",
+ "description": "The MediaType string. This must be a configured media type. \nhttps://gohugo.io/configuration/output-formats/#mediatype"
+ },
+ "path": {
+ "type": "string",
+ "description": "Must be set to a value when there are two or more conflicting mediatype for the same resource. \nhttps://gohugo.io/configuration/output-formats/#path"
+ },
+ "baseName": {
+ "type": "string",
+ "description": "The base output file name used when not using \"ugly URLs\", defaults to \"index\". \nhttps://gohugo.io/configuration/output-formats/#basename"
+ },
+ "rel": {
+ "type": "string",
+ "description": "The value to use for rel links. \nhttps://gohugo.io/configuration/output-formats/#rel"
+ },
+ "protocol": {
+ "type": "string",
+ "description": "The protocol to use, i.e. \"webcal://\". Defaults to the protocol of the baseURL. \nhttps://gohugo.io/configuration/output-formats/#protocol"
+ },
+ "isPlainText": {
+ "type": "boolean",
+ "description": "IsPlainText decides whether to use text/template or html/template\nas template parser. \nhttps://gohugo.io/configuration/output-formats/#isplaintext"
+ },
+ "isHTML": {
+ "type": "boolean",
+ "description": "IsHTML returns whether this format is int the HTML family. This includes\nHTML, AMP etc. This is used to decide when to create alias redirects etc. \nhttps://gohugo.io/configuration/output-formats/#ishtml"
+ },
+ "noUgly": {
+ "type": "boolean",
+ "description": "Enable to ignore the global uglyURLs setting. \nhttps://gohugo.io/configuration/output-formats/#nougly"
+ },
+ "ugly": {
+ "type": "boolean",
+ "description": "Enable to override the global uglyURLs setting. \nhttps://gohugo.io/configuration/output-formats/#ugly"
+ },
+ "notAlternative": {
+ "type": "boolean",
+ "description": "Enable if it doesn't make sense to include this format in an alternative\nformat listing, CSS being one good example.\nNote that we use the term \"alternative\" and not \"alternate\" here, as it\ndoes not necessarily replace the other format, it is an alternative representation. \nhttps://gohugo.io/configuration/output-formats/#notalternative"
+ },
+ "root": {
+ "type": "boolean",
+ "description": "Eneable if this is a resource which path always starts at the root,\ne.g. /robots.txt. \nhttps://gohugo.io/configuration/output-formats/#root"
+ },
+ "permalinkable": {
+ "type": "boolean",
+ "description": "Setting this will make this output format control the value of\n.Permalink and .RelPermalink for a rendered Page.\nIf not set, these values will point to the main (first) output format\nconfigured. That is probably the behavior you want in most situations,\nas you probably don't want to link back to the RSS version of a page, as an\nexample. AMP would, however, be a good example of an output format where this\nbehavior is wanted. \nhttps://gohugo.io/configuration/output-formats/#permalinkable"
+ },
+ "weight": {
+ "type": "integer",
+ "description": "Setting this to a non-zero value will be used as the first sort criteria. \nhttps://gohugo.io/configuration/output-formats/#weight"
+ }
+ },
+ "type": "object",
+ "description": "OutputFormatConfig configures a single output format."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-outputs.schema.json b/docs/content/en/jsonschemas/hugo-config-outputs.schema.json
new file mode 100644
index 00000000000..0985304bb6b
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-outputs.schema.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-outputs.schema.json",
+ "additionalProperties": {
+ "items": {
+ "type": "string",
+ "description": "Output format name"
+ },
+ "type": "array",
+ "description": "List of output formats for this page kind"
+ },
+ "type": "object",
+ "description": "Output format configuration. Maps page kind to list of output formats."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-page.schema.json b/docs/content/en/jsonschemas/hugo-config-page.schema.json
new file mode 100644
index 00000000000..0c86aee363c
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-page.schema.json
@@ -0,0 +1,32 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-page.schema.json",
+ "properties": {
+ "nextPrevSortOrder": {
+ "oneOf": [
+ {
+ "const": "asc"
+ },
+ {
+ "const": "desc"
+ }
+ ],
+ "type": "string",
+ "description": "Sort order for Page.Next and Page.Prev. Default \"desc\" (the default page sort order in Hugo). \nhttps://gohugo.io/configuration/page/#next-prev-sort-order"
+ },
+ "nextPrevInSectionSortOrder": {
+ "oneOf": [
+ {
+ "const": "asc"
+ },
+ {
+ "const": "desc"
+ }
+ ],
+ "type": "string",
+ "description": "Sort order for Page.NextInSection and Page.PrevInSection. Default \"desc\". \nhttps://gohugo.io/configuration/page/#next-prev-in-section-sort-order"
+ }
+ },
+ "type": "object",
+ "description": "PageConfig configures the behavior of pages."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-pagination.schema.json b/docs/content/en/jsonschemas/hugo-config-pagination.schema.json
new file mode 100644
index 00000000000..e8947892655
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-pagination.schema.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-pagination.schema.json",
+ "properties": {
+ "pagerSize": {
+ "type": "integer",
+ "description": "Default number of elements per pager in pagination. \nhttps://gohugo.io/configuration/pagination/#pagersize"
+ },
+ "path": {
+ "type": "string",
+ "description": "The path element used during pagination. \nhttps://gohugo.io/configuration/pagination/#path"
+ },
+ "disableAliases": {
+ "type": "boolean",
+ "description": "Whether to disable generation of alias for the first pagination page. \nhttps://gohugo.io/configuration/pagination/#disablealiases"
+ }
+ },
+ "type": "object",
+ "description": "Pagination configures the pagination behavior."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-permalinks.schema.json b/docs/content/en/jsonschemas/hugo-config-permalinks.schema.json
new file mode 100644
index 00000000000..80bde9c8412
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-permalinks.schema.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-permalinks.schema.json",
+ "additionalProperties": {
+ "additionalProperties": {
+ "type": "string",
+ "description": "The permalink pattern for this section"
+ },
+ "type": "object",
+ "description": "Permalink patterns for this content kind"
+ },
+ "type": "object",
+ "description": "Permalink configuration. Maps content kind (page, section, term, taxonomy) to permalink patterns."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-privacy.schema.json b/docs/content/en/jsonschemas/hugo-config-privacy.schema.json
new file mode 100644
index 00000000000..4b6a5d464e3
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-privacy.schema.json
@@ -0,0 +1,114 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-privacy.schema.json",
+ "properties": {
+ "disqus": {
+ "properties": {
+ "disable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/privacy/#disqusdisable"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/privacy/#disqus"
+ },
+ "googleAnalytics": {
+ "properties": {
+ "disable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/privacy/#googleanalyticsdisable"
+ },
+ "respectDoNotTrack": {
+ "type": "boolean",
+ "description": "Enabling this will make the GA templates respect the\n\"Do Not Track\" HTTP header. See https://www.paulfurley.com/google-analytics-dnt/. \nhttps://gohugo.io/configuration/privacy/#googleanalyticsrespectdonottrack"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/privacy/#google-analytics"
+ },
+ "instagram": {
+ "properties": {
+ "disable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/privacy/#instagramdisable"
+ },
+ "simple": {
+ "type": "boolean",
+ "description": "If simple mode is enabled, a static and no-JS version of the Instagram\nimage card will be built. \nhttps://gohugo.io/configuration/privacy/#instagramsimple"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/privacy/#instagram"
+ },
+ "twitter": {
+ "properties": {
+ "disable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/privacy/#twitterdisable"
+ },
+ "enableDNT": {
+ "type": "boolean",
+ "description": "When set to true, the Tweet and its embedded page on your site are not used\nfor purposes that include personalized suggestions and personalized ads. \nhttps://gohugo.io/configuration/privacy/#twitterenablednt"
+ },
+ "simple": {
+ "type": "boolean",
+ "description": "If simple mode is enabled, a static and no-JS version of the Tweet will be built. \nhttps://gohugo.io/configuration/privacy/#twittersimple"
+ }
+ },
+ "type": "object",
+ "description": "deprecated in favor of X in v0.141.0 \nhttps://gohugo.io/configuration/privacy/#twitter"
+ },
+ "vimeo": {
+ "properties": {
+ "disable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/privacy/#vimeodisable"
+ },
+ "enableDNT": {
+ "type": "boolean",
+ "description": "When set to true, the Vimeo player will be blocked from tracking any session data,\nincluding all cookies and stats. \nhttps://gohugo.io/configuration/privacy/#vimeoenablednt"
+ },
+ "simple": {
+ "type": "boolean",
+ "description": "If simple mode is enabled, only a thumbnail is fetched from i.vimeocdn.com and\nshown with a play button overlaid. If a user clicks the button, he/she will\nbe taken to the video page on vimeo.com in a new browser tab. \nhttps://gohugo.io/configuration/privacy/#vimeosimple"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/privacy/#vimeo"
+ },
+ "youTube": {
+ "properties": {
+ "disable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/privacy/#youtubedisable"
+ },
+ "privacyEnhanced": {
+ "type": "boolean",
+ "description": "When you turn on privacy-enhanced mode,\nYouTube won’t store information about visitors on your website\nunless the user plays the embedded video. \nhttps://gohugo.io/configuration/privacy/#youtubeprivacyenhanced"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/privacy/#you-tube"
+ },
+ "x": {
+ "properties": {
+ "disable": {
+ "type": "boolean",
+ "description": "https://gohugo.io/configuration/privacy/#xdisable"
+ },
+ "enableDNT": {
+ "type": "boolean",
+ "description": "When set to true, the X post and its embedded page on your site are not\nused for purposes that include personalized suggestions and personalized\nads. \nhttps://gohugo.io/configuration/privacy/#xenablednt"
+ },
+ "simple": {
+ "type": "boolean",
+ "description": "If simple mode is enabled, a static and no-JS version of the X post will\nbe built. \nhttps://gohugo.io/configuration/privacy/#xsimple"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/privacy/#x"
+ }
+ },
+ "type": "object",
+ "description": "Config is a privacy configuration for all the relevant services in Hugo."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-related.schema.json b/docs/content/en/jsonschemas/hugo-config-related.schema.json
new file mode 100644
index 00000000000..c24a1c48ab5
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-related.schema.json
@@ -0,0 +1,58 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-related.schema.json",
+ "properties": {
+ "threshold": {
+ "type": "integer",
+ "description": "Only include matches \u003e= threshold, a normalized rank between 0 and 100. \nhttps://gohugo.io/configuration/related-content/#threshold"
+ },
+ "includeNewer": {
+ "type": "boolean",
+ "description": "To get stable \"See also\" sections we, by default, exclude newer related pages. \nhttps://gohugo.io/configuration/related-content/#includenewer"
+ },
+ "toLower": {
+ "type": "boolean",
+ "description": "Will lower case all string values and queries to the indices.\nMay get better results, but at a slight performance cost. \nhttps://gohugo.io/configuration/related-content/#tolower-1"
+ },
+ "indices": {
+ "items": {
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The index name. This directly maps to a field or Param name. \nhttps://gohugo.io/configuration/related-content/#name"
+ },
+ "type": {
+ "type": "string",
+ "description": "The index type. \nhttps://gohugo.io/configuration/related-content/#type"
+ },
+ "applyFilter": {
+ "type": "boolean",
+ "description": "Enable to apply a type specific filter to the results.\nThis is currently only used for the \"fragments\" type. \nhttps://gohugo.io/configuration/related-content/#applyfilter"
+ },
+ "pattern": {
+ "type": "string",
+ "description": "Contextual pattern used to convert the Param value into a string.\nCurrently only used for dates. Can be used to, say, bump posts in the same\ntime frame when searching for related documents.\nFor dates it follows Go's time.Format patterns, i.e.\n\"2006\" for YYYY and \"200601\" for YYYYMM. \nhttps://gohugo.io/configuration/related-content/#pattern"
+ },
+ "weight": {
+ "type": "integer",
+ "description": "This field's weight when doing multi-index searches. Higher is \"better\". \nhttps://gohugo.io/configuration/related-content/#weight"
+ },
+ "cardinalityThreshold": {
+ "type": "integer",
+ "description": "A percentage (0-100) used to remove common keywords from the index.\nAs an example, setting this to 50 will remove all keywords that are\nused in more than 50% of the documents in the index. \nhttps://gohugo.io/configuration/related-content/#cardinalitythreshold"
+ },
+ "toLower": {
+ "type": "boolean",
+ "description": "Will lower case all string values in and queries tothis index.\nMay get better accurate results, but at a slight performance cost. \nhttps://gohugo.io/configuration/related-content/#tolower-1"
+ }
+ },
+ "type": "object",
+ "description": "IndexConfig configures an index."
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/related-content/#indices"
+ }
+ },
+ "type": "object",
+ "description": "Config is the top level configuration element used to configure how to retrieve related content in Hugo."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-security.schema.json b/docs/content/en/jsonschemas/hugo-config-security.schema.json
new file mode 100644
index 00000000000..983aca8b10f
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-security.schema.json
@@ -0,0 +1,60 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-security.schema.json",
+ "properties": {
+ "exec": {
+ "properties": {
+ "allow": {
+ "properties": {},
+ "type": "object",
+ "description": "https://gohugo.io/configuration/security/#execallow"
+ },
+ "osEnv": {
+ "properties": {},
+ "type": "object",
+ "description": "https://gohugo.io/configuration/security/#execosenv"
+ }
+ },
+ "type": "object",
+ "description": "Restricts access to os.Exec....\n\u003cdocsmeta\u003e{ \"newIn\": \"0.91.0\" }\u003c/docsmeta\u003e \nhttps://gohugo.io/configuration/security/#exec"
+ },
+ "funcs": {
+ "properties": {
+ "getenv": {
+ "properties": {},
+ "type": "object",
+ "description": "OS env keys allowed to query in os.Getenv. \nhttps://gohugo.io/configuration/security/#funcsgetenv"
+ }
+ },
+ "type": "object",
+ "description": "Restricts access to certain template funcs. \nhttps://gohugo.io/configuration/security/#funcs"
+ },
+ "http": {
+ "properties": {
+ "urls": {
+ "properties": {},
+ "type": "object",
+ "description": "URLs to allow in remote HTTP (resources.Get, getJSON, getCSV). \nhttps://gohugo.io/configuration/security/#httpurls"
+ },
+ "methods": {
+ "properties": {},
+ "type": "object",
+ "description": "HTTP methods to allow. \nhttps://gohugo.io/configuration/security/#httpmethods"
+ },
+ "mediaTypes": {
+ "properties": {},
+ "type": "object",
+ "description": "Media types where the Content-Type in the response is used instead of resolving from the file content. \nhttps://gohugo.io/configuration/security/#httpmediatypes"
+ }
+ },
+ "type": "object",
+ "description": "Restricts access to resources.GetRemote, getJSON, getCSV. \nhttps://gohugo.io/configuration/security/#http"
+ },
+ "enableInlineShortcodes": {
+ "type": "boolean",
+ "description": "Allow inline shortcodes \nhttps://gohugo.io/configuration/security/#enableinlineshortcodes"
+ }
+ },
+ "type": "object",
+ "description": "Config is the top level security config."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-segments.schema.json b/docs/content/en/jsonschemas/hugo-config-segments.schema.json
new file mode 100644
index 00000000000..c11f5137c79
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-segments.schema.json
@@ -0,0 +1,59 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-segments.schema.json",
+ "properties": {
+ "excludes": {
+ "items": {
+ "properties": {
+ "kind": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/segments/#kind"
+ },
+ "path": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/segments/#path"
+ },
+ "lang": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/segments/#lang"
+ },
+ "output": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/segments/#output"
+ }
+ },
+ "type": "object",
+ "description": "SegmentMatcherFields is a matcher for a segment include or exclude."
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/segments/#excludes"
+ },
+ "includes": {
+ "items": {
+ "properties": {
+ "kind": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/segments/#kind"
+ },
+ "path": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/segments/#path"
+ },
+ "lang": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/segments/#lang"
+ },
+ "output": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/segments/#output"
+ }
+ },
+ "type": "object",
+ "description": "SegmentMatcherFields is a matcher for a segment include or exclude."
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/segments/#includes"
+ }
+ },
+ "type": "object"
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-server.schema.json b/docs/content/en/jsonschemas/hugo-config-server.schema.json
new file mode 100644
index 00000000000..ee55cd86a16
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-server.schema.json
@@ -0,0 +1,61 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-server.schema.json",
+ "properties": {
+ "headers": {
+ "items": {
+ "properties": {
+ "for": {
+ "type": "string",
+ "description": "https://gohugo.io/configuration/server/#headersfor"
+ },
+ "values": {
+ "type": "object",
+ "description": "https://gohugo.io/configuration/server/#headersvalues"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/server/#headers"
+ },
+ "redirects": {
+ "items": {
+ "properties": {
+ "from": {
+ "type": "string",
+ "description": "From is the Glob pattern to match.\nOne of From or FromRe must be set. \nhttps://gohugo.io/configuration/server/#from"
+ },
+ "fromRe": {
+ "type": "string",
+ "description": "FromRe is the regexp to match.\nThis regexp can contain group matches (e.g. $1) that can be used in the To field.\nOne of From or FromRe must be set. \nhttps://gohugo.io/configuration/server/#fromre"
+ },
+ "to": {
+ "type": "string",
+ "description": "To is the target URL. \nhttps://gohugo.io/configuration/server/#to"
+ },
+ "fromHeaders": {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object",
+ "description": "Headers to match for the redirect.\nThis maps the HTTP header name to a Glob pattern with values to match.\nIf the map is empty, the redirect will always be triggered. \nhttps://gohugo.io/configuration/server/#fromheaders"
+ },
+ "status": {
+ "type": "integer",
+ "description": "HTTP status code to use for the redirect.\nA status code of 200 will trigger a URL rewrite. \nhttps://gohugo.io/configuration/server/#status"
+ },
+ "force": {
+ "type": "boolean",
+ "description": "Forcode redirect, even if original request path exists. \nhttps://gohugo.io/configuration/server/#force"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/configuration/server/#redirects"
+ }
+ },
+ "type": "object",
+ "description": "Config for the dev server."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-services.schema.json b/docs/content/en/jsonschemas/hugo-config-services.schema.json
new file mode 100644
index 00000000000..7a68368e517
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-services.schema.json
@@ -0,0 +1,72 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-services.schema.json",
+ "properties": {
+ "disqus": {
+ "properties": {
+ "shortname": {
+ "type": "string",
+ "description": "A Shortname is the unique identifier assigned to a Disqus site. \nhttps://gohugo.io/configuration/services/#disqusshortname"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/services/#disqus"
+ },
+ "googleAnalytics": {
+ "properties": {
+ "iD": {
+ "type": "string",
+ "description": "The GA tracking ID. \nhttps://gohugo.io/configuration/services/#googleanalyticsid"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/services/#google-analytics"
+ },
+ "instagram": {
+ "properties": {
+ "disableInlineCSS": {
+ "type": "boolean",
+ "description": "The Simple variant of the Instagram is decorated with Bootstrap 4 card classes.\nThis means that if you use Bootstrap 4 or want to provide your own CSS, you want\nto disable the inline CSS provided by Hugo. \nhttps://gohugo.io/configuration/services/#instagramdisableinlinecss"
+ },
+ "accessToken": {
+ "type": "string",
+ "description": "App or Client Access Token.\nIf you are using a Client Access Token, remember that you must combine it with your App ID\nusing a pipe symbol (\u003cAPPID\u003e|\u003cCLIENTTOKEN\u003e) otherwise the request will fail. \nhttps://gohugo.io/configuration/services/#instagramaccesstoken"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/services/#instagram"
+ },
+ "twitter": {
+ "properties": {
+ "disableInlineCSS": {
+ "type": "boolean",
+ "description": "The Simple variant of Twitter is decorated with a basic set of inline styles.\nThis means that if you want to provide your own CSS, you want\nto disable the inline CSS provided by Hugo. \nhttps://gohugo.io/configuration/services/#twitterdisableinlinecss"
+ }
+ },
+ "type": "object",
+ "description": "deprecated in favor of X in v0.141.0 \nhttps://gohugo.io/configuration/services/#twitter"
+ },
+ "x": {
+ "properties": {
+ "disableInlineCSS": {
+ "type": "boolean",
+ "description": "The Simple variant of X is decorated with a basic set of inline styles.\nThis means that if you want to provide your own CSS, you want\nto disable the inline CSS provided by Hugo. \nhttps://gohugo.io/configuration/services/#xdisableinlinecss"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/services/#x"
+ },
+ "rSS": {
+ "properties": {
+ "limit": {
+ "type": "integer",
+ "description": "Limit the number of pages. \nhttps://gohugo.io/configuration/services/#rsslimit"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/configuration/services/#r-s-s"
+ }
+ },
+ "type": "object",
+ "description": "Config is a privacy configuration for all the relevant services in Hugo."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-sitemap.schema.json b/docs/content/en/jsonschemas/hugo-config-sitemap.schema.json
new file mode 100644
index 00000000000..42a0c23f8b4
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-sitemap.schema.json
@@ -0,0 +1,47 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-sitemap.schema.json",
+ "properties": {
+ "changeFreq": {
+ "oneOf": [
+ {
+ "const": "always"
+ },
+ {
+ "const": "hourly"
+ },
+ {
+ "const": "daily"
+ },
+ {
+ "const": "weekly"
+ },
+ {
+ "const": "monthly"
+ },
+ {
+ "const": "yearly"
+ },
+ {
+ "const": "never"
+ }
+ ],
+ "type": "string",
+ "description": "The page change frequency. \nhttps://gohugo.io/configuration/sitemap/#changefreq"
+ },
+ "priority": {
+ "type": "number",
+ "description": "The priority of the page. \nhttps://gohugo.io/configuration/sitemap/#priority"
+ },
+ "filename": {
+ "type": "string",
+ "description": "The sitemap filename. \nhttps://gohugo.io/configuration/sitemap/#filename"
+ },
+ "disable": {
+ "type": "boolean",
+ "description": "Whether to disable page inclusion. \nhttps://gohugo.io/configuration/sitemap/#disable"
+ }
+ },
+ "type": "object",
+ "description": "SitemapConfig configures the sitemap to be generated."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config-taxonomies.schema.json b/docs/content/en/jsonschemas/hugo-config-taxonomies.schema.json
new file mode 100644
index 00000000000..28e319c6d14
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config-taxonomies.schema.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config-taxonomies.schema.json",
+ "additionalProperties": {
+ "type": "string",
+ "description": "The plural form of the taxonomy"
+ },
+ "type": "object",
+ "description": "Taxonomy configuration. Maps singular taxonomy name to plural form."
+}
diff --git a/docs/content/en/jsonschemas/hugo-config.schema.json b/docs/content/en/jsonschemas/hugo-config.schema.json
new file mode 100644
index 00000000000..a52db7fbd64
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-config.schema.json
@@ -0,0 +1,473 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-config.schema.json",
+ "properties": {
+ "baseURL": {
+ "type": "string",
+ "description": "The base URL of the site.\nNote that the default value is empty, but Hugo requires a valid URL (e.g. \"https://example.com/\") to work properly.\n\u003cdocsmeta\u003e{\"identifiers\": [\"URL\"] }\u003c/docsmeta\u003e \nhttps://gohugo.io/configuration/all/#baseurl"
+ },
+ "buildDrafts": {
+ "type": "boolean",
+ "description": "Whether to build content marked as draft.X\n\u003cdocsmeta\u003e{\"identifiers\": [\"draft\"] }\u003c/docsmeta\u003e \nhttps://gohugo.io/configuration/all/#builddrafts"
+ },
+ "buildExpired": {
+ "type": "boolean",
+ "description": "Whether to build content with expiryDate in the past.\n\u003cdocsmeta\u003e{\"identifiers\": [\"expiryDate\"] }\u003c/docsmeta\u003e \nhttps://gohugo.io/configuration/all/#buildexpired"
+ },
+ "buildFuture": {
+ "type": "boolean",
+ "description": "Whether to build content with publishDate in the future.\n\u003cdocsmeta\u003e{\"identifiers\": [\"publishDate\"] }\u003c/docsmeta\u003e \nhttps://gohugo.io/configuration/all/#buildfuture"
+ },
+ "copyright": {
+ "type": "string",
+ "description": "Copyright information. \nhttps://gohugo.io/configuration/all/#copyright"
+ },
+ "defaultContentLanguage": {
+ "type": "string",
+ "description": "The language to apply to content without any language indicator. \nhttps://gohugo.io/configuration/all/#defaultcontentlanguage"
+ },
+ "defaultContentLanguageInSubdir": {
+ "type": "boolean",
+ "description": "By default, we put the default content language in the root and the others below their language ID, e.g. /no/.\nSet this to true to put all languages below their language ID. \nhttps://gohugo.io/configuration/all/#defaultcontentlanguageinsubdir"
+ },
+ "defaultOutputFormat": {
+ "type": "string",
+ "description": "The default output format to use for the site.\nIf not set, we will use the first output format. \nhttps://gohugo.io/configuration/all/#defaultoutputformat"
+ },
+ "disableDefaultLanguageRedirect": {
+ "type": "boolean",
+ "description": "Disable generation of redirect to the default language when DefaultContentLanguageInSubdir is enabled. \nhttps://gohugo.io/configuration/all/#disabledefaultlanguageredirect"
+ },
+ "disableAliases": {
+ "type": "boolean",
+ "description": "Disable creation of alias redirect pages. \nhttps://gohugo.io/configuration/all/#disablealiases"
+ },
+ "disablePathToLower": {
+ "type": "boolean",
+ "description": "Disable lower casing of path segments. \nhttps://gohugo.io/configuration/all/#disablepathtolower"
+ },
+ "disableKinds": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Disable page kinds from build. \nhttps://gohugo.io/configuration/all/#disablekinds"
+ },
+ "disableLanguages": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "A list of languages to disable. \nhttps://gohugo.io/configuration/all/#disablelanguages"
+ },
+ "renderSegments": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "The named segments to render.\nThis needs to match the name of the segment in the segments configuration. \nhttps://gohugo.io/configuration/all/#rendersegments"
+ },
+ "disableHugoGeneratorInject": {
+ "type": "boolean",
+ "description": "Disable the injection of the Hugo generator tag on the home page. \nhttps://gohugo.io/configuration/all/#disablehugogeneratorinject"
+ },
+ "disableLiveReload": {
+ "type": "boolean",
+ "description": "Disable live reloading in server mode. \nhttps://gohugo.io/configuration/all/#disablelivereload"
+ },
+ "enableEmoji": {
+ "type": "boolean",
+ "description": "Enable replacement in Pages' Content of Emoji shortcodes with their equivalent Unicode characters.\n\u003cdocsmeta\u003e{\"identifiers\": [\"Content\", \"Unicode\"] }\u003c/docsmeta\u003e \nhttps://gohugo.io/configuration/all/#enableemoji"
+ },
+ "mainSections": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "THe main section(s) of the site.\nIf not set, Hugo will try to guess this from the content. \nhttps://gohugo.io/configuration/all/#mainsections"
+ },
+ "enableRobotsTXT": {
+ "type": "boolean",
+ "description": "Enable robots.txt generation. \nhttps://gohugo.io/configuration/all/#enablerobotstxt"
+ },
+ "enableGitInfo": {
+ "type": "boolean",
+ "description": "When enabled, Hugo will apply Git version information to each Page if possible, which\ncan be used to keep lastUpdated in synch and to print version information.\n\u003cdocsmeta\u003e{\"identifiers\": [\"Page\"] }\u003c/docsmeta\u003e \nhttps://gohugo.io/configuration/all/#enablegitinfo"
+ },
+ "templateMetrics": {
+ "type": "boolean",
+ "description": "Enable to track, calculate and print metrics. \nhttps://gohugo.io/configuration/all/#templatemetrics"
+ },
+ "templateMetricsHints": {
+ "type": "boolean",
+ "description": "Enable to track, print and calculate metric hints. \nhttps://gohugo.io/configuration/all/#templatemetricshints"
+ },
+ "noBuildLock": {
+ "type": "boolean",
+ "description": "Enable to disable the build lock file. \nhttps://gohugo.io/configuration/all/#nobuildlock"
+ },
+ "ignoreLogs": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "A list of log IDs to ignore. \nhttps://gohugo.io/configuration/all/#ignorelogs"
+ },
+ "ignoreFiles": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "A list of regexps that match paths to ignore.\nDeprecated: Use the settings on module imports. \nhttps://gohugo.io/configuration/all/#ignorefiles"
+ },
+ "ignoreCache": {
+ "type": "boolean",
+ "description": "Ignore cache. \nhttps://gohugo.io/configuration/all/#ignorecache"
+ },
+ "enableMissingTranslationPlaceholders": {
+ "type": "boolean",
+ "description": "Enable to print greppable placeholders (on the form \"[i18n] TRANSLATIONID\") for missing translation strings. \nhttps://gohugo.io/configuration/all/#enablemissingtranslationplaceholders"
+ },
+ "panicOnWarning": {
+ "type": "boolean",
+ "description": "Enable to panic on warning log entries. This may make it easier to detect the source. \nhttps://gohugo.io/configuration/all/#paniconwarning"
+ },
+ "environment": {
+ "type": "string",
+ "description": "The configured environment. Default is \"development\" for server and \"production\" for build. \nhttps://gohugo.io/configuration/all/#environment"
+ },
+ "languageCode": {
+ "type": "string",
+ "description": "The default language code. \nhttps://gohugo.io/configuration/all/#languagecode"
+ },
+ "hasCJKLanguage": {
+ "type": "boolean",
+ "description": "Enable if the site content has CJK language (Chinese, Japanese, or Korean). This affects how Hugo counts words. \nhttps://gohugo.io/configuration/all/#hascjklanguage"
+ },
+ "paginate": {
+ "type": "integer",
+ "description": "The default number of pages per page when paginating.\nDeprecated: Use the Pagination struct. \nhttps://gohugo.io/configuration/all/#paginate"
+ },
+ "paginatePath": {
+ "type": "string",
+ "description": "The path to use when creating pagination URLs, e.g. \"page\" in /page/2/.\nDeprecated: Use the Pagination struct. \nhttps://gohugo.io/configuration/all/#paginatepath"
+ },
+ "pluralizeListTitles": {
+ "type": "boolean",
+ "description": "Whether to pluralize default list titles.\nNote that this currently only works for English, but you can provide your own title in the content file's front matter. \nhttps://gohugo.io/configuration/all/#pluralizelisttitles"
+ },
+ "capitalizeListTitles": {
+ "type": "boolean",
+ "description": "Whether to capitalize automatic page titles, applicable to section, taxonomy, and term pages. \nhttps://gohugo.io/configuration/all/#capitalizelisttitles"
+ },
+ "canonifyURLs": {
+ "type": "boolean",
+ "description": "Make all relative URLs absolute using the baseURL.\n\u003cdocsmeta\u003e{\"identifiers\": [\"baseURL\"] }\u003c/docsmeta\u003e \nhttps://gohugo.io/configuration/all/#canonifyurls"
+ },
+ "relativeURLs": {
+ "type": "boolean",
+ "description": "Enable this to make all relative URLs relative to content root. Note that this does not affect absolute URLs. \nhttps://gohugo.io/configuration/all/#relativeurls"
+ },
+ "removePathAccents": {
+ "type": "boolean",
+ "description": "Removes non-spacing marks from composite characters in content paths. \nhttps://gohugo.io/configuration/all/#removepathaccents"
+ },
+ "printUnusedTemplates": {
+ "type": "boolean",
+ "description": "Whether to track and print unused templates during the build. \nhttps://gohugo.io/configuration/all/#printunusedtemplates"
+ },
+ "printI18nWarnings": {
+ "type": "boolean",
+ "description": "Enable to print warnings for missing translation strings. \nhttps://gohugo.io/configuration/all/#printi18nwarnings"
+ },
+ "printPathWarnings": {
+ "type": "boolean",
+ "description": "ENable to print warnings for multiple files published to the same destination. \nhttps://gohugo.io/configuration/all/#printpathwarnings"
+ },
+ "refLinksNotFoundURL": {
+ "type": "string",
+ "description": "URL to be used as a placeholder when a page reference cannot be found in ref or relref. Is used as-is. \nhttps://gohugo.io/configuration/all/#reflinksnotfoundurl"
+ },
+ "refLinksErrorLevel": {
+ "type": "string",
+ "enum": [
+ "ERROR",
+ "WARNING"
+ ],
+ "description": "When using ref or relref to resolve page links and a link cannot be resolved, it will be logged with this log level.\nValid values are ERROR (default) or WARNING. Any ERROR will fail the build (exit -1). \nhttps://gohugo.io/configuration/all/#reflinkserrorlevel"
+ },
+ "sectionPagesMenu": {
+ "type": "string",
+ "description": "This will create a menu with all the sections as menu items and all the sections’ pages as “shadow-members”. \nhttps://gohugo.io/configuration/all/#sectionpagesmenu"
+ },
+ "summaryLength": {
+ "type": "integer",
+ "description": "The length of text in words to show in a .Summary. \nhttps://gohugo.io/configuration/all/#summarylength"
+ },
+ "title": {
+ "type": "string",
+ "description": "The site title. \nhttps://gohugo.io/configuration/all/#title"
+ },
+ "theme": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "The theme(s) to use.\nSee Modules for more a more flexible way to load themes. \nhttps://gohugo.io/configuration/all/#theme"
+ },
+ "timeout": {
+ "type": "string",
+ "description": "Timeout for generating page contents, specified as a duration or in seconds. \nhttps://gohugo.io/configuration/all/#timeout"
+ },
+ "timeZone": {
+ "type": "string",
+ "description": "The time zone (or location), e.g. Europe/Oslo, used to parse front matter dates without such information and in the time function. \nhttps://gohugo.io/configuration/all/#timezone"
+ },
+ "titleCaseStyle": {
+ "type": "string",
+ "enum": [
+ "ap",
+ "chicago",
+ "go",
+ "firstupper",
+ "none"
+ ],
+ "description": "Set titleCaseStyle to specify the title style used by the title template function and the automatic section titles in Hugo.\nIt defaults to AP Stylebook for title casing, but you can also set it to Chicago or Go (every word starts with a capital letter). \nhttps://gohugo.io/configuration/all/#titlecasestyle"
+ },
+ "newContentEditor": {
+ "type": "string",
+ "description": "The editor used for opening up new content. \nhttps://gohugo.io/configuration/all/#newcontenteditor"
+ },
+ "noTimes": {
+ "type": "boolean",
+ "description": "Don't sync modification time of files for the static mounts. \nhttps://gohugo.io/configuration/all/#notimes"
+ },
+ "noChmod": {
+ "type": "boolean",
+ "description": "Don't sync modification time of files for the static mounts. \nhttps://gohugo.io/configuration/all/#nochmod"
+ },
+ "cleanDestinationDir": {
+ "type": "boolean",
+ "description": "Clean the destination folder before a new build.\nThis currently only handles static files. \nhttps://gohugo.io/configuration/all/#cleandestinationdir"
+ },
+ "ignoreVendorPaths": {
+ "type": "string",
+ "description": "A Glob pattern of module paths to ignore in the _vendor folder. \nhttps://gohugo.io/configuration/all/#ignorevendorpaths"
+ },
+ "themesDir": {
+ "type": "string",
+ "description": "The directory where Hugo will look for themes. \nhttps://gohugo.io/configuration/all/#themesdir"
+ },
+ "publishDir": {
+ "type": "string",
+ "description": "Where to put the generated files. \nhttps://gohugo.io/configuration/all/#publishdir"
+ },
+ "resourceDir": {
+ "type": "string",
+ "description": "The directory to put the generated resources files. This directory should in most situations be considered temporary\nand not be committed to version control. But there may be cached content in here that you want to keep,\ne.g. resources/_gen/images for performance reasons or CSS built from SASS when your CI server doesn't have the full setup. \nhttps://gohugo.io/configuration/all/#resourcedir"
+ },
+ "workingDir": {
+ "type": "string",
+ "description": "The project root directory. \nhttps://gohugo.io/configuration/all/#workingdir"
+ },
+ "cacheDir": {
+ "type": "string",
+ "description": "The root directory for all cache files. \nhttps://gohugo.io/configuration/all/#cachedir"
+ },
+ "contentDir": {
+ "type": "string",
+ "description": "The content source directory.\nDeprecated: Use module mounts. \nhttps://gohugo.io/configuration/all/#contentdir"
+ },
+ "dataDir": {
+ "type": "string",
+ "description": "Deprecated: Use module mounts.\nThe data source directory. \nhttps://gohugo.io/configuration/all/#datadir"
+ },
+ "layoutDir": {
+ "type": "string",
+ "description": "Deprecated: Use module mounts.\nThe layout source directory. \nhttps://gohugo.io/configuration/all/#layoutdir"
+ },
+ "i18nDir": {
+ "type": "string",
+ "description": "Deprecated: Use module mounts.\nThe i18n source directory. \nhttps://gohugo.io/configuration/all/#i18ndir"
+ },
+ "archeTypeDir": {
+ "type": "string",
+ "description": "Deprecated: Use module mounts.\nThe archetypes source directory. \nhttps://gohugo.io/configuration/all/#archetypedir"
+ },
+ "assetDir": {
+ "type": "string",
+ "description": "Deprecated: Use module mounts.\nThe assets source directory. \nhttps://gohugo.io/configuration/all/#assetdir"
+ },
+ "staticDir": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "The odd constructs below are kept for backwards compatibility.\nDeprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir"
+ },
+ "staticDir0": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir0"
+ },
+ "staticDir1": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir1"
+ },
+ "staticDir2": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir2"
+ },
+ "staticDir3": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir3"
+ },
+ "staticDir4": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir4"
+ },
+ "staticDir5": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir5"
+ },
+ "staticDir6": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir6"
+ },
+ "staticDir7": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir7"
+ },
+ "staticDir8": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir8"
+ },
+ "staticDir9": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir9"
+ },
+ "staticDir10": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "Deprecated: Use module mount config instead. \nhttps://gohugo.io/configuration/all/#staticdir10"
+ },
+ "mediatypes": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-mediatypes.schema.json"
+ },
+ "markup": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-markup.schema.json"
+ },
+ "params": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-params.schema.json"
+ },
+ "cascade": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-cascade.schema.json"
+ },
+ "segments": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-segments.schema.json"
+ },
+ "server": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-server.schema.json"
+ },
+ "imaging": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-imaging.schema.json"
+ },
+ "languages": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-languages.schema.json"
+ },
+ "outputs": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-outputs.schema.json"
+ },
+ "deployment": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-deployment.schema.json"
+ },
+ "taxonomies": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-taxonomies.schema.json"
+ },
+ "services": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-services.schema.json"
+ },
+ "menus": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-menus.schema.json"
+ },
+ "build": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-build.schema.json"
+ },
+ "contenttypes": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-contenttypes.schema.json"
+ },
+ "related": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-related.schema.json"
+ },
+ "security": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-security.schema.json"
+ },
+ "privacy": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-privacy.schema.json"
+ },
+ "permalinks": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-permalinks.schema.json"
+ },
+ "page": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-page.schema.json"
+ },
+ "caches": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-caches.schema.json"
+ },
+ "module": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-module.schema.json"
+ },
+ "sitemap": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-sitemap.schema.json"
+ },
+ "pagination": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-pagination.schema.json"
+ },
+ "outputformats": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-outputformats.schema.json"
+ },
+ "httpcache": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-httpcache.schema.json"
+ },
+ "frontmatter": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-frontmatter.schema.json"
+ },
+ "minify": {
+ "$ref": "http://gohugo.io/jsonschemas/hugo-config-minify.schema.json"
+ }
+ },
+ "type": "object",
+ "title": "Hugo Configuration Schema",
+ "description": "JSON Schema for Hugo configuration files"
+}
diff --git a/docs/content/en/jsonschemas/hugo-page.schema.json b/docs/content/en/jsonschemas/hugo-page.schema.json
new file mode 100644
index 00000000000..46489c402f7
--- /dev/null
+++ b/docs/content/en/jsonschemas/hugo-page.schema.json
@@ -0,0 +1,206 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema",
+ "$id": "https://gohugo.io/jsonschemas/hugo-page.schema.json",
+ "$defs": {
+ "flexibleDate": {
+ "oneOf": [
+ {
+ "type": "string",
+ "format": "date-time",
+ "description": "RFC3339 date-time format (e.g., 2017-01-02T15:04:05Z07:00)"
+ },
+ {
+ "type": "string",
+ "format": "date",
+ "description": "Date only format (e.g., 2017-01-02)"
+ },
+ {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}$",
+ "description": "Date with time format (e.g., 2017-01-02 15:04:05)"
+ },
+ {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}$",
+ "description": "Date with hour:minute format (e.g., 2017-01-02 15:04)"
+ }
+ ],
+ "description": "Hugo date field supporting multiple formats"
+ }
+ },
+ "properties": {
+ "date": {
+ "$ref": "#/$defs/flexibleDate",
+ "description": "https://gohugo.io/content-management/front-matter#date"
+ },
+ "lastMod": {
+ "type": "string",
+ "description": "https://gohugo.io/content-management/front-matter#lastmod"
+ },
+ "publishDate": {
+ "$ref": "#/$defs/flexibleDate",
+ "description": "https://gohugo.io/content-management/front-matter#publishdate"
+ },
+ "expiryDate": {
+ "$ref": "#/$defs/flexibleDate",
+ "description": "https://gohugo.io/content-management/front-matter#expirydate"
+ },
+ "kind": {
+ "type": "string",
+ "description": "The kind of page, e.g. \"page\", \"section\", \"home\" etc. This is usually derived from the content path. \nhttps://gohugo.io/content-management/front-matter#kind"
+ },
+ "path": {
+ "type": "string",
+ "description": "The canonical path to the page, e.g. /sect/mypage. Note: Leading slash, no trailing slash, no extensions or language identifiers. \nhttps://gohugo.io/content-management/front-matter#path"
+ },
+ "lang": {
+ "type": "string",
+ "description": "The language code for this page. This is usually derived from the module mount or filename. \nhttps://gohugo.io/content-management/front-matter"
+ },
+ "cascade": {
+ "items": {
+ "type": "object"
+ },
+ "type": "array",
+ "description": "https://gohugo.io/content-management/front-matter#cascade"
+ },
+ "title": {
+ "type": "string",
+ "description": "The title of the page. \nhttps://gohugo.io/content-management/front-matter#title"
+ },
+ "linkTitle": {
+ "type": "string",
+ "description": "The link title of the page. \nhttps://gohugo.io/content-management/front-matter#linktitle"
+ },
+ "type": {
+ "type": "string",
+ "description": "The content type of the page. \nhttps://gohugo.io/content-management/front-matter#type"
+ },
+ "layout": {
+ "type": "string",
+ "description": "The layout to use for to render this page. \nhttps://gohugo.io/content-management/front-matter#layout"
+ },
+ "weight": {
+ "type": "integer",
+ "description": "The weight of the page, used in sorting if set to a non-zero value. \nhttps://gohugo.io/content-management/front-matter#weight"
+ },
+ "uRL": {
+ "type": "string",
+ "description": "The URL to the rendered page, e.g. /sect/mypage.html. \nhttps://gohugo.io/content-management/front-matter#url"
+ },
+ "slug": {
+ "type": "string",
+ "description": "The slug for this page. \nhttps://gohugo.io/content-management/front-matter#slug"
+ },
+ "description": {
+ "type": "string",
+ "description": "The description for this page. \nhttps://gohugo.io/content-management/front-matter#description"
+ },
+ "summary": {
+ "type": "string",
+ "description": "The summary for this page. \nhttps://gohugo.io/content-management/front-matter#summary"
+ },
+ "draft": {
+ "type": "boolean",
+ "description": "Whether or not the content is a draft. \nhttps://gohugo.io/content-management/front-matter#draft"
+ },
+ "isCJKLanguage": {
+ "type": "boolean",
+ "description": "Whether or not the content is in a CJK language. \nhttps://gohugo.io/content-management/front-matter#iscjklanguage"
+ },
+ "translationKey": {
+ "type": "string",
+ "description": "The translation key for this page. \nhttps://gohugo.io/content-management/front-matter#translationkey"
+ },
+ "keywords": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "The keywords for this page. \nhttps://gohugo.io/content-management/front-matter#keywords"
+ },
+ "aliases": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "The aliases for this page. \nhttps://gohugo.io/content-management/front-matter#aliases"
+ },
+ "outputs": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "The output formats to render this page in. If not set, the site's configured output formats for this page kind will be used. \nhttps://gohugo.io/content-management/front-matter#outputs"
+ },
+ "sitemap": {
+ "properties": {
+ "changeFreq": {
+ "type": "string",
+ "enum": [
+ "always",
+ "hourly",
+ "daily",
+ "weekly",
+ "monthly",
+ "yearly",
+ "never"
+ ],
+ "description": "The page change frequency. \nhttps://gohugo.io/content-management/front-matter#sitemap"
+ },
+ "priority": {
+ "type": "number",
+ "description": "The priority of the page. \nhttps://gohugo.io/content-management/front-matter#sitemap"
+ },
+ "filename": {
+ "type": "string",
+ "description": "The sitemap filename. \nhttps://gohugo.io/content-management/front-matter#sitemap"
+ },
+ "disable": {
+ "type": "boolean",
+ "description": "Whether to disable page inclusion. \nhttps://gohugo.io/content-management/front-matter#sitemap"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/content-management/front-matter#sitemap"
+ },
+ "build": {
+ "properties": {
+ "list": {
+ "type": "string",
+ "enum": [
+ "never",
+ "always",
+ "local"
+ ],
+ "description": "Whether to add it to any of the page collections.\nNote that the page can always be found with .Site.GetPage.\nValid values: never, always, local.\nSetting it to 'local' means they will be available via the local\npage collections, e.g. $section.Pages.\nNote: before 0.57.2 this was a bool, so we accept those too. \nhttps://gohugo.io/content-management/front-matter#build"
+ },
+ "render": {
+ "type": "string",
+ "enum": [
+ "never",
+ "always",
+ "link"
+ ],
+ "description": "Whether to render it.\nValid values: never, always, link.\nThe value link means it will not be rendered, but it will get a RelPermalink/Permalink.\nNote that before 0.76.0 this was a bool, so we accept those too. \nhttps://gohugo.io/content-management/front-matter#build"
+ },
+ "publishResources": {
+ "type": "boolean",
+ "description": "Whether to publish its resources. These will still be published on demand,\nbut enabling this can be useful if the originals (e.g. images) are\nnever used. \nhttps://gohugo.io/content-management/front-matter#build"
+ }
+ },
+ "type": "object",
+ "description": "https://gohugo.io/content-management/front-matter#build"
+ },
+ "menus": {
+ "description": "Can be a string, []string or map[string]any. \nhttps://gohugo.io/content-management/front-matter#menus"
+ },
+ "params": {
+ "type": "object",
+ "description": "User defined params. \nhttps://gohugo.io/content-management/front-matter#params"
+ }
+ },
+ "type": "object",
+ "title": "Hugo Page Front Matter Schema",
+ "description": "JSON Schema for Hugo page front matter structure"
+}
diff --git a/docs/content/en/jsonschemas/index.md b/docs/content/en/jsonschemas/index.md
new file mode 100644
index 00000000000..96a37651b76
--- /dev/null
+++ b/docs/content/en/jsonschemas/index.md
@@ -0,0 +1,165 @@
+---
+title: JSON schemas
+linkTitle: JSON schemas
+description: Use JSON Schema files to validate Hugo configuration files and page frontmatter.
+categories: []
+keywords: []
+weight: 70
+---
+
+Hugo provides JSON Schema files for validating Hugo configuration files and page frontmatter. These schemas enable IntelliSense, auto-completion, and validation in code editors that support JSON Schema.
+
+## Available schemas
+
+### Configuration schemas
+
+These schemas validate Hugo configuration files (`hugo.yaml`, `hugo.json`, `hugo.toml`):
+
+- [`hugo-config.schema.json`](hugo-config.schema.json) - Main configuration schema that references all other config schemas
+- [`hugo-config-build.schema.json`](hugo-config-build.schema.json) - Build configuration (`build`)
+- [`hugo-config-caches.schema.json`](hugo-config-caches.schema.json) - Cache configuration (`caches`)
+- [`hugo-config-cascade.schema.json`](hugo-config-cascade.schema.json) - Cascade configuration (`cascade`)
+- [`hugo-config-contenttypes.schema.json`](hugo-config-contenttypes.schema.json) - Content types configuration (`contenttypes`)
+- [`hugo-config-deployment.schema.json`](hugo-config-deployment.schema.json) - Deployment configuration (`deployment`)
+- [`hugo-config-frontmatter.schema.json`](hugo-config-frontmatter.schema.json) - Front matter configuration (`frontmatter`)
+- [`hugo-config-httpcache.schema.json`](hugo-config-httpcache.schema.json) - HTTP cache configuration (`httpcache`)
+- [`hugo-config-imaging.schema.json`](hugo-config-imaging.schema.json) - Image processing configuration (`imaging`)
+- [`hugo-config-languages.schema.json`](hugo-config-languages.schema.json) - Language configuration (`languages`)
+- [`hugo-config-markup.schema.json`](hugo-config-markup.schema.json) - Markup configuration (`markup`)
+- [`hugo-config-mediatypes.schema.json`](hugo-config-mediatypes.schema.json) - Media types configuration (`mediatypes`)
+- [`hugo-config-menus.schema.json`](hugo-config-menus.schema.json) - Menu configuration (`menus`)
+- [`hugo-config-minify.schema.json`](hugo-config-minify.schema.json) - Minification configuration (`minify`)
+- [`hugo-config-module.schema.json`](hugo-config-module.schema.json) - Module configuration (`module`)
+- [`hugo-config-outputformats.schema.json`](hugo-config-outputformats.schema.json) - Output formats configuration (`outputformats`)
+- [`hugo-config-outputs.schema.json`](hugo-config-outputs.schema.json) - Outputs configuration (`outputs`)
+- [`hugo-config-page.schema.json`](hugo-config-page.schema.json) - Page configuration (`page`)
+- [`hugo-config-pagination.schema.json`](hugo-config-pagination.schema.json) - Pagination configuration (`pagination`)
+- [`hugo-config-params.schema.json`](hugo-config-params.schema.json) - Parameters configuration (`params`)
+- [`hugo-config-permalinks.schema.json`](hugo-config-permalinks.schema.json) - Permalinks configuration (`permalinks`)
+- [`hugo-config-privacy.schema.json`](hugo-config-privacy.schema.json) - Privacy configuration (`privacy`)
+- [`hugo-config-related.schema.json`](hugo-config-related.schema.json) - Related content configuration (`related`)
+- [`hugo-config-security.schema.json`](hugo-config-security.schema.json) - Security configuration (`security`)
+- [`hugo-config-segments.schema.json`](hugo-config-segments.schema.json) - Segments configuration (`segments`)
+- [`hugo-config-server.schema.json`](hugo-config-server.schema.json) - Server configuration (`server`)
+- [`hugo-config-services.schema.json`](hugo-config-services.schema.json) - Services configuration (`services`)
+- [`hugo-config-sitemap.schema.json`](hugo-config-sitemap.schema.json) - Sitemap configuration (`sitemap`)
+- [`hugo-config-taxonomies.schema.json`](hugo-config-taxonomies.schema.json) - Taxonomies configuration (`taxonomies`)
+
+### Page frontmatter schema
+
+This schema validates Hugo page frontmatter in Markdown files:
+
+- [`hugo-page.schema.json`](hugo-page.schema.json) - Page frontmatter schema with flexible date handling and build options
+
+## Configuration file organization
+
+Hugo supports two approaches for organizing configuration:
+
+### Single configuration file
+All configuration in one file: `hugo.yaml`, `hugo.json`, or `hugo.toml`
+
+### Split configuration files
+Configuration sections in separate files in the `config/` directory, organized by environment:
+
+```text
+config/
+├── _default/ # Default configuration (all environments)
+│ ├── hugo.yaml # Main configuration
+│ ├── build.yaml # Build configuration
+│ ├── markup.yaml # Markup and rendering configuration
+│ ├── params.yaml # Site parameters
+│ ├── module.yaml # Hugo Modules configuration
+│ ├── deployment.yaml # Deployment settings
+│ ├── languages.yaml # Multi-language configuration
+│ ├── menus.yaml # Site navigation menus
+│ └── caches.yaml # File cache settings
+├── production/ # Production environment overrides
+│ ├── params.yaml
+│ └── build.yaml
+├── staging/ # Staging environment overrides
+│ └── params.yaml
+└── development/ # Development environment overrides
+ └── server.yaml # Development server settings
+```
+
+Each file can use `.yaml`, `.yml`, `.json`, or `.toml` extensions. The individual schemas validate the specific configuration section, providing targeted IntelliSense and validation for each file.
+
+## Using the schemas
+
+### SchemaStore integration
+
+Hugo's JSON schemas are being integrated with [SchemaStore](https://schemastore.org/), the central repository for JSON schemas used by most editors and IDEs. Once available, schemas will be automatically detected by compatible editors without any manual configuration required.
+
+For current editor integrations and setup instructions, visit [schemastore.org](https://schemastore.org/).
+
+### Recommended VS Code extensions
+
+Until Hugo schemas are available in SchemaStore, use these extensions that provide automatic JSON Schema validation:
+
+#### YAML files
+- **[YAML Language Support](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml)** by Red Hat
+ - Automatically uses SchemaStore for schema detection
+ - Provides validation, auto-completion, and hover documentation
+ - Supports Hugo configuration files when schemas are available in SchemaStore
+
+#### JSON files
+- **Built-in JSON Language Features** (included with VS Code)
+ - Automatically uses SchemaStore for JSON schema validation
+ - No additional configuration needed once schemas are in SchemaStore
+
+#### TOML files
+- **[Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml)** by tamasfe
+ - Uses SchemaStore for automatic schema detection
+ - Provides syntax highlighting, validation, and IntelliSense
+ - Supports Hugo's TOML configuration files
+
+#### Markdown files
+- **[YAML Language Support](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml)** also validates YAML frontmatter in Markdown files
+
+### Manual configuration (temporary)
+
+Until Hugo schemas are available in SchemaStore, you can manually configure VS Code by adding this to your workspace settings (`.vscode/settings.json`):
+
+```json
+{
+ "yaml.schemas": {
+ "https://gohugo.io/jsonschemas/hugo-config.schema.json": [
+ "hugo.{yaml,yml}",
+ "config.{yaml,yml}",
+ "config/**/*.{yaml,yml}"
+ ],
+ "https://gohugo.io/jsonschemas/hugo-page.schema.json": [
+ "content/**/*.md",
+ "archetypes/*.md"
+ ]
+ },
+ "json.schemas": [
+ {
+ "fileMatch": [
+ "hugo.json",
+ "config.json",
+ "config/**/*.json"
+ ],
+ "url": "https://gohugo.io/jsonschemas/hugo-config.schema.json"
+ }
+ ]
+}
+```
+
+### Other editors
+
+Most modern editors with JSON Schema support will automatically use schemas from SchemaStore. For manual configuration, reference these URLs:
+
+- Main configuration: `https://gohugo.io/jsonschemas/hugo-config.schema.json`
+- Page frontmatter: `https://gohugo.io/jsonschemas/hugo-page.schema.json`
+- Individual config sections: `https://gohugo.io/jsonschemas/hugo-config-{section}.schema.json`
+
+## Generating schemas
+
+The schemas are generated using the `hugo gen jsonschemas` command, which uses reflection to create schemas directly from Hugo's Go source code. This ensures the schemas are always accurate and up-to-date.
+
+```bash
+hugo gen jsonschemas --dir docs/content/en/jsonschemas
+```
+
+For more information about configuration options, see the [configuration documentation](../configuration/).
diff --git a/go.mod b/go.mod
index 1fa93cb5c01..4701c7ca51c 100644
--- a/go.mod
+++ b/go.mod
@@ -124,6 +124,8 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
github.com/aws/smithy-go v1.22.2 // indirect
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect
+ github.com/bahlo/generic-list-go v0.2.0 // indirect
+ github.com/buger/jsonparser v1.1.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
@@ -143,6 +145,7 @@ require (
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/invopop/jsonschema v0.13.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
@@ -164,6 +167,7 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
github.com/zeebo/errs v1.4.0 // indirect
+ github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.35.0 // indirect
diff --git a/go.sum b/go.sum
index 4328b73b958..85a36d0f5aa 100644
--- a/go.sum
+++ b/go.sum
@@ -137,6 +137,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudr
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
+github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
+github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/bep/clocks v0.5.0 h1:hhvKVGLPQWRVsBP/UB7ErrHYIO42gINVbvqxvYTPVps=
github.com/bep/clocks v0.5.0/go.mod h1:SUq3q+OOq41y2lRQqH5fsOoxN8GbxSiT6jvoVVLCVhU=
github.com/bep/debounce v1.2.0 h1:wXds8Kq8qRfwAOpAxHrJDbCXgC5aHSzgQb/0gKsHQqo=
@@ -171,6 +173,8 @@ github.com/bep/tmc v0.5.1 h1:CsQnSC6MsomH64gw0cT5f+EwQDcvZz4AazKunFwTpuI=
github.com/bep/tmc v0.5.1/go.mod h1:tGYHN8fS85aJPhDLgXETVKp+PR382OvFi2+q2GkGsq0=
github.com/bep/workers v1.0.0 h1:U+H8YmEaBCEaFZBst7GcRVEoqeRC9dzH2dWOwGmOchg=
github.com/bep/workers v1.0.0/go.mod h1:7kIESOB86HfR2379pwoMWNy8B50D7r99fRLUyPSNyCs=
+github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
+github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -366,6 +370,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
+github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/jdkato/prose v1.2.1 h1:Fp3UnJmLVISmlc57BgKUzdjr0lOtjqTZicL3PaYy6cU=
github.com/jdkato/prose v1.2.1/go.mod h1:AiRHgVagnEx2JbQRQowVBKjG0bcs/vtkGCH1dYAL1rA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@@ -497,6 +503,8 @@ github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZB
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
+github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
+github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
diff --git a/internal/js/esbuild/options.go b/internal/js/esbuild/options.go
index 21f9e31cd97..9ccd271ad9b 100644
--- a/internal/js/esbuild/options.go
+++ b/internal/js/esbuild/options.go
@@ -108,24 +108,24 @@ type ExternalOptions struct {
Minify bool
// One of "inline", "external", "linked" or "none".
- SourceMap string
+ SourceMap string `jsonschema:"enum=inline,enum=external,enum=linked,enum=none"`
SourcesContent bool
// The language target.
// One of: es2015, es2016, es2017, es2018, es2019, es2020 or esnext.
// Default is esnext.
- Target string
+ Target string `jsonschema:"enum=es5,enum=es2015,enum=es2016,enum=es2017,enum=es2018,enum=es2019,enum=es2020,enum=es2021,enum=es2022,enum=es2023,enum=es2024,enum=esnext"`
// The output format.
// One of: iife, cjs, esm
// Default is to esm.
- Format string
+ Format string `jsonschema:"enum=iife,enum=cjs,enum=esm"`
// One of browser, node, neutral.
// Default is browser.
// See https://esbuild.github.io/api/#platform
- Platform string
+ Platform string `jsonschema:"enum=browser,enum=node,enum=neutral"`
// External dependencies, e.g. "react".
Externals []string
@@ -140,7 +140,7 @@ type ExternalOptions struct {
// This tells esbuild to edit your source code before building to drop certain constructs.
// See https://esbuild.github.io/api/#drop
- Drop string
+ Drop string `jsonschema:"enum=console,enum=debugger"`
// Maps a component import to another.
Shims map[string]string
@@ -165,7 +165,7 @@ type ExternalOptions struct {
// What to do about JSX syntax.
// See https://esbuild.github.io/api/#jsx
- JSX string
+ JSX string `jsonschema:"enum=transform,enum=preserve,enum=automatic"`
// Which library to use to automatically import JSX helper functions from. Only works if JSX is set to automatic.
// See https://esbuild.github.io/api/#jsx-import-source
diff --git a/langs/config.go b/langs/config.go
index 7cca0f5e7b2..0213d74ddc9 100644
--- a/langs/config.go
+++ b/langs/config.go
@@ -34,7 +34,7 @@ type LanguageConfig struct {
Title string
// The language direction, e.g. "ltr" or "rtl".
- LanguageDirection string
+ LanguageDirection string `jsonschema:"enum=ltr,enum=rtl"`
// The language weight. When set to a non-zero value, this will
// be the main sort criteria for the language.
diff --git a/magefile.go b/magefile.go
index 120e23666f4..1d8eb9a072c 100644
--- a/magefile.go
+++ b/magefile.go
@@ -257,6 +257,12 @@ func TestCoverHTML() error {
return sh.Run(goexe, "tool", "cover", "-html="+coverAll)
}
+// Generate JSON Schema for Hugo config
+func GenJSONSchema() error {
+ cmd := sh.RunCmd("./hugo", "gen", "jsonschemas")
+ return cmd()
+}
+
func runCmd(env map[string]string, cmd string, args ...any) error {
if mg.Verbose() {
return runWith(env, cmd, args...)
diff --git a/markup/asciidocext/asciidocext_config/config.go b/markup/asciidocext/asciidocext_config/config.go
index 4c38fbbbf7b..5319cd3d103 100644
--- a/markup/asciidocext/asciidocext_config/config.go
+++ b/markup/asciidocext/asciidocext_config/config.go
@@ -65,15 +65,15 @@ var (
// Config configures asciidoc.
type Config struct {
- Backend string
+ Backend string `jsonschema:"enum=html5,enum=html5s,enum=xhtml5,enum=docbook5,enum=docbook45,enum=manpage"`
Extensions []string
Attributes map[string]string
NoHeaderOrFooter bool
- SafeMode string
+ SafeMode string `jsonschema:"enum=unsafe,enum=safe,enum=server,enum=secure"`
SectionNumbers bool
Verbose bool
Trace bool
- FailureLevel string
+ FailureLevel string `jsonschema:"enum=fatal,enum=warn"`
WorkingFolderCurrent bool
PreserveTOC bool
}
diff --git a/markup/goldmark/goldmark_config/config.go b/markup/goldmark/goldmark_config/config.go
index 04eb371d90a..8a5102ce801 100644
--- a/markup/goldmark/goldmark_config/config.go
+++ b/markup/goldmark/goldmark_config/config.go
@@ -147,7 +147,7 @@ type Extensions struct {
Table bool
Strikethrough bool
Linkify bool
- LinkifyProtocol string
+ LinkifyProtocol string `jsonschema:"enum=http,enum=https"`
TaskList bool
CJK CJK
}
@@ -239,7 +239,7 @@ type CJK struct {
EastAsianLineBreaks bool
// Styles of Line Breaking of EastAsianLineBreaks: "simple" or "css3draft"
- EastAsianLineBreaksStyle string
+ EastAsianLineBreaksStyle string `jsonschema:"enum=simple,enum=css3draft"`
// Whether a '\' escaped half-space(0x20) should not be rendered.
EscapedSpace bool
@@ -267,7 +267,7 @@ type Parser struct {
// The strategy to use when generating IDs.
// Available options are "github", "github-ascii", and "blackfriday".
// Default is "github", which will create GitHub-compatible anchor names.
- AutoIDType string
+ AutoIDType string `jsonschema:"enum=github,enum=github-ascii,enum=blackfriday"`
// Enables custom attributes.
Attribute ParserAttribute
diff --git a/resources/page/pagemeta/pagemeta.go b/resources/page/pagemeta/pagemeta.go
index b6b9532310e..fc8bc091ccd 100644
--- a/resources/page/pagemeta/pagemeta.go
+++ b/resources/page/pagemeta/pagemeta.go
@@ -40,13 +40,13 @@ type BuildConfig struct {
// Setting it to 'local' means they will be available via the local
// page collections, e.g. $section.Pages.
// Note: before 0.57.2 this was a bool, so we accept those too.
- List string
+ List string `jsonschema:"enum=never,enum=always,enum=local"`
// Whether to render it.
// Valid values: never, always, link.
// The value link means it will not be rendered, but it will get a RelPermalink/Permalink.
// Note that before 0.76.0 this was a bool, so we accept those too.
- Render string
+ Render string `jsonschema:"enum=never,enum=always,enum=link"`
// Whether to publish its resources. These will still be published on demand,
// but enabling this can be useful if the originals (e.g. images) are
diff --git a/resources/resource_transformers/tocss/dartsass/client.go b/resources/resource_transformers/tocss/dartsass/client.go
index 965232ad4de..074c6fa2289 100644
--- a/resources/resource_transformers/tocss/dartsass/client.go
+++ b/resources/resource_transformers/tocss/dartsass/client.go
@@ -144,7 +144,7 @@ type Options struct {
// Default is nested.
// One of nested, expanded, compact, compressed.
- OutputStyle string
+ OutputStyle string `jsonschema:"enum=nested,enum=expanded,enum=compact,enum=compressed"`
// When enabled, Hugo will generate a source map.
EnableSourceMap bool
diff --git a/testscripts/commands/gen.txt b/testscripts/commands/gen.txt
index e83e9982f9f..1b372a13274 100644
--- a/testscripts/commands/gen.txt
+++ b/testscripts/commands/gen.txt
@@ -20,3 +20,8 @@ hugo gen chromastyles --style monokai
stdout '{ }'
hugo gen chromastyles --omitEmpty --style monokai
! stdout '\{ \}'
+
+# Test the jsonschemas generator
+hugo gen jsonschemas -h
+stdout 'Generate a JSON Schema for Hugo configuration options and page structures using reflection'
+hugo gen jsonschemas --dir jsonschemas