diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-01-02 12:33:26 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-03-23 18:51:22 +0100 |
commit | 597e418cb02883418f2cebb41400e8e61413f651 (patch) | |
tree | 177ad9c540b2583b6dab138c9f0490d28989c7f7 /resources/page/page_generate/generate_page_wrappers.go | |
parent | 44f5c1c14cb1f42cc5f01739c289e9cfc83602af (diff) |
Make Page an interface
The main motivation of this commit is to add a `page.Page` interface to replace the very file-oriented `hugolib.Page` struct.
This is all a preparation step for issue #5074, "pages from other data sources".
But this also fixes a set of annoying limitations, especially related to custom output formats, and shortcodes.
Most notable changes:
* The inner content of shortcodes using the `{{%` as the outer-most delimiter will now be sent to the content renderer, e.g. Blackfriday.
This means that any markdown will partake in the global ToC and footnote context etc.
* The Custom Output formats are now "fully virtualized". This removes many of the current limitations.
* The taxonomy list type now has a reference to the `Page` object.
This improves the taxonomy template `.Title` situation and make common template constructs much simpler.
See #5074
Fixes #5763
Fixes #5758
Fixes #5090
Fixes #5204
Fixes #4695
Fixes #5607
Fixes #5707
Fixes #5719
Fixes #3113
Fixes #5706
Fixes #5767
Fixes #5723
Fixes #5769
Fixes #5770
Fixes #5771
Fixes #5759
Fixes #5776
Fixes #5777
Fixes #5778
Diffstat (limited to 'resources/page/page_generate/generate_page_wrappers.go')
-rw-r--r-- | resources/page/page_generate/generate_page_wrappers.go | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/resources/page/page_generate/generate_page_wrappers.go b/resources/page/page_generate/generate_page_wrappers.go new file mode 100644 index 000000000..af85cb429 --- /dev/null +++ b/resources/page/page_generate/generate_page_wrappers.go @@ -0,0 +1,212 @@ +// Copyright 2019 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package page_generate + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "reflect" + + "github.com/pkg/errors" + + "github.com/gohugoio/hugo/common/maps" + + "github.com/gohugoio/hugo/codegen" + "github.com/gohugoio/hugo/resources/page" + "github.com/gohugoio/hugo/source" +) + +const header = `// Copyright 2019 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file is autogenerated. +` + +var ( + fileInterfaceDeprecated = reflect.TypeOf((*source.FileWithoutOverlap)(nil)).Elem() + pageInterfaceDeprecated = reflect.TypeOf((*page.DeprecatedWarningPageMethods)(nil)).Elem() + pageInterface = reflect.TypeOf((*page.Page)(nil)).Elem() + + packageDir = filepath.FromSlash("resources/page") +) + +func Generate(c *codegen.Inspector) error { + if err := generateMarshalJSON(c); err != nil { + return errors.Wrap(err, "failed to generate JSON marshaler") + + } + + if err := generateDeprecatedWrappers(c); err != nil { + return errors.Wrap(err, "failed to generate deprecate wrappers") + } + + return nil +} + +func generateMarshalJSON(c *codegen.Inspector) error { + filename := filepath.Join(c.ProjectRootDir, packageDir, "page_marshaljson.autogen.go") + f, err := os.Create(filename) + + if err != nil { + return err + } + defer f.Close() + + includes := []reflect.Type{pageInterface} + + // Exclude these methods + excludes := []reflect.Type{ + // We need to eveluate the deprecated vs JSON in the future, + // but leave them out for now. + pageInterfaceDeprecated, + + // Leave this out for now. We need to revisit the author issue. + reflect.TypeOf((*page.AuthorProvider)(nil)).Elem(), + + // navigation.PageMenus + + // Prevent loops. + reflect.TypeOf((*page.SitesProvider)(nil)).Elem(), + reflect.TypeOf((*page.Positioner)(nil)).Elem(), + + reflect.TypeOf((*page.ChildCareProvider)(nil)).Elem(), + reflect.TypeOf((*page.TreeProvider)(nil)).Elem(), + reflect.TypeOf((*page.InSectionPositioner)(nil)).Elem(), + reflect.TypeOf((*page.PaginatorProvider)(nil)).Elem(), + reflect.TypeOf((*maps.Scratcher)(nil)).Elem(), + } + + methods := c.MethodsFromTypes( + includes, + excludes) + + if len(methods) == 0 { + return errors.New("no methods found") + } + + marshalJSON, pkgImports := methods.ToMarshalJSON("Page", "github.com/gohugoio/hugo/resources/page") + + fmt.Fprintf(f, `%s + +package page + +%s + + +%s + + +`, header, importsString(pkgImports), marshalJSON) + + return nil +} + +func generateDeprecatedWrappers(c *codegen.Inspector) error { + filename := filepath.Join(c.ProjectRootDir, packageDir, "page_wrappers.autogen.go") + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + // Generate a wrapper for deprecated page methods + + reasons := map[string]string{ + "IsDraft": "Use .Draft.", + "Hugo": "Use the global hugo function.", + "LanguagePrefix": "Use .Site.LanguagePrefix.", + "GetParam": "Use .Param or .Params.myParam.", + "RSSLink": `Use the Output Format's link, e.g. something like: + {{ with .OutputFormats.Get "RSS" }}{{ . RelPermalink }}{{ end }}`, + "URL": "Use .Permalink or .RelPermalink. If what you want is the front matter URL value, use .Params.url", + } + + deprecated := func(name string, tp reflect.Type) string { + var alternative string + if tp == fileInterfaceDeprecated { + alternative = "Use .File." + name + } else { + var found bool + alternative, found = reasons[name] + if !found { + panic(fmt.Sprintf("no deprecated reason found for %q", name)) + } + } + + return fmt.Sprintf("helpers.Deprecated(%q, %q, %q, false)", "Page", "."+name, alternative) + } + + var buff bytes.Buffer + + methods := c.MethodsFromTypes([]reflect.Type{fileInterfaceDeprecated, pageInterfaceDeprecated}, nil) + + for _, m := range methods { + fmt.Fprint(&buff, m.Declaration("*pageDeprecated")) + fmt.Fprintln(&buff, " {") + fmt.Fprintf(&buff, "\t%s\n", deprecated(m.Name, m.Owner)) + fmt.Fprintf(&buff, "\t%s\n}\n", m.Delegate("p", "p")) + + } + + pkgImports := append(methods.Imports(), "github.com/gohugoio/hugo/helpers") + + fmt.Fprintf(f, `%s + +package page + +%s +// NewDeprecatedWarningPage adds deprecation warnings to the given implementation. +func NewDeprecatedWarningPage(p DeprecatedWarningPageMethods) DeprecatedWarningPageMethods { + return &pageDeprecated{p: p} +} + +type pageDeprecated struct { + p DeprecatedWarningPageMethods +} + +%s + +`, header, importsString(pkgImports), buff.String()) + + return nil +} + +func importsString(imps []string) string { + if len(imps) == 0 { + return "" + } + + if len(imps) == 1 { + return fmt.Sprintf("import %q", imps[0]) + } + + impsStr := "import (\n" + for _, imp := range imps { + impsStr += fmt.Sprintf("%q\n", imp) + } + + return impsStr + ")" +} |