bridgetown-core 0.19.2 → 0.21.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
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,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Resource
5
+ class Transformer
6
+ # @return [Array<Hash>]
7
+ attr_reader :conversions
8
+
9
+ # @return [Bridgetown::Resource::Base]
10
+ attr_reader :resource
11
+
12
+ # @return [Bridgetown::Site]
13
+ attr_reader :site
14
+
15
+ def initialize(resource)
16
+ @resource = resource
17
+ @site = resource.site
18
+ @conversions = []
19
+ end
20
+
21
+ # @return [String]
22
+ def output_ext
23
+ @output_ext ||= output_ext_from_converters
24
+ end
25
+
26
+ # @return [String]
27
+ def final_ext
28
+ output_ext # we always need this to get run
29
+
30
+ permalink_ext || output_ext
31
+ end
32
+
33
+ def process!
34
+ Bridgetown.logger.debug "Transforming:", resource.relative_path
35
+ resource.around_hook :render do
36
+ run_conversions
37
+ resource.place_in_layout? ? place_into_layouts : resource.output = resource.content.dup
38
+ end
39
+ end
40
+
41
+ def execute_inline_ruby!
42
+ return unless site.config.should_execute_inline_ruby?
43
+
44
+ Bridgetown::Utils::RubyExec.search_data_for_ruby_code(resource, self)
45
+ end
46
+
47
+ def inspect
48
+ "#<#{self.class} Conversion Steps: #{conversions.length}>"
49
+ end
50
+
51
+ private
52
+
53
+ ### Utilities
54
+
55
+ def permalink_ext
56
+ resource_permalink = resource.permalink
57
+ if resource_permalink &&
58
+ !resource_permalink.end_with?("/") &&
59
+ !resource_permalink.end_with?(".*")
60
+ permalink_ext = File.extname(resource_permalink)
61
+ permalink_ext unless permalink_ext.empty?
62
+ end
63
+ end
64
+
65
+ # @return [Array<Bridgetown::Converter>]
66
+ def converters
67
+ @converters ||= site.matched_converters_for_convertible(resource)
68
+ end
69
+
70
+ # @return [String]
71
+ def output_ext_from_converters
72
+ @conversions = converters.map do |converter|
73
+ {
74
+ converter: converter,
75
+ output_ext: converter.output_ext(resource.extname),
76
+ }
77
+ end
78
+
79
+ conversions
80
+ .reverse
81
+ .find do |conversion|
82
+ conversions.length == 1 ||
83
+ !conversion[:converter].is_a?(Bridgetown::Converters::Identity)
84
+ end
85
+ .fetch(:output_ext)
86
+ end
87
+
88
+ # @return [Array<Bridgetown::Layout>]
89
+ def validated_layouts
90
+ layout = site.layouts[resource.data.layout]
91
+ warn_on_missing_layout layout, resource.data.layout
92
+
93
+ layout_list = Set.new([layout])
94
+ while layout
95
+ layout_name = layout.data.layout
96
+ layout = site.layouts[layout_name]
97
+ warn_on_missing_layout layout, layout_name
98
+
99
+ layout_list << layout
100
+ end
101
+
102
+ layout_list.to_a.compact
103
+ end
104
+
105
+ def warn_on_missing_layout(layout, layout_name)
106
+ if layout.nil? && layout_name
107
+ Bridgetown.logger.warn "Build Warning:", "Layout '#{layout_name}' " \
108
+ "requested via #{resource.relative_path} does not exist."
109
+ end
110
+ end
111
+
112
+ ### Transformation Actions
113
+
114
+ def run_conversions # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
115
+ input = resource.content.to_s
116
+
117
+ # @param content [String]
118
+ # @param converter [Bridgetown::Converter]
119
+ resource.content = converters.each_with_index.inject(input) do |content, (converter, index)|
120
+ output = if converter.method(:convert).arity == 1
121
+ converter.convert content
122
+ else
123
+ converter.convert content, resource
124
+ end
125
+ conversions[index] = {
126
+ type: :content,
127
+ converter: converter,
128
+ output: Bridgetown.env.production? ? nil : output,
129
+ output_ext: conversions[index]&.dig(:output_ext) ||
130
+ converter.output_ext(resource.extname),
131
+ }
132
+ output.html_safe
133
+ rescue StandardError => e
134
+ Bridgetown.logger.error "Conversion error:",
135
+ "#{converter.class} encountered an error while "\
136
+ "converting `#{resource.relative_path}'"
137
+ raise e
138
+ end
139
+ end
140
+
141
+ def place_into_layouts
142
+ Bridgetown.logger.debug "Placing in Layouts:", resource.relative_path
143
+ output = resource.content.dup
144
+ validated_layouts.each do |layout|
145
+ output = run_layout_conversions layout, output
146
+ end
147
+ resource.output = output
148
+ end
149
+
150
+ def run_layout_conversions(layout, output)
151
+ layout_converters = site.matched_converters_for_convertible(layout)
152
+ layout_input = layout.content.dup
153
+
154
+ layout_converters.inject(layout_input) do |content, converter|
155
+ next(content) unless [2, -2].include?(converter.method(:convert).arity)
156
+
157
+ layout.current_document = resource
158
+ layout.current_document_output = output
159
+ layout_output = converter.convert content, layout
160
+
161
+ conversions << {
162
+ type: :layout,
163
+ layout: layout,
164
+ converter: converter,
165
+ output: Bridgetown.env.production? ? nil : layout_output,
166
+ }
167
+ layout_output
168
+ rescue StandardError => e
169
+ Bridgetown.logger.error "Conversion error:",
170
+ "#{converter.class} encountered an error while "\
171
+ "converting `#{resource.relative_path}'"
172
+ raise e
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
@@ -7,6 +7,7 @@ module Bridgetown
7
7
  require "bridgetown-core/helpers"
