yass 0.6.1 → 0.8.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dbf192ae9cf4c4a5b3e25e2d9bf3dabdf3a1fececf59dad399d172011a6016f4
4
- data.tar.gz: 7b39f236d0b15b947be5a8553feefa12d8a65b7fdacfd75c7d98049089c3dbc1
3
+ metadata.gz: 56e665858452753381b536e074b6274703fd300fa17d632db1c5ff483200534f
4
+ data.tar.gz: bf41608fb07a38904412bc128a3c02a5cb5688798bb3f60402f905c553b601f6
5
5
  SHA512:
6
- metadata.gz: ad8980f7bcd8b5ff6a8620e21c083b21fb803296f7d19fe5e64ba0b9934f22c4d5f5df47d6e72297ca564fe990821d48795f824755da603f35ded65dd322b0ce
7
- data.tar.gz: 0d82bbf8fc40f76a1da01a634d5673364353d3db5db116283520b5cea266df1880d29a5b86be6347fe41d0e47efcc3d02f3268a5d2bc74779c08d515d7e740f7
6
+ metadata.gz: 1f9cd5d5c10817e729ba035c31af5afed41c5db07311b186226d48a698f8d72ee06844363fda9a1abc9e8942a07684ace5c6a6ed43404492d26b99041c6439ba
7
+ data.tar.gz: 24708d754b8835a1c86b5d004343cba13e6c166dfd6a1565ff4092924c31d140ff7a43db338ae07e7870c14475a524e05b37a0bbe481f079a98cc94ac1de7899
data/README.md CHANGED
@@ -17,7 +17,7 @@ Creating blog/site/assets/highlight.min.js
17
17
  Creating blog/site/assets/highlightjs-atom-one-dark.min.css
18
18
  Creating blog/site/assets/main.css.liquid
19
19
  Creating blog/site/helpers/index.md.liquid
20
- Creating blog/site/index.splash.md.liquid
20
+ Creating blog/site/index.md.liquid
21
21
  Creating blog/site/layouts-templates/index.md.liquid
22
22
  Creating blog/templates/asset_tags.liquid
23
23
  Creating blog/templates/nav.liquid
@@ -32,16 +32,16 @@ The built site will be placed into `dist`.
32
32
  yass build
33
33
  ```
34
34
 
35
- NOTE If you're building for webserverless, local viewing, and using the `skip_index` filter anywhere, use the `--no-skip-index` option.
35
+ NOTE If you're building for webserverless, local viewing, and using the `strip_index` filter anywhere, use the `--no-strip-index` option.
36
36
 
37
37
  ```bash
38
- yass build --no-skip-index
38
+ yass build --no-strip-index
39
39
  ```
40
40
 
41
41
  Use the `watch` command to continually build your site as files change.
42
42
 
43
43
  ```bash
