bridgetown-core 0.19.2 → 0.21.0.beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/bridgetown-core.gemspec +1 -2
  3. data/lib/bridgetown-core.rb +37 -29
  4. data/lib/bridgetown-core/cleaner.rb +9 -3
  5. data/lib/bridgetown-core/collection.rb +177 -78
  6. data/lib/bridgetown-core/commands/base.rb +9 -0
  7. data/lib/bridgetown-core/commands/build.rb +0 -11
  8. data/lib/bridgetown-core/commands/concerns/git_helpers.rb +20 -0
  9. data/lib/bridgetown-core/commands/configure.rb +8 -3
  10. data/lib/bridgetown-core/commands/console.rb +4 -0
  11. data/lib/bridgetown-core/commands/doctor.rb +1 -19
  12. data/lib/bridgetown-core/commands/new.rb +2 -2
  13. data/lib/bridgetown-core/commands/plugins.rb +14 -13
  14. data/lib/bridgetown-core/commands/serve.rb +0 -14
  15. data/lib/bridgetown-core/component.rb +178 -0
  16. data/lib/bridgetown-core/concerns/data_accessible.rb +1 -0
  17. data/lib/bridgetown-core/concerns/front_matter_importer.rb +52 -0
  18. data/lib/bridgetown-core/concerns/site/configurable.rb +10 -10
  19. data/lib/bridgetown-core/concerns/site/content.rb +56 -15
  20. data/lib/bridgetown-core/concerns/site/localizable.rb +3 -5
  21. data/lib/bridgetown-core/concerns/site/processable.rb +6 -4
  22. data/lib/bridgetown-core/concerns/site/renderable.rb +26 -0
  23. data/lib/bridgetown-core/concerns/site/writable.rb +12 -2
  24. data/lib/bridgetown-core/concerns/validatable.rb +2 -5
  25. data/lib/bridgetown-core/configuration.rb +51 -30
  26. data/lib/bridgetown-core/configurations/bt-postcss.rb +1 -3
  27. data/lib/bridgetown-core/configurations/netlify.rb +1 -0
  28. data/lib/bridgetown-core/configurations/tailwindcss.rb +1 -3
  29. data/lib/bridgetown-core/converter.rb +23 -0
  30. data/lib/bridgetown-core/converters/erb_templates.rb +51 -35
  31. data/lib/bridgetown-core/converters/identity.rb +0 -9
  32. data/lib/bridgetown-core/converters/liquid_templates.rb +1 -1
  33. data/lib/bridgetown-core/converters/markdown.rb +14 -4
  34. data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +5 -38
  35. data/lib/bridgetown-core/converters/ruby_templates.rb +17 -0
  36. data/lib/bridgetown-core/converters/smartypants.rb +3 -1
  37. data/lib/bridgetown-core/core_ext/psych.rb +19 -0
  38. data/lib/bridgetown-core/current.rb +10 -0
  39. data/lib/bridgetown-core/document.rb +9 -16
  40. data/lib/bridgetown-core/drops/collection_drop.rb +1 -1
  41. data/lib/bridgetown-core/drops/page_drop.rb +4 -0
  42. data/lib/bridgetown-core/drops/relations_drop.rb +23 -0
  43. data/lib/bridgetown-core/drops/resource_drop.rb +83 -0
  44. data/lib/bridgetown-core/drops/site_drop.rb +33 -8
  45. data/lib/bridgetown-core/drops/unified_payload_drop.rb +5 -0
  46. data/lib/bridgetown-core/entry_filter.rb +17 -28
  47. data/lib/bridgetown-core/errors.rb +0 -2
  48. data/lib/bridgetown-core/filters.rb +3 -26
  49. data/lib/bridgetown-core/filters/from_liquid.rb +23 -0
  50. data/lib/bridgetown-core/filters/url_filters.rb +12 -0
  51. data/lib/bridgetown-core/frontmatter_defaults.rb +1 -1
  52. data/lib/bridgetown-core/generators/prototype_generator.rb +37 -19
  53. data/lib/bridgetown-core/helpers.rb +48 -9
  54. data/lib/bridgetown-core/layout.rb +28 -13
  55. data/lib/bridgetown-core/liquid_renderer/file.rb +1 -0
  56. data/lib/bridgetown-core/liquid_renderer/table.rb +1 -0
  57. data/lib/bridgetown-core/model/base.rb +138 -0
  58. data/lib/bridgetown-core/model/builder_origin.rb +40 -0
  59. data/lib/bridgetown-core/model/origin.rb +38 -0
  60. data/lib/bridgetown-core/model/repo_origin.rb +126 -0
  61. data/lib/bridgetown-core/page.rb +11 -2
  62. data/lib/bridgetown-core/plugin_manager.rb +1 -3
  63. data/lib/bridgetown-core/publisher.rb +8 -2
  64. data/lib/bridgetown-core/reader.rb +37 -22
  65. data/lib/bridgetown-core/readers/data_reader.rb +5 -5
  66. data/lib/bridgetown-core/readers/defaults_reader.rb +1 -1
  67. data/lib/bridgetown-core/readers/page_reader.rb +1 -0
  68. data/lib/bridgetown-core/readers/post_reader.rb +5 -4
  69. data/lib/bridgetown-core/regenerator.rb +9 -2
  70. data/lib/bridgetown-core/related_posts.rb +9 -6
  71. data/lib/bridgetown-core/renderer.rb +6 -13
  72. data/lib/bridgetown-core/resource/base.rb +313 -0
  73. data/lib/bridgetown-core/resource/destination.rb +49 -0
  74. data/lib/bridgetown-core/resource/permalink_processor.rb +179 -0
  75. data/lib/bridgetown-core/resource/relations.rb +132 -0
  76. data/lib/bridgetown-core/resource/taxonomy_term.rb +34 -0
  77. data/lib/bridgetown-core/resource/taxonomy_type.rb +56 -0
  78. data/lib/bridgetown-core/resource/transformer.rb +177 -0
  79. data/lib/bridgetown-core/ruby_template_view.rb +11 -11
  80. data/lib/bridgetown-core/site.rb +13 -6
  81. data/lib/bridgetown-core/static_file.rb +33 -10
  82. data/lib/bridgetown-core/tags/highlight.rb +2 -15
  83. data/lib/bridgetown-core/tags/include.rb +1 -1
  84. data/lib/bridgetown-core/tags/post_url.rb +2 -2
  85. data/lib/bridgetown-core/url.rb +1 -0
  86. data/lib/bridgetown-core/utils.rb +49 -43
  87. data/lib/bridgetown-core/utils/require_gems.rb +60 -0
  88. data/lib/bridgetown-core/utils/ruby_exec.rb +6 -9
  89. data/lib/bridgetown-core/utils/ruby_front_matter.rb +39 -0
  90. data/lib/bridgetown-core/version.rb +2 -2
  91. data/lib/bridgetown-core/watcher.rb +1 -1
  92. data/lib/bridgetown-core/yaml_parser.rb +22 -0
  93. data/lib/site_template/package.json.erb +2 -2
  94. data/lib/site_template/plugins/site_builder.rb +1 -1
  95. data/lib/site_template/src/_posts/0000-00-00-welcome-to-bridgetown.md.erb +1 -1
  96. data/lib/site_template/webpack.config.js.erb +26 -6
  97. metadata +39 -40
  98. data/lib/bridgetown-core/external.rb +0 -58
  99. data/lib/bridgetown-core/page_without_a_file.rb +0 -17
  100. data/lib/bridgetown-core/path_manager.rb +0 -31
  101. data/lib/bridgetown-core/readers/collection_reader.rb +0 -23
  102. data/lib/bridgetown-core/readers/static_file_reader.rb +0 -25
  103. data/lib/bridgetown-core/utils/exec.rb +0 -26
  104. data/lib/bridgetown-core/utils/internet.rb +0 -37
  105. data/lib/bridgetown-core/utils/platforms.rb +0 -80
  106. data/lib/bridgetown-core/utils/thread_event.rb +0 -31
  107. data/lib/bridgetown-core/utils/win_tz.rb +0 -75
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Resource
5
+ class Destination
6
+ # @return [Bridgetown::Resource::Base]
7
+ attr_accessor :resource
8
+
9
+ # @return [String]
10
+ attr_accessor :output_ext
11
+
12
+ # @param resource [Bridgetown::Resource::Base]
13
+ def initialize(resource)
14
+ @resource = resource
15
+ @output_ext = resource.transformer.final_ext
16
+ end
17
+
18
+ def absolute_url
19
+ Addressable::URI.parse(
20
+ resource.site.config.url.to_s + relative_url
21
+ ).normalize.to_s
22
+ end
23
+
24
+ def relative_url
25
+ @processor ||= PermalinkProcessor.new(resource)
26
+ @processor.transform
27
+ end
28
+
29
+ def final_ext
30
+ output_ext || resource.extname
31
+ end
32
+
33
+ def output_path
34
+ path = URL.unescape_path(relative_url)
35
+ path = path.delete_prefix(resource.site.baseurl) if resource.site.baseurl.present?
36
+ path = resource.site.in_dest_dir(path)
37
+ path = File.join(path, "index.html") if relative_url.end_with? "/"
38
+ path
39
+ end
40
+
41
+ def write(output)
42
+ path = output_path
43
+ FileUtils.mkdir_p(File.dirname(path))
44
+ Bridgetown.logger.debug "Writing:", path
45
+ File.write(path, output, mode: "wb")
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Resource
5
+ class PermalinkProcessor
6
+ # @return [Bridgetown::Resource::Base]
7
+ attr_accessor :resource
8
+
9
+ attr_accessor :slugify_mode
10
+
11
+ def self.placeholder_processors
12
+ @placeholder_processors || {}
13
+ end
14
+
15
+ def self.register_placeholder(key, block)
16
+ @placeholder_processors ||= {}
17
+ @placeholder_processors[key] = block
18
+ end
19
+
20
+ def initialize(resource)
21
+ @resource = resource
22
+ @slugify_mode = @resource.site.config.slugify_mode
23
+ end
24
+
25
+ def final_ext
26
+ resource.method(:destination).arity == 1 ? resource.extname : resource.destination.final_ext
27
+ end
28
+
29
+ def transform
30
+ permalink = resource.data.permalink ||
31
+ permalink_for_permalink_style(resource.collection.default_permalink)
32
+
33
+ # Strip out file extension and process each segment of a URL to swap out
34
+ # placeholders such as :categories or :title
35
+ url_segments = Bridgetown::Filters::URLFilters.strip_extname(permalink).split("/")
36
+ new_url = url_segments.map do |segment|
37
+ segment.starts_with?(":") ? process_segment(segment.sub(%r{^:}, "")) : segment
38
+ end.select(&:present?).join("/")
39
+
40
+ # No relative URLs should ever end in /index.html
41
+ new_url.sub!(%r{/index$}, "") if final_ext == ".html"
42
+
43
+ add_baseurl finalize_permalink(new_url, permalink)
44
+ end
45
+
46
+ def process_segment(segment)
47
+ segment = segment.to_sym
48
+ if self.class.placeholder_processors[segment]
49
+ segment_value = self.class.placeholder_processors[segment].(resource)
50
+ if segment_value.is_a?(Hash)
51
+ segment_value[:raw_value]
52
+ elsif segment_value.is_a?(Array)
53
+ segment_value.map do |subsegment|
54
+ Utils.slugify(subsegment, mode: slugify_mode)
55
+ end.join("/")
56
+ else
57
+ Utils.slugify(segment_value, mode: slugify_mode)
58
+ end
59
+ else
60
+ segment
61
+ end
62
+ end
63
+
64
+ def permalink_for_permalink_style(permalink_style)
65
+ collection_prefix = ("/:collection" unless resource.collection.builtin?)
66
+
67
+ case permalink_style.to_sym
68
+ when :pretty
69
+ "#{collection_prefix}/:categories/:year/:month/:day/:slug/"
70
+ when :pretty_ext, :date
71
+ "#{collection_prefix}/:categories/:year/:month/:day/:slug.*"
72
+ when :simple
73
+ "#{collection_prefix}/:categories/:slug/"
74
+ when :simple_ext
75
+ "#{collection_prefix}/:categories/:slug.*"
76
+ else
77
+ permalink_style.to_s
78
+ end
79
+ end
80
+
81
+ # @param new_url [String]
82
+ # @param permalink [String]
83
+ def finalize_permalink(new_url, permalink)
84
+ # Handle .* style permalinks or files not ending in .html
85
+ if permalink.ends_with?(".*") || !%r{\.html?$}.match?(final_ext)
86
+ "/#{new_url}#{final_ext}"
87
+ # If permalink includes the file extension, add it back in to the URL
88
+ elsif permalink =~ %r{\.[^/]*$}
89
+ "/#{new_url}#{Regexp.last_match[0]}"
90
+ # Ensure index-style URLs get output correctly
91
+ elsif permalink.ends_with?("/")
92
+ "/#{new_url}/".sub(%r{^/index/$}, "/")
93
+ # We good :)
94
+ else
95
+ "/#{new_url}"
96
+ end
97
+ end
98
+
99
+ def add_baseurl(permalink)
100
+ resource.site.baseurl.present? ? "#{resource.site.baseurl}#{permalink}" : permalink
101
+ end
102
+
103
+ ### Default Placeholders Processors
104
+
105
+ # @param resource [Bridgetown::Resource::Base]
106
+ register_placeholder :path, ->(resource) do
107
+ { raw_value: resource.relative_path_basename_without_prefix }
108
+ end
109
+
110
+ # @param resource [Bridgetown::Resource::Base]
111
+ register_placeholder :name, ->(resource) do
112
+ resource.basename_without_ext
113
+ end
114
+
115
+ # @param resource [Bridgetown::Resource::Base]
116
+ register_placeholder :slug, ->(resource) do
117
+ resource.data.slug || placeholder_processors[:name].(resource)
118
+ end
119
+
120
+ # @param resource [Bridgetown::Resource::Base]
121
+ register_placeholder :title, ->(resource) do
122
+ resource.data.title || placeholder_processors[:slug].(resource)
123
+ end
124
+
125
+ # @param resource [Bridgetown::Resource::Base]
126
+ register_placeholder :locale, ->(resource) do
127
+ locale_data = resource.data.locale
128
+ resource.site.config.available_locales.include?(locale_data) ? locale_data : nil
129
+ end
130
+ register_placeholder :lang, placeholder_processors[:locale]
131
+
132
+ # @param resource [Bridgetown::Resource::Base]
133
+ register_placeholder :collection, ->(resource) do
134
+ resource.collection.label
135
+ end
136
+
137
+ # @param resource [Bridgetown::Resource::Base]
138
+ register_placeholder :categories, ->(resource) do
139
+ resource.taxonomies.category&.terms&.map(&:label)&.uniq
140
+ end
141
+
142
+ # YYYY
143
+ # @param resource [Bridgetown::Resource::Base]
144
+ register_placeholder :year, ->(resource) do
145
+ resource.date.strftime("%Y")
146
+ end
147
+
148
+ # MM: 01..12
149
+ # @param resource [Bridgetown::Resource::Base]
150
+ register_placeholder :month, ->(resource) do
151
+ resource.date.strftime("%m")
152
+ end
153
+
154
+ # DD: 01..31
155
+ # @param resource [Bridgetown::Resource::Base]
156
+ register_placeholder :day, ->(resource) do
157
+ resource.date.strftime("%d")
158
+ end
159
+
160
+ # D: 1..31
161
+ # @param resource [Bridgetown::Resource::Base]
162
+ register_placeholder :i_day, ->(resource) do
163
+ resource.date.strftime("%-d")
164
+ end
165
+
166
+ # M: 1..12
167
+ # @param resource [Bridgetown::Resource::Base]
168
+ register_placeholder :i_month, ->(resource) do
169
+ resource.date.strftime("%-m")
170
+ end
171
+
172
+ # YY: 00..99
173
+ # @param resource [Bridgetown::Resource::Base]
174
+ register_placeholder :short_year, ->(resource) do
175
+ resource.date.strftime("%y")
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Resource
5
+ class Relations
6
+ # @return [Bridgetown::Resource::Base]
7
+ attr_reader :resource
8
+
9
+ # @return [Bridgetown::Site]
10
+ attr_reader :site
11
+
12
+ # @param resource [Bridgetown::Resource::Base]
13
+ def initialize(resource)
14
+ @resource = resource
15
+ @site = resource.site
16
+ end
17
+
18
+ # @return [HashWithDotAccess::Hash]
19
+ def relation_schema
20
+ resource.collection.metadata.relations
21
+ end
22
+
23
+ # @return [Array<String>]
24
+ def relation_types
25
+ @relation_types ||= begin
26
+ types = []
27
+ relation_schema&.each do |_relation_type, collections|
28
+ types << collections
29
+ types << Array(collections).map { |item| ActiveSupport::Inflector.pluralize(item) }
30
+ end
31
+ types.flatten.uniq
32
+ end
33
+ end
34
+
35
+ # @param type [Symbol]
36
+ # @return [Bridgetown::Resource::Base, Array<Bridgetown::Resource::Base>]
37
+ def resources_for_type(type)
38
+ relation_kind = kind_of_relation_for_type(type)
39
+ return [] unless relation_kind
40
+
41
+ case relation_kind.to_sym
42
+ when :belongs_to
43
+ belongs_to_relation_for_type(type)
44
+ when :has_many
45
+ has_many_relation_for_type(type)
46
+ when :has_one
47
+ has_one_relation_for_type(type)
48
+ end
49
+ end
50
+
51
+ def method_missing(type, *args)
52
+ return super unless type.to_s.in?(relation_types)
53
+
54
+ resources_for_type(type)
55
+ end
56
+
57
+ def respond_to_missing?(type, *_args)
58
+ type.to_s.in?(relation_types)
59
+ end
60
+
61
+ def to_liquid
62
+ @to_liquid ||= Drops::RelationsDrop.new(self)
63
+ end
64
+
65
+ private
66
+
67
+ # @param type [Symbol]
68
+ # @return [String]
69
+ def kind_of_relation_for_type(type)
70
+ relation_schema&.each do |relation_type, collections|
71
+ collections = Array(collections).yield_self do |collections_arr|
72
+ collections_arr +
73
+ collections_arr.map { |item| ActiveSupport::Inflector.pluralize(item) }
74
+ end.flatten.uniq
75
+ return relation_type if collections.include?(type.to_s)
76
+ end
77
+ end
78
+
79
+ # @param type [Symbol]
80
+ # @return [Bridgetown::Collection]
81
+ def other_collection_for_type(type)
82
+ site.collections[type] || site.collections[ActiveSupport::Inflector.pluralize(type)]
83
+ end
84
+
85
+ # @return [Array<String>]
86
+ def collection_labels
87
+ [
88
+ resource.collection.label,
89
+ ActiveSupport::Inflector.singularize(resource.collection.label),
90
+ ]
91
+ end
92
+
93
+ # @param type [Symbol]
94
+ # @return [Bridgetown::Resource::Base, Array<Bridgetown::Resource::Base>]
95
+ def belongs_to_relation_for_type(type)
96
+ if resource.data[type].is_a?(Array)
97
+ other_collection_for_type(type).resources.select do |other_resource|
98
+ other_resource.data.slug.in?(resource.data[type])
99
+ end
100
+ else
101
+ other_collection_for_type(type).resources.find do |other_resource|
102
+ other_resource.data.slug == resource.data[type]
103
+ end
104
+ end
105
+ end
106
+
107
+ # @param type [Symbol]
108
+ # @return [Array<Bridgetown::Resource::Base>]
109
+ def has_many_relation_for_type(type) # rubocop:disable Naming/PredicateName
110
+ label, singular_label = collection_labels
111
+
112
+ other_collection_for_type(type).resources.select do |other_resource|
113
+ resource.data.slug.in?(
114
+ Array(other_resource.data[label] || other_resource.data[singular_label])
115
+ )
116
+ end
117
+ end
118
+
119
+ # @param type [Symbol]
120
+ # @return [Bridgetown::Resource::Base]
121
+ def has_one_relation_for_type(type) # rubocop:disable Naming/PredicateName
122
+ label, singular_label = collection_labels
123
+
124
+ other_collection_for_type(type).resources.find do |other_resource|
125
+ resource.data.slug.in?(
126
+ Array(other_resource.data[label] || other_resource.data[singular_label])
127
+ )
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Resource
5
+ class TaxonomyTerm
6
+ attr_reader :resource
7
+
8
+ attr_reader :label
9
+
10
+ attr_reader :type
11
+
12
+ def initialize(resource:, label:, type:)
13
+ @resource = resource
14
+ @label = label
15
+ @type = type
16
+ end
17
+
18
+ def to_liquid
19
+ {
20
+ "label" => label,
21
+ }
22
+ end
23
+ alias_method :to_h, :to_liquid
24
+
25
+ def as_json(*)
26
+ to_h
27
+ end
28
+
29
+ ruby2_keywords def to_json(*options)
30
+ as_json(*options).to_json(*options)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Resource
5
+ class TaxonomyType
6
+ # @return [Bridgetown::Site]
7
+ attr_reader :site
8
+
9
+ # @return [String] aka `category`, `tag`, `region`, etc.
10
+ attr_reader :label
11
+
12
+ # @return [String] the key used in front matter
13
+ attr_reader :key
14
+
15
+ # @return [HashWithDotAccess::Hash] any associated metadata
16
+ attr_reader :metadata
17
+
18
+ # @param site [Bridgetown::Site]
19
+ # @param label [String]
20
+ # @param key [String]
21
+ def initialize(site:, label:, key:, metadata:)
22
+ @site = site
23
+ @label = label
24
+ @key = key
25
+ @metadata = metadata
26
+ end
27
+
28
+ def terms
29
+ site.resources.map do |resource|
30
+ resource.taxonomies[label].terms
31
+ end.flatten.group_by(&:label).with_dot_access
32
+ end
33
+
34
+ def inspect
35
+ "#<#{self.class} label=#{label}>"
36
+ end
37
+
38
+ def to_liquid
39
+ {
40
+ "label" => label,
41
+ "key" => key,
42
+ "metadata" => metadata,
43
+ }
44
+ end
45
+ alias_method :to_h, :to_liquid
46
+
47
+ def as_json(*)
48
+ to_h
49
+ end
50
+
51
+ ruby2_keywords def to_json(*options)
52
+ as_json(*options).to_json(*options)
53
+ end
54
+ end
55
+ end
56
+ end