8
8
 
9
9
  attr_reader :layout, :page, :paginator, :site, :content
10
+ alias_method :resource, :page
10
11
 
11
12
  def initialize(convertible)
12
13
  if convertible.is_a?(Layout)
@@ -27,20 +28,17 @@ module Bridgetown
27
28
 
28
29
  def render(item, options = {}, &block)
29
30
  if item.respond_to?(:render_in)
30
- previous_buffer_state = @_erbout
31
- @_erbout = Bridgetown::ERBBuffer.new
32
-
33
- @in_view_component ||= defined?(::ViewComponent::Base) && item.is_a?(::ViewComponent::Base)
34
31
  result = item.render_in(self, &block)
35
- @in_view_component = false
36
-
37
- @_erbout = previous_buffer_state
38
- result
32
+ result&.html_safe
39
33
  else
40
- partial(item, options, &block)
34
+ partial(item, options, &block)&.html_safe
41
35
  end
42
36
  end
43
37
 
38
+ def collections
39
+ site.collections
40
+ end
41
+
44
42
  def site_drop
45
43
  site.site_payload.site
46
44
  end
@@ -56,14 +54,15 @@ module Bridgetown
56
54
  Bridgetown.logger.warn "Liquid Warning:",
57
55
  LiquidRenderer.format_error(e, path || document.relative_path)
58
56
  end
59
- template.render!(options.deep_stringify_keys, _liquid_context)
57
+ template.render!(options.deep_stringify_keys, _liquid_context).html_safe
60
58
  end
61
59
 
62
60
  def helpers
63
61
  @helpers ||= Helpers.new(self, site)
64
62
  end
65
63
 
66
- def method_missing(method, *args, &block)
64
+ # rubocop:disable Style/MissingRespondToMissing
65
+ ruby2_keywords def method_missing(method, *args, &block)
67
66
  if helpers.respond_to?(method.to_sym)
68
67
  helpers.send method.to_sym, *args, &block
69
68
  else
@@ -74,6 +73,7 @@ module Bridgetown
74
73
  def respond_to_missing?(method, include_private = false)
75
74
  helpers.respond_to?(method.to_sym, include_private) || super
76
75
  end
76
+ # rubocop:enable Style/MissingRespondToMissing
77
77
 
78
78
  private
79
79
 
@@ -26,12 +26,15 @@ module Bridgetown
26
26
  # @return [Array<Page>]
27
27
  attr_accessor :pages
28
28
 
29
- attr_accessor :exclude, :include, :lsi, :highlighter, :permalink_style,
30
- :time, :future, :unpublished, :limit_posts,
31
- :keep_files, :baseurl, :data, :file_read_opts,
32
- :plugin_manager, :converters, :generators, :reader
29
+ # NOTE: Eventually pages will be deprecated once the Resource content engine
30
+ # is default
31
+ alias_method :generated_pages, :pages
33
32
 