44
- yass watch # also supports --no-skip-index
44
+ yass watch # also supports --no-strip-index
45
45
  ```
46
46
 
47
47
  ## License
@@ -4,6 +4,7 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>{{ page.title }}</title>
7
+ <link rel="icon" href="{{ "favicon.png" | relative }}" sizes="32x32">
7
8
  {% render "asset_tags", files: files, page: page %}
8
9
  </head>
9
10
  <body>
@@ -4,6 +4,7 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>{{ page.title }}</title>
7
+ <link rel="icon" href="{{ "favicon.png" | relative }}" sizes="32x32">
7
8
  {% render "asset_tags", files: files, page: page %}
8
9
  </head>
9
10
  <body>
Binary file
@@ -8,12 +8,16 @@ Your `.liquid` files have access to all the [standard Liquid tags and filters](h
8
8
 
9
9
  An object representing the current page. Properties:
10
10
 
11
- * `title` A titleized version of the filename (e.g. *My File* from *my-file.html*)
11
+ * `title` A titleized version of the filename (e.g. *My File* from *my-file.html*), or from YAML front matter
12
+ * `layout` Name of the page's layout (if any), e.g. *default.html*
12
13
  * `src_path` Path with the original filename (e.g. *foo/bar/zorp.md.liquid*)
13
14
  * `path` URL path relative to the relative root (e.g. *foo/bar/zorp.html*)
14
15
  * `dirname` Directory file is in (e.g. *foo/bar* from *foo/bar/zorp.html*)
15
16
  * `filename` Name of file (e.g. *zorp.html* from *foo/bar/zorp.html*)
16
17
  * `extname` File extension (e.g. *.html* from *foo/bar/zorp.html*)
18
+ * `filesize` Size of file in bytes
19
+ * `published` If the file is published or not
20
+ * Any other value defined in the file's YAML front matter
17
21
 
18
22
  {% highlight html %}
19
23
  <h1>{% echo "{{" %} page.title {% echo "}}" %}</h1>
@@ -21,7 +25,7 @@ An object representing the current page. Properties:
21
25
 
22
26
  ### files
23
27
 
24
- Any array of all files that will be written `dist/`. Same properties as `page`.
28
+ Any array of all (published) files that will be written `dist/`. Same properties as `page`.
25
29
 
26
30
  {% highlight html %}
27
31
  {% echo '{% assign css_files = files | where: "extname", ".css" %' %}}
@@ -66,6 +70,14 @@ Works like Liquid's built-it `where`, but accepts a regular expression.
66
70
  {% echo '{% assign posts = where_match: "path", "^posts/.+\.html$" %' %}}
67
71
  {% endhighlight %}
68
72
 
73
+ ### where_not
74
+
75
+ Works like Liquid's built-it `where`, but returns object that *don't* match.
76
+
77
+ {% highlight %}
78
+ {% echo '{% assign posts = where_not: "hidden", true %' %}}
79
+ {% endhighlight %}
80
+
69
81
  ## Tags
70
82
 
71
83
  ### highlight
@@ -1,6 +1,9 @@
1
+ ---
2
+ layout: splash
3
+ ---
1
4
  # What is Yass?
2
5
 
3
- Yass is an astonishingly un-opinionated static site generator. Your sites's structure is entirely up to you: organize static assets, `.html` files, `.md` ([Markdown](https://commonmark.org/)) files, and `.liquid` ([Liquid](https://shopify.github.io/liquid/)) templates however you want under `site/`. Liquid layouts and reusable templates are supported but optional.
6
+ Yass is an astonishingly un-opinionated static site generator. Your sites's structure is entirely up to you: organize static assets, `.html` files, `.md` ([Markdown](https://github.github.com/gfm/)) files, and `.liquid` ([Liquid](https://shopify.github.io/liquid/)) templates however you want under `site/`. Liquid layouts, reusable templates, and YAML front matter are supported.
4
7
 
5
8
  The **one** opinion Yass holds is that **you** should decide everything. There's zero configuration and no conventions to learn!
6
9
 
@@ -17,7 +20,7 @@ Creating blog/site/assets/highlight.min.js
17
20
  Creating blog/site/assets/highlightjs-atom-one-dark.min.css
18
21
  Creating blog/site/assets/main.css.liquid
19
22
  Creating blog/site/helpers/index.md.liquid
20
- Creating blog/site/index.splash.md.liquid
23
+ Creating blog/site/index.md.liquid
21
24
  Creating blog/site/layouts-templates/index.md.liquid
22
25
  Creating blog/templates/asset_tags.liquid
23
26
  Creating blog/templates/nav.liquid
@@ -40,18 +43,20 @@ $ yass build
40
43
 
41
44
  To preview your site on your computer, simply open `dist/index.html` with your browser 🤯. (This requires using relative links, but there are helpers for that.)
42
45
 
43
- If you're building for webserverless, local viewing, and using the `skip_index` filter anywhere, use the `--no-skip-index` option.
46
+ If you're building for webserverless, local viewing, and using the `strip_index` filter anywhere, use the `--no-strip-index` option.
44
47
 
45
48
  {% highlight bash %}
46
- $ yass build --no-skip-index
49
+ $ yass build --no-strip-index
47
50
  {% endhighlight %}
48
51
 
49
52
  The `watch` command will continuously build as you make changes in `site/`, `layouts/`, and `templates/`.
50
53
 
51
54
  {% highlight bash %}
52
- $ yass watch # --no-skip-index works here too
55
+ $ yass watch # --no-strip-index works here too
53
56
  {% endhighlight %}
54
57
 
58
+ Run `yass --help` for all options.
59
+
55
60
  ## Interested?
56
61
 
57
62
  Keep reading about [layouts, templates]({{ "layouts-templates/index.html" | relative | strip_index }}), and [helpers]({{ "helpers/index.html" | relative | strip_index }}), or check out the code on [Github](https://github.com/jhollinger/yass)!
@@ -1,6 +1,27 @@
1
+ # Front Matter
2
+
3
+ Any file under `site/` may prepend YAML front matter to tweak how that file is rendered. All fields are optional.
4
+
5
+ {% highlight yaml %}
6
+ ---
7
+ # The default title is based on the filename
8
+ title: My Title
9
+ # Override the default layout, or disable the layout with false
10
+ layout: home
11
+ # If this file isn't ready yet, set to false
12
+ published: true
13
+
14
+ # Arbitrary values will be available on `page` and `files`
15
+ my_val: bar
16
+ ---
17
+ <!DOCTYPE html>
18
+ <html lang="en">
19
+ ...
20
+ {% endhighlight %}
21
+
1
22
  # Layouts
2
23
 
3
- Layouts live in `layouts/` and will be applied to files with matching names. The `content` variable contains the data to render in the layout.
24
+ Layouts are `.liquid` files in `layouts/`. The `content` variable contains the data to render.
4
25
 
5
26
  {% highlight html %}
6
27
  <!DOCTYPE html>
@@ -14,18 +35,20 @@ Layouts live in `layouts/` and will be applied to files with matching names. The
14
35
  </html>
15
36
  {% endhighlight %}
16
37
 
17
- If the above layout is named *page.html.liquid*, it will match any file named `*.page.html*`. Examples:
18
-
19
- * `foo.page.html`
20
- * `foo.page.html.*`
21
- * `foo.page.md` (because *.md* converts to *.html*)
22
- * `foo.page.md.*`
38
+ Layouts can be applied in the YAML front matter of any file under `site/`. If the following file is named `bar.html*` or `bar.md*`, it will look for a layout named `foo.html.liquid`:
23
39
 
24
- The name of the layout (e.g. `page`) is removed from the final filename, resulting in `foo.html`.
40
+ {% highlight yaml %}
41
+ ---
42
+ layout: foo
43
+ ---
44
+ My content
45
+ {% endhighlight %}
25
46
 
26
47
  ## Default layouts
27
48
 
28
- If you create a layout named `default.<ext>.liquid`, Yass will apply it to any `.<ext>` files without layouts. For example, a layout named `default.html.liquid` will match `foo.html` or `foo.not-a-layout.md.liquid`.
49
+ If you create a layout named `default.<ext>.liquid`, Yass will apply it to any `.<ext>` files without a layout. For example, a layout named `default.html.liquid` will match `foo.html` or `foo.md.liquid`.
50
+
51
+ A file may eschew the default layout by setting `layout: false` in the YAML front matter.
29
52
 
30
53
  # Templates
31
54
 
@@ -49,6 +49,7 @@ yass <command> [path/to/dir] [options]
49
49
  ).strip
50
50
  opts.on("--clean", "Remove unknown files from dist/ when bulding") { config.clean = true }
51
51
  opts.on("--dest=DIR", "Build to a different directory") { |dir| config.dest = find_path(dir, cwd: Dir.pwd) }
52
+ opts.on("--drafts", "Include unpublished files in build") { config.include_drafts = true }
52
53
  opts.on("--no-strip-index", "Disable the strip_index Liquid filter") { config.strip_index = false }
53
54
  opts.on("--debug", "Print stack traces") { config.debug = true }
54
55
  opts.on("-h", "--help", "Prints this help") { config.stdout.puts opts; exit }
@@ -63,6 +64,7 @@ yass <command> [path/to/dir] [options]
63
64
  templates: "templates",
64
65
  dest: "dist",
65
66
  clean: false,
67
+ include_drafts: false,
66
68
  strip_index: true,
67
69
  stdin: $stdin,
68
70
  stdout: $stdout,
data/lib/yass/config.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Yass
2
- Config = Struct.new(:cwd, :src, :dest, :layouts, :templates, :clean, :strip_index, :stdin, :stdout, :stderr, :debug, keyword_init: true) do
2
+ Config = Struct.new(:cwd, :src, :dest, :layouts, :templates, :clean, :include_drafts, :strip_index, :stdin, :stdout, :stderr, :debug, keyword_init: true) do
3
3
  def src_dir = @src_dir ||= get_dir(src)
4
4
  def dest_dir = @dest_dir ||= get_dir(dest)
5
5
  def template_dir = @template_dir ||= get_dir(templates)
@@ -23,6 +23,7 @@ module Yass
23
23
  .reject { |path| Dir.exist? path }
24
24
  .map { |path| Pathname.new path }
25
25
  .map { |path| Source.new(self, path) }
26
+ .select { |source| source.published? || include_drafts }
26
27
  end
27
28
 
28
29
  def liquid_env
@@ -24,10 +24,10 @@ module Yass
24
24
 
25
25
  private
26
26
 
27
- def generate(source, outfile, content = source.path.read)
27
+ def generate(source, outfile, content = source.content)
28
28
  case outfile.extname
29
29
  when ".md"
30
- content = Kramdown::Document.new(content).to_html
30
+ content = Kramdown::Document.new(content, input: "GFM").to_html
31
31
  return generate(source, outfile.sub(/\.md$/, ".html"), content)
32
32
  when ".liquid"
33
33
  template = LiquidTemplate.compile(config, source.src_path, content)
@@ -9,9 +9,8 @@ module Yass
9
9
  end
10
10
 
11
11
  def strip_index(url)
12
- path = Pathname.new(url)
13
- strip = path.basename.to_s == "index.html" && strip_index?
14
- strip ? path.dirname.to_s : path.to_s
12
+ path = strip_index? ? url.sub(%r'/?index\.html([\?#][^/]*)?$', '\1') : url
13
+ path == "" ? "." : path
15
14
  end
16
15
 
17
16
  def match(str, regex) = Regexp.new(regex).match? str
@@ -21,6 +20,8 @@ module Yass
21
20
  objects.select { |obj| regex =~ obj[field].to_s }
22
21
  end
23
22
 
23
+ def where_not(objects, field, value) = objects.reject { |obj| obj[field] == value }
24
+
24
25
  private
25
26
 
26
27
  def strip_index? = context.registers[:source].config.strip_index
@@ -1,23 +1,25 @@
1
1
  module Yass
2
2
  class LiquidTemplate
3
- def self.compile(config, name, src)
3
+ def self.compile(config, filename, src)
4
4
  template = Liquid::Template.parse(src, environment: config.liquid_env)
5
- new(name, template)
5
+ new(filename, template)
6
6
  end
7
7
 
8
- attr_reader :name
8
+ attr_reader :filename
9
9
 
10
- def initialize(name, template)
11
- @name = name
10
+ def initialize(filename, template)
11
+ @filename = filename
12
12
  @template = template
13
13
  end
14
14
 
15
+ def name = filename.sub(/\.liquid$/, "")
16
+
15
17
  def render(source)
16
18
  vars = { "page" => file_attrs(source), "files" => files_attrs(source.config.sources) }
17
19
  vars["content"] = yield if block_given?
18
20
  content = @template.render(vars, { strict_variables: true, strict_filters: true, registers: { source: source } })
19
21
  if @template.errors.any?
20
- source.config.stderr.puts "Errors found in #{name}:"
22
+ source.config.stderr.puts "Errors found in #{filename}:"
21
23
  source.config.stderr.puts @template.errors.map { |e| " #{e}" }.join("\n")
22
24
  end
23
25
  content
@@ -26,15 +28,17 @@ module Yass
26
28
  private
27
29
 
28
30
  def file_attrs(source)
29
- {
31
+ source.front_matter.merge({
30
32
  "title" => source.title,
33
+ "layout" => source.layout&.name,
31
34
  "path" => source.dest_path.to_s,
32
35
  "src_path" => source.src_path.to_s,
33
36
  "dirname" => source.dest_path.dirname.to_s,
34
37
  "filename" => source.dest_path.basename.to_s,
35
38
  "extname" => source.dest_path.basename.extname,
36
- "filesize" => File.stat(source.path).size,
37
- }
39
+ "filesize" => source.size,
40
+ "published" => source.published?,
41
+ })
38
42
  end
39
43
 
40
44
  def files_attrs(sources) = sources.map { |s| file_attrs s }
data/lib/yass/source.rb CHANGED
@@ -1,40 +1,66 @@
1
+ require 'yaml'
2
+
1
3
  module Yass
2
4
  class Source
3
5
  EXT_CONVERSIONS = {"md" => "html"}.freeze
4
- attr_reader :config, :path, :layout, :src_path, :dest_path, :outfile
6
+ YAML_HEADER = /\A---\s*\n/
7
+ FRONT_MATTER = /\A(?<matter>---\s*\n.*^---\s*\n?)(?<content>.+)?$/m
8
+
9
+ attr_reader :config, :front_matter, :path, :src_path, :dest_path, :outfile, :size
5
10
 
6
11
  def initialize(config, path)
7
12
  @config = config
8
13
  @path = path
9
14
  @src_path = path.relative_path_from config.src_dir
10
- dest_filename, @layout = parse_name
11
15
  @dest_path = src_path.dirname.join(dest_filename)
12
16
  @outfile = config.dest_dir.join(dest_path)
17
+ @size = File.stat(path).size
18
+
19
+ @front_matter, @content = parse_content
20
+ @title = front_matter.delete "title" if front_matter.key? "title"
21
+ @layout_name = front_matter.delete "layout" if front_matter.key? "layout"
22
+ end
23
+
24
+ def layout
25
+ return nil if @layout_name == false
26
+
27
+ ext = dest_path.extname
28
+ config.layout_cache["#{@layout_name}#{ext}"] || config.layout_cache["default#{ext}"]
13
29
  end
14
30
 
15
31
  def title
32
+ return @title if @title
33
+
16
34
  fname = dest_path.basename.sub(/\..+$/, "").to_s
17
35
  fname = src_path.dirname.basename.to_s if fname == "index"
18
36
  fname = "Home" if fname == "."
19
- fname.sub(/[_-]+/, " ").split(/ +/).map(&:capitalize).join(" ")
37
+ @title = fname.gsub(/[_-]+/, " ").split(/ +/).map(&:capitalize).join(" ")
20
38
  end
21
39
 
22
- def dynamic? = !!(/\.(liquid|md)(\..+)?$/ =~ path.basename.to_s || layout)
40
+ def dynamic? = !!(/\.(liquid|md)(\..+)?$/ =~ path.basename.to_s || layout || @has_front_matter)
41
+
42
+ def content = @content ||= path.read
43
+
44
+ def published? = front_matter["published"].nil? ? true : !!front_matter["published"]
23
45
 
24
46
  private
25
47
 
26
- def parse_name
48
+ def dest_filename
27
49
  name, exts = path.basename.to_s.split(".", 2)
28
- return name, nil if exts.nil?
29
-
30
- exts = exts.split(".").map { |x| EXT_CONVERSIONS[x] || x } - %w[liquid]
31
- return "#{name}.#{exts[0]}", config.layout_cache["default.#{exts[0]}"] if exts.size == 1
50
+ exts = (exts || "").split(".").map { |x| EXT_CONVERSIONS[x] || x } - %w[liquid]
51
+ [name, *exts].join(".")
52
+ end
32
53
 
33
- layout = config.layout_cache["#{exts[-2..].join(".")}"]
34
- exts.delete_at(-2) if layout
35
- layout ||= config.layout_cache["default.#{exts[-1]}"]
54
+ def parse_content
55
+ @has_front_matter = YAML_HEADER.match? path.read(10)
56
+ return {}, nil unless @has_front_matter
36
57
 
37
- return "#{name}.#{exts.join "."}", layout
58
+ @has_front_matter = true
59
+ captures = FRONT_MATTER.match(path.read).named_captures
60
+ return YAML.safe_load(captures["matter"].to_s), captures["content"].to_s
61
+ rescue Psych::SyntaxError => e
62
+ config.stderr.puts "Error parsing front matter for #{path}: #{e.message}"
63
+ return {}, ""
38
64
  end
39
65
  end
40
66
  end
data/lib/yass/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yass
2
- VERSION = "0.6.1".freeze
2
+ VERSION = "0.8.0".freeze
3
3
  end
data/lib/yass.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  require 'pathname'
2
2
  require 'filewatcher'
3
+ require 'liquid' # MUST be loaded before kramdown-parser-gfm for some reason
3
4
  require 'kramdown'
4
- require 'liquid'
5
+ require 'kramdown-parser-gfm'
5
6
 
6
7
  module Yass
7
8
  autoload :CLI, 'yass/cli'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Hollinger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-12 00:00:00.000000000 Z
11
+ date: 2025-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: filewatcher
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: kramdown-parser-gfm
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: liquid
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -69,8 +83,9 @@ files:
69
83
  - docs-src/site/assets/highlight.min.js
70
84
  - docs-src/site/assets/highlightjs-atom-one-dark.min.css
71
85
  - docs-src/site/assets/main.css.liquid
86
+ - docs-src/site/favicon.png
72
87
  - docs-src/site/helpers/index.md.liquid
73
- - docs-src/site/index.splash.md.liquid
88
+ - docs-src/site/index.md.liquid
74
89
  - docs-src/site/layouts-templates/index.md.liquid
75
90
  - docs-src/templates/asset_tags.liquid
76
91
  - docs-src/templates/nav.liquid