34
- # Public: Initialize a new Site.
33
+ attr_accessor :permalink_style, :time, :baseurl, :data,
34
+ :file_read_opts, :plugin_manager, :converters,
35
+ :generators, :reader
36
+
37
+ # Initialize a new Site.
35
38
  #
36
39
  # config - A Hash containing site configuration details.
37
40
  def initialize(config)
@@ -46,7 +49,7 @@ module Bridgetown
46
49
 
47
50
  ensure_not_in_dest
48
51
 
49
- Bridgetown.sites << self
52
+ Bridgetown::Current.site = self
50
53
  Bridgetown::Hooks.trigger :site, :after_init, self
51
54
 
52
55
  reset # Processable
@@ -64,5 +67,9 @@ module Bridgetown
64
67
  end
65
68
  end
66
69
  end
70
+
71
+ def inspect
72
+ "#<Bridgetown::Site #{metadata.inspect.delete_prefix("{").delete_suffix("}")}>"
73
+ end
67
74
  end
68
75
  end
@@ -4,7 +4,7 @@ module Bridgetown
4
4
  class StaticFile
5
5
  extend Forwardable
6
6
 
7
- attr_reader :relative_path, :extname, :name, :data
7
+ attr_reader :relative_path, :extname, :name, :data, :site, :collection
8
8
 
9
9
  def_delegator :to_liquid, :to_json, :to_json
10
10
 
@@ -25,8 +25,7 @@ module Bridgetown
25
25
  # base - The String path to the <source>.
26
26
  # dir - The String path between <source> and the file.
27
27
  # name - The String filename of the file.
28
- # rubocop: disable Metrics/ParameterLists
29
- def initialize(site, base, dir, name, collection = nil)
28
+ def initialize(site, base, dir, name, collection = nil) # rubocop:disable Metrics/ParameterLists
30
29
  @site = site
31
30
  @base = base
32
31
  @dir = dir
@@ -34,9 +33,15 @@ module Bridgetown
34
33
  @collection = collection
35
34
  @relative_path = File.join(*[@dir, @name].compact)
36
35
  @extname = File.extname(@name)
37
- @data = @site.frontmatter_defaults.all(relative_path, type)
36
+ @data = @site.frontmatter_defaults.all(relative_path, type).with_dot_access
37
+ if site.uses_resource? && !data.permalink
38
+ data.permalink = if collection && !collection.builtin?
39
+ "/:collection/:path.*"
40
+ else
41
+ "/:path.*"
42
+ end
43
+ end
38
44
  end
39
- # rubocop: enable Metrics/ParameterLists
40
45
 
41
46
  # Returns source file path.
42
47
  def path
@@ -51,8 +56,11 @@ module Bridgetown
51
56
  #
52
57
  # Returns destination file path.
53
58
  def destination(dest)
54
- dest = @site.in_dest_dir(dest)
55
- @site.in_dest_dir(dest, Bridgetown::URL.unescape_path(url))
59
+ dest = site.in_dest_dir(dest)
60
+ dest_url = url
61
+ dest_url = dest_url.delete_prefix(site.baseurl) if site.uses_resource? &&
62
+ site.baseurl.present? && collection
63
+ site.in_dest_dir(dest, Bridgetown::URL.unescape_path(dest_url))
56
64
  end
57
65
 
58
66
  def destination_rel_dir
@@ -118,6 +126,15 @@ module Bridgetown
118
126
  @basename ||= File.basename(name, extname).gsub(%r!\.*\z!, "")
119
127
  end
120
128
 
129
+ def relative_path_basename_without_prefix
130
+ return_path = Pathname.new("")
131
+ Pathname.new(cleaned_relative_path).each_filename do |filename|
132
+ return_path += filename unless filename.starts_with?("_")
133
+ end
134
+
135
+ (return_path.dirname + return_path.basename(".*")).to_s
136
+ end
137
+
121
138
  def placeholders
122
139
  {
123
140
  collection: @collection.label,
@@ -154,15 +171,21 @@ module Bridgetown
154
171
  # be overriden in the collection's configuration in bridgetown.config.yml.
155
172
  def url
156
173
  @url ||= begin
157
- base = if @collection.nil? || @collection.label == "posts"
174
+ newly_processed = false
175
+ special_posts_case = @collection&.label == "posts" &&
176
+ site.config.content_engine != "resource"
177
+ base = if @collection.nil? || special_posts_case
158
178
  cleaned_relative_path
179
+ elsif site.uses_resource?
180
+ newly_processed = true
181
+ Bridgetown::Resource::PermalinkProcessor.new(self).transform
159
182
  else
160
183
  Bridgetown::URL.new(
161
184
  template: @collection.url_template,
162
185
  placeholders: placeholders
163
186
  )
164
187
  end.to_s.chomp("/")
165
- base << extname
188
+ newly_processed ? base : "#{base}#{extname}"
166
189
  end
167
190
  end
168
191
 
@@ -174,7 +197,7 @@ module Bridgetown
174
197
  # Returns the front matter defaults defined for the file's URL and/or type
175
198
  # as defined in bridgetown.config.yml.
176
199
  def defaults
177
- @defaults ||= @site.frontmatter_defaults.all url, type
200
+ @defaults ||= site.frontmatter_defaults.all url, type
178
201
  end
179
202
 
180
203
  # Returns a debug string on inspecting the static file.
@@ -36,13 +36,11 @@ module Bridgetown
36
36
  code = super.to_s.gsub(LEADING_OR_TRAILING_LINE_TERMINATORS, "")
37
37
 
38
38
  output =
39
- case context.registers[:site].highlighter
39
+ case context.registers[:site].config.highlighter
40
40
  when "rouge"
41
41
  render_rouge(code)
42
- when "pygments"
43
- render_pygments(code, context)
44
42
  else
45
- render_codehighlighter(code)
43
+ h(code).strip
46
44
  end
47
45
 
48
46
  rendered_output = add_code_tag(output)
@@ -72,13 +70,6 @@ module Bridgetown
72
70
  options
73
71
  end
74
72
 
75
- def render_pygments(code, _context)
76
- Bridgetown.logger.warn "Warning:", "Highlight Tag no longer supports" \
77
- " rendering with Pygments."
78
- Bridgetown.logger.warn "", "Using the default highlighter, Rouge, instead."
79
- render_rouge(code)
80
- end
81
-
82
73
  def render_rouge(code)
83
74
  require "rouge"
84
75
  formatter = ::Rouge::Formatters::HTMLLegacy.new(
@@ -92,10 +83,6 @@ module Bridgetown
92
83
  formatter.format(lexer.lex(code))
93
84
  end
94
85
 
95
- def render_codehighlighter(code)
96
- h(code).strip
97
- end
98
-
99
86
  def add_code_tag(code)
100
87
  code_attributes = [
101
88
  "class=\"language-#{@lang.to_s.tr("+", "-")}\"",
@@ -112,7 +112,7 @@ module Bridgetown
112
112
  def locate_include_file(context, file)
113
113
  includes_dirs = tag_includes_dirs(context)
114
114
  includes_dirs.each do |dir|
115
- path = PathManager.join(dir, file)
115
+ path = File.join(dir, file)
116
116
  return path if valid_include_file?(path, dir.to_s)
117
117
  end
118
118
  raise IOError, could_not_locate_message(file, includes_dirs)
@@ -77,14 +77,14 @@ module Bridgetown
77
77
  @context = context
78
78
  site = context.registers[:site]
79
79
 
80
- site.posts.docs.each do |document|
80
+ site.collections.posts.docs.each do |document|
81
81
  return relative_url(document) if @post == document
82
82
  end
83
83
 
84
84
  # New matching method did not match, fall back to old method
85
85
  # with deprecation warning if this matches
86
86
 
87
- site.posts.docs.each do |document|
87
+ site.collections.posts.docs.each do |document|
88
88
  next unless @post.deprecated_equality document
89
89
 
90
90
  Bridgetown::Deprecator.deprecation_message "A call to "\
@@ -129,6 +129,7 @@ module Bridgetown
129
129
  #
130
130
  # Returns the escaped path.
131
131
  def self.escape_path(path)
132
+ path = path.to_s
132
133
  return path if path.empty? || %r!^[a-zA-Z0-9./-]+$!.match?(path)
133
134
 
134
135
  # Because URI.escape doesn't escape "?", "[" and "]" by default,