diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..756503ff3a6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,77 @@ +name: Continuous Integration + +on: + push: + branches: + - master + - "*-stable" + pull_request: + branches: + - master + - "*-stable" + +jobs: + ci: + name: "Run Tests (${{ matrix.label }})" + runs-on: "ubuntu-latest" + strategy: + fail-fast: false + matrix: + include: + - label: Ruby 2.5 + ruby_version: "2.5" + - label: Ruby 2.7 + ruby_version: "2.7" + - label: Ruby 3.0 + ruby_version: "3.0" + - label: Ruby 3.1 + ruby_version: "3.1" + - label: Ruby 3.2 + ruby_version: "3.2" + - label: Ruby 3.3 + ruby_version: "3.3" + - label: JRuby 9.2.20.1 + ruby_version: "jruby-9.2.20.1" + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + - name: "Set up ${{ matrix.label }}" + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: true + cache-version: 2 + - name: Run Minitest based tests + run: bash script/test + - name: Run Cucumber based tests + if: "!contains(matrix.ruby_version, 'jruby')" + run: bash script/cucumber + - name: Generate and Build a new site + run: bash script/default-site + + xtras: + name: "${{ matrix.job_name }} (Ruby ${{ matrix.ruby_version }})" + runs-on: "ubuntu-latest" + strategy: + fail-fast: false + matrix: + include: + - job_name: "Profile Docs Site" + step_name: "Build and Profile docs site" + script_file: "profile-docs" + ruby_version: "2.5" + - job_name: "Style Check" + step_name: "Run RuboCop" + script_file: "fmt" + ruby_version: "2.5" + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + - name: "Set up Ruby ${{ matrix.ruby_version }}" + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: true + cache-version: 2 + - name: ${{ matrix.step_name }} + run: bash script/${{ matrix.script_file }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000000..d181e6d0a6d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,34 @@ +name: Release Gem + +on: + push: + branches: + - master + - "*-stable" + paths: + - "lib/**/version.rb" + +jobs: + release: + if: "github.repository_owner == 'jekyll'" + name: "Release Gem (Ruby ${{ matrix.ruby_version }})" + runs-on: "ubuntu-latest" + strategy: + fail-fast: true + matrix: + ruby_version: + - 2.7 + steps: + - name: Checkout Repository + uses: actions/checkout@v2 + - name: "Set up Ruby ${{ matrix.ruby_version }}" + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby_version }} + bundler-cache: true + - name: Build and Publish Gem + uses: ashmaroli/release-gem@dist + with: + gemspec_name: jekyll + env: + GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_GEM_PUSH_API_KEY }} diff --git a/.github/workflows/third-party.yml b/.github/workflows/third-party.yml new file mode 100644 index 00000000000..eabf72a46d7 --- /dev/null +++ b/.github/workflows/third-party.yml @@ -0,0 +1,39 @@ +name: Third-Party Repository Profiling + +on: + push: + branches: + - 3.9-stable + pull_request: + branches: + - 3.9-stable +jobs: + build_n_profile: + if: "!contains(github.event.commits[0].message, '[ci skip]')" + runs-on: 'ubuntu-latest' + env: + BUNDLE_GEMFILE: "sandbox/Gemfile" + BUNDLE_PATH: "vendor/bundle" + BUNDLE_JOBS: 4 + BUNDLE_RETRY: 3 + steps: + - name: Checkout Jekyll + uses: actions/checkout@v2 + with: + fetch-depth: 5 + path: jekyll + - name: Checkout Third-Party Repository + uses: actions/checkout@v2 + with: + repository: ashmaroli/tomjoht.github.io + path: sandbox + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.7 + bundler-cache: true + - name: Run Jekyll Build 3 times + run: | + bundle exec jekyll build -s sandbox -d sandbox/_site --trace + bundle exec jekyll build -s sandbox -d sandbox/_site --trace + bundle exec jekyll build -s sandbox -d sandbox/_site --trace diff --git a/.rubocop.yml b/.rubocop.yml index ffd8bed8992..e10e55511c3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -53,6 +53,8 @@ Layout/EmptyComment: Enabled: false Layout/EndAlignment: Severity: error +Lint/SplatKeywordArguments: + Enabled: false Lint/UnreachableCode: Severity: error Lint/UselessAccessModifier: diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 25ae6f0888b..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,58 +0,0 @@ -bundler_args: --without benchmark:site:development -script: script/cibuild -cache: bundler -language: ruby -sudo: false - -rvm: - - &ruby1 2.5.1 - - &ruby2 2.4.4 - - &ruby3 2.3.7 - - &ruby4 2.2.10 - - &jruby jruby-9.1.16.0 - -matrix: - include: - - rvm: *ruby1 - env: TEST_SUITE=fmt - - rvm: *ruby1 - env: TEST_SUITE=default-site - - rvm: *ruby1 - env: ROUGE_VERSION=1.11.1 # runs everything with this version - exclude: - - rvm: *jruby - env: TEST_SUITE=cucumber - -env: - matrix: - - TEST_SUITE=test - - TEST_SUITE=cucumber -branches: - only: - - master - - themes - - /*-stable/ - -notifications: - slack: - secure: "\ - dNdKk6nahNURIUbO3ULhA09/vTEQjK0fNbgjVjeYPEvROHgQBP1cIP3AJy8aWs8rl5Yyow4Y\ - GEilNRzKPz18AsFptVXofpwyqcBxaCfmHP809NX5PHBaadydveLm+TNVao2XeLXSWu+HUNAY\ - O1AanCUbJSEyJTju347xCBGzESU=\ - " - -addons: - code_climate: - repo_token: - secure: "\ - mAuvDu+nrzB8dOaLqsublDGt423mGRyZYM3vsrXh4Tf1sT+L1PxsRzU4gLmcV27HtX2Oq9\ - DA4vsRURfABU0fIhwYkQuZqEcA3d8TL36BZcGEshG6MQ2AmnYsmFiTcxqV5bmlElHEqQuT\ - 5SUFXLafgZPBnL0qDwujQcHukID41sE=\ - " -# regular test configuration -after_success: - - bundle exec codeclimate-test-reporter - -before_install: - - gem update --system - - gem install bundler diff --git a/Gemfile b/Gemfile index af7e21902a0..ae61036074d 100644 --- a/Gemfile +++ b/Gemfile @@ -7,43 +7,50 @@ gem "rake", "~> 12.0" gem "rouge", ENV["ROUGE"] if ENV["ROUGE"] -# Dependency of jekyll-mentions. RubyGems in Ruby 2.1 doesn't shield us from this. -gem "activesupport", "~> 4.2", :groups => [:test_legacy, :site] if RUBY_VERSION < "2.2.2" - group :development do gem "launchy", "~> 2.3" gem "pry" - unless RUBY_ENGINE == "jruby" - gem "pry-byebug" - end + gem "pry-byebug" unless RUBY_ENGINE == "jruby" end # group :test do gem "codeclimate-test-reporter", "~> 1.0.5" - gem "cucumber", RUBY_VERSION >= "2.2" ? "~> 3.0" : "3.0.1" + gem "cucumber", "~> 3.0" gem "httpclient" gem "jekyll_test_plugin" gem "jekyll_test_plugin_malicious" - # nokogiri v1.8 does not work with ruby 2.1 and below - gem "nokogiri", RUBY_VERSION >= "2.2" ? "~> 1.7" : "~> 1.7.0" + gem "nokogiri", "~> 1.9" + + # Ruby 3.1.0 shipped with `psych-4.0.3` which caused some of our Cucumber-based tests to fail. + # TODO: Remove lock once we implement a way to use Psych 4 without breaking anything. + # See https://github.com/jekyll/jekyll/pull/8918 + gem "psych", "~> 3.3" + gem "rspec" gem "rspec-mocks" gem "rubocop", "~> 0.56.0" gem "test-dependency-theme", :path => File.expand_path("test/fixtures/test-dependency-theme", __dir__) gem "test-theme", :path => File.expand_path("test/fixtures/test-theme", __dir__) + gem "test-theme-skinny", :path => File.expand_path("test/fixtures/test-theme-skinny", __dir__) + gem "test-theme-symlink", :path => File.expand_path("test/fixtures/test-theme-symlink", __dir__) + + gem "webrick" if RUBY_VERSION >= "3" - gem "jruby-openssl" if RUBY_ENGINE == "jruby" + # http_parser.rb has stopped shipping jruby-compatible versions + # latest compatible one was 0.6.0 https://rubygems.org/gems/http_parser.rb + if RUBY_ENGINE == "jruby" + gem "http_parser.rb", "~> 0.6.0" + gem "jruby-openssl" + end end # group :test_legacy do - if RUBY_PLATFORM =~ %r!cygwin! || RUBY_VERSION.start_with?("2.2") - gem "test-unit" - end + gem "test-unit" if RUBY_PLATFORM =~ %r!cygwin! gem "minitest" gem "minitest-profile" @@ -66,37 +73,49 @@ end # group :jekyll_optional_dependencies do - gem "coderay", "~> 1.1.0" gem "jekyll-coffeescript" gem "jekyll-docs", :path => "../docs" if Dir.exist?("../docs") && ENV["JEKYLL_VERSION"] gem "jekyll-feed", "~> 0.9" gem "jekyll-gist" gem "jekyll-paginate" gem "jekyll-redirect-from" - gem "kramdown", "~> 1.14" + + # Add gem 'matrix' + # Ref: https://github.com/jekyll/jekyll/commit/d0eb07ba29dc7d5f52defab855bdb7a768cf824c + gem "matrix" + gem "mime-types", "~> 3.0" - gem "rdoc", RUBY_VERSION >= "2.2.2" ? "~> 6.0" : "~> 5.1" - gem "tomlrb", "~> 1.2" + gem "rdoc", "~> 6.3.0" + gem "tomlrb", "~> 2.0" + + if ENV["KRAMDOWN_VERSION"].nil? || ENV["KRAMDOWN_VERSION"].to_i >= 2 + gem "kramdown-syntax-coderay" + gem "kramdown-parser-gfm" + else + gem "coderay", "~> 1.0" + end platform :ruby, :mswin, :mingw, :x64_mingw do gem "classifier-reborn", "~> 2.2.0" - gem "liquid-c", "~> 3.0" + gem "liquid-c", "~> 4.0" gem "pygments.rb", "~> 1.0" gem "rdiscount", "~> 2.0" gem "redcarpet", "~> 3.2", ">= 3.2.3" gem "yajl-ruby", "~> 1.3.1" end - # Windows does not include zoneinfo files, so bundle the tzinfo-data gem - gem "tzinfo-data", :platforms => [:mingw, :mswin, :x64_mingw, :jruby] + # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem + # and associated library + platforms :jruby, :mswin, :mingw, :x64_mingw do + gem "tzinfo", ENV["TZINFO_VERSION"] if ENV["TZINFO_VERSION"] + gem "tzinfo-data" + end end # group :site do - if ENV["PROOF"] - gem "html-proofer", "~> 3.4" - end + gem "html-proofer", "~> 3.4" if ENV["PROOF"] gem "jekyll-avatar" gem "jekyll-mentions" diff --git a/History.markdown b/History.markdown index 7c5bdb82e44..20df3fe9075 100644 --- a/History.markdown +++ b/History.markdown @@ -1,3 +1,88 @@ +## 3.9.5 / 2024-02-12 + +### Minor Enhancements + + * 3.9-stable: allow Pages to be Excerpted (#9550) + +## 3.9.4 / 2023-12-28 + +### Bug Fixes + + * Backport #9392 for v3.9.x: Add support for Ruby 3.3 Logger (#9513) + +## 3.9.3 / 2023-01-27 + +### Bug Fixes + + * 3.9.x: Support i18n 1.x (#9269) + * Backport #8880 for v3.9.x: Support both tzinfo v1 and v2 alongwith + non-half hour offsets (#9280) + +### Development Fixes + + * v3.9.x: test under Ruby 3.2 #9272) + * v3.9.x: fix rdiscount test (#9277) + +## 3.9.2 / 2022-03-27 + +### Bug Fixes + + * Lock `http_parser.rb` gem to `v0.6.x` on JRuby (#8943) + * Backport #8756 for v3.9.x: Respect collections_dir config within include tag (#8795) + * Backport #8965 for v3.9.x: Fix response header for content served via `jekyll serve` (#8976) + +### Development Fixes + + * Update and fix CI for `3.9-stable` on Ruby 3.x (#8942) + * Fix CI for commits to `3.9-stable` branch (#8788) + +## 3.9.1 / 2021-04-08 + +### Bug Fixes + + * Backport #8618 for v3.9.x: Update include tag to be more permissive (#8629) + +## 3.9.0 / 2020-08-05 + +### Minor Enhancements + + * Allow use of kramdown v2 (#8322) + * Add default language for kramdown syntax highlighting (#8325) + +## 3.8.7 / 2020-05-08 + +### Bug Fixes + + * Prevent console warnings with Ruby 2.7 (#8125) + +## 3.8.6 / 2019-07-02 + +### Bug Fixes + + * Update log output for an invalid theme directory (#7734) + * Memoize `SiteDrop#documents` to reduce allocations (#7722) + * Excerpt handling of custom and intermediate tags (#7467) + * Escape valid special chars in a site's path name (#7573) + * Revert memoizing `Site#docs_to_write` and refactor `#documents` (#7689) + * Fix broken `include_relative` usage in excerpt (#7690) + * Install platform-specific gems as required (3c06609406) + +### Security Fixes + + * Theme gems: ensure directories aren't symlinks (#7424) + +## 3.8.5 / 2018-11-04 + +### Bug Fixes + + * Re-implement handling Liquid blocks in excerpts (#7250) + +## 3.8.4 / 2018-09-18 + +### Bug Fixes + + * security: fix `include` bypass of `EntryFilter#filter` symlink check (#7228) + ## 3.8.3 / 2018-06-05 ### Bug Fixes diff --git a/appveyor.yml b/appveyor.yml index 480c7fb9cd1..d4ed170bf73 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,30 +6,37 @@ branches: only: - master - themes + - /.*-stable/ build: off install: - - SET PATH=C:\Ruby%RUBY_FOLDER_VER%\bin;%PATH% + - SET PATH=C:\Ruby%RUBY_FOLDER_VER%-x64\bin;%PATH% - bundle install --retry 5 --jobs=%NUMBER_OF_PROCESSORS% --clean --path vendor\bundle environment: - BUNDLE_WITHOUT: "benchmark:site:development" + BUNDLE_WITHOUT: "benchmark:development" matrix: - - RUBY_FOLDER_VER: "25" - TEST_SUITE: "test" - - RUBY_FOLDER_VER: "25" - TEST_SUITE: "cucumber" - - RUBY_FOLDER_VER: "25" - TEST_SUITE: "default-site" - - RUBY_FOLDER_VER: "25-x64" + - RUBY_FOLDER_VER: "26" + TZINFO_VERSION: "~> 1.2" TEST_SUITE: "test" - - RUBY_FOLDER_VER: "24" + - RUBY_FOLDER_VER: "26" + TZINFO_VERSION: "~> 2.0" TEST_SUITE: "test" - - RUBY_FOLDER_VER: "23" + - RUBY_FOLDER_VER: "26" TEST_SUITE: "test" - - RUBY_FOLDER_VER: "22" + - RUBY_FOLDER_VER: "25" TEST_SUITE: "test" + - RUBY_FOLDER_VER: "26" + TEST_SUITE: "default-site" + - RUBY_FOLDER_VER: "26" + TEST_SUITE: "profile-docs" + - RUBY_FOLDER_VER: "26" + TZINFO_VERSION: "~> 1.2" + TEST_SUITE: "cucumber" + - RUBY_FOLDER_VER: "26" + TZINFO_VERSION: "~> 2.0" + TEST_SUITE: "cucumber" test_script: - ruby --version diff --git a/docs/_config.yml b/docs/_config.yml index 27ad51ffc8d..9a5bd3274a4 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,5 +1,5 @@ --- -version: 3.8.3 +version: 3.9.4 name: Jekyll • Simple, blog-aware, static sites description: Transform your plain text into static websites and blogs url: https://jekyllrb.com diff --git a/docs/_docs/history.md b/docs/_docs/history.md index 1e6c14d8716..131c5ab430b 100644 --- a/docs/_docs/history.md +++ b/docs/_docs/history.md @@ -4,6 +4,124 @@ permalink: "/docs/history/" note: This file is autogenerated. Edit /History.markdown instead. --- +## 3.9.5 / 2024-02-12 +{: #v3-9-5} + +### Minor Enhancements +{: #minor-enhancements-v3-9-5} + +- 3.9-stable: allow Pages to be Excerpted ([#9550]({{ site.repository }}/issues/9550)) + + +## 3.9.4 / 2023-12-28 +{: #v3-9-4} + +### Bug Fixes +{: #bug-fixes-v3-9-4} + +- Backport [#9392]({{ site.repository }}/issues/9392) for v3.9.x: Add support for Ruby 3.3 Logger ([#9513]({{ site.repository }}/issues/9513)) + + +## 3.9.3 / 2023-01-27 +{: #v3-9-3} + +### Bug Fixes +{: #bug-fixes-v3-9-3} + +- 3.9.x: Support i18n 1.x ([#9269]({{ site.repository }}/issues/9269)) +- Backport [#8880]({{ site.repository }}/issues/8880) for v3.9.x: Support both tzinfo v1 and v2 alongwith + non-half hour offsets ([#9280]({{ site.repository }}/issues/9280)) + +### Development Fixes +{: #development-fixes-v3-9-3} + +- v3.9.x: test under Ruby 3.2 [#9272]({{ site.repository }}/issues/9272)) +- v3.9.x: fix rdiscount test ([#9277]({{ site.repository }}/issues/9277)) + + +## 3.9.2 / 2022-03-27 +{: #v3-9-2} + +### Bug Fixes +{: #bug-fixes-v3-9-2} + +- Lock `http_parser.rb` gem to `v0.6.x` on JRuby ([#8943]({{ site.repository }}/issues/8943)) +- Backport [#8756]({{ site.repository }}/issues/8756) for v3.9.x: Respect collections_dir config within include tag ([#8795]({{ site.repository }}/issues/8795)) +- Backport [#8965]({{ site.repository }}/issues/8965) for v3.9.x: Fix response header for content served via `jekyll serve` ([#8976]({{ site.repository }}/issues/8976)) + +### Development Fixes +{: #development-fixes-v3-9-2} + +- Update and fix CI for `3.9-stable` on Ruby 3.x ([#8942]({{ site.repository }}/issues/8942)) +- Fix CI for commits to `3.9-stable` branch ([#8788]({{ site.repository }}/issues/8788)) + + +## 3.9.1 / 2021-04-08 +{: #v3-9-1} + +### Bug Fixes +{: #bug-fixes-v3-9-1} + +- Backport [#8618]({{ site.repository }}/issues/8618) for v3.9.x: Update include tag to be more permissive ([#8629]({{ site.repository }}/issues/8629)) + + +## 3.9.0 / 2020-08-05 +{: #v3-9-0} + +### Minor Enhancements +{: #minor-enhancements-v3-9-0} + +- Allow use of kramdown v2 ([#8322]({{ site.repository }}/issues/8322)) +- Add default language for kramdown syntax highlighting ([#8325]({{ site.repository }}/issues/8325)) + + +## 3.8.7 / 2020-05-08 +{: #v3-8-7} + +### Bug Fixes +{: #bug-fixes-v3-8-7} + +- Prevent console warnings with Ruby 2.7 ([#8125]({{ site.repository }}/issues/8125)) + + +## 3.8.6 / 2019-07-02 +{: #v3-8-6} + +### Bug Fixes +{: #bug-fixes-v3-8-6} + +- Update log output for an invalid theme directory ([#7734]({{ site.repository }}/issues/7734)) +- Memoize `SiteDrop#documents` to reduce allocations ([#7722]({{ site.repository }}/issues/7722)) +- Excerpt handling of custom and intermediate tags ([#7467]({{ site.repository }}/issues/7467)) +- Escape valid special chars in a site's path name ([#7573]({{ site.repository }}/issues/7573)) +- Revert memoizing `Site#docs_to_write` and refactor `#documents` ([#7689]({{ site.repository }}/issues/7689)) +- Fix broken `include_relative` usage in excerpt ([#7690]({{ site.repository }}/issues/7690)) +- Install platform-specific gems as required (3c06609406) + +### Security Fixes +{: #security-fixes-v3-8-6} + +- Theme gems: ensure directories aren't symlinks ([#7424]({{ site.repository }}/issues/7424)) + + +## 3.8.5 / 2018-11-04 +{: #v3-8-5} + +### Bug Fixes +{: #bug-fixes-v3-8-5} + +- Re-implement handling Liquid blocks in excerpts ([#7250]({{ site.repository }}/issues/7250)) + + +## 3.8.4 / 2018-09-18 +{: #v3-8-4} + +### Bug Fixes +{: #bug-fixes-v3-8-4} + +- security: fix `include` bypass of `EntryFilter#filter` symlink check ([#7228]({{ site.repository }}/issues/7228)) + + ## 3.8.3 / 2018-06-05 {: #v3-8-3} diff --git a/docs/_docs/windows.md b/docs/_docs/windows.md index b81c65c66d9..0559d4dd71b 100644 --- a/docs/_docs/windows.md +++ b/docs/_docs/windows.md @@ -198,8 +198,12 @@ Jekyll now uses a rubygem to internally configure Timezone based on established While 'new' blogs created with Jekyll v3.4 and greater, will have the following added to their 'Gemfile' by default, existing sites *will* have to update their 'Gemfile' (and installed) to enable development on Windows: ```ruby -# Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] +# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem +# and associated library. +platforms :mingw, :x64_mingw, :mswin, :jruby do + gem "tzinfo", ">= 1", "< 3" + gem "tzinfo-data" +end ``` [IANA-database]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones diff --git a/docs/_posts/2019-07-02-jekyll-3-8-6-released.markdown b/docs/_posts/2019-07-02-jekyll-3-8-6-released.markdown new file mode 100644 index 00000000000..f05cd7cd981 --- /dev/null +++ b/docs/_posts/2019-07-02-jekyll-3-8-6-released.markdown @@ -0,0 +1,19 @@ +--- +title: 'Jekyll 3.8.6 Released' +date: 2019-07-02 11:21:02 -0400 +author: parkr +version: 3.8.6 +categories: [release] +--- + +We have another patch release in the 3.8 series! This time, we have one security patch +and a handful of bug patches, including: + +- Filter symlinks from theme gems +- Fix excerpt handling of some Liquid tags +- Handle case where a theme directory doesn't exist +- A few internal optimizations to reduce memory overhead + +... and a few more! You can check out the patches and see all the details in [the release notes](/docs/history/#v3-8-6) + +Happy Jekylling! diff --git a/docs/_posts/2020-08-06-jekyll-3-9-0-released.markdown b/docs/_posts/2020-08-06-jekyll-3-9-0-released.markdown new file mode 100644 index 00000000000..f2e79e3cad2 --- /dev/null +++ b/docs/_posts/2020-08-06-jekyll-3-9-0-released.markdown @@ -0,0 +1,28 @@ +--- +title: 'Jekyll 3.9.0 Released' +author: parkr +version: 3.9.0 +categories: [release] +--- + +Jekyll 3.9.0 allows use of kramdown v2, the latest series of kramdown. + +If you choose to upgrade, please note that the GitHub-Flavored Markdown +parser and other features of kramdown v1 are now distributed via +separate gems. If you would like to continue using these features, you will +need to add the gems to your `Gemfile`. They are as follows: + +- GFM parser – `kramdown-parser-gfm` +- coderay syntax highlighter – `kramdown-syntax-coderay` +- mathjaxnode math engine – `kramdown-math-mathjaxnode` +- sskatex math engine – `kramdown-math-sskatex` +- katex math engine – `kramdown-math-katex` +- ritex math engine – `kramdown-math-ritex` +- itex2mml math engine – `kramdown-math-itex2mml` + +Jekyll will require the given gem when the configuration requires it, and +will show a helpful message when a dependency is missing. + +You can check out the patches and see all the details in [the release notes](/docs/history/#v3-9-0) + +Happy Jekylling! diff --git a/docs/_posts/2021-04-07-jekyll-3-9-1-released.markdown b/docs/_posts/2021-04-07-jekyll-3-9-1-released.markdown new file mode 100644 index 00000000000..882dd318b32 --- /dev/null +++ b/docs/_posts/2021-04-07-jekyll-3-9-1-released.markdown @@ -0,0 +1,28 @@ +--- +title: 'Jekyll 3.9.1 Released' +date: 2021-04-07 15:59:45 -0400 +author: parkr +version: 3.9.1 +categories: [release] +--- + +This patch release of the 3.9 series is released to fix a bug where the +`include` tag does not allow valid filename characters. For example, this +would previously fail: + +{% raw %} +```text +{% include my-logo@2x.svg %} +``` +{% endraw %} + +This release adds support for the following characters in filenames: + +- `@` +- `-` +- `(` and `)` +- `+` +- `~` +- `#` + +Happy Jekylling! diff --git a/docs/_posts/2022-03-27-jekyll-3-9-2-released.markdown b/docs/_posts/2022-03-27-jekyll-3-9-2-released.markdown new file mode 100644 index 00000000000..5ea445dbb5f --- /dev/null +++ b/docs/_posts/2022-03-27-jekyll-3-9-2-released.markdown @@ -0,0 +1,19 @@ +--- +title: 'Jekyll 3.9.2 Released' +date: 2022-03-27 13:20:00 -0700 +author: parkr +version: 3.9.2 +categories: [release] +--- + +Hey Jekyllers, + +Quick bug-fix release for you all today: + +1. Ruby 3.0 and 3.1 support :tada: (you will need to run `bundle add webrick` for `jekyll serve` to work) +2. `jekyll serve` will no longer inject a charset into the MIME type for +binary types +3. Incremental regeneration now handles includes in collection files + correctly + +That's all, Happy Jekylling! diff --git a/docs/_posts/2023-01-27-jekyll-3-9-3-released.markdown b/docs/_posts/2023-01-27-jekyll-3-9-3-released.markdown new file mode 100644 index 00000000000..d5c8aac2e49 --- /dev/null +++ b/docs/_posts/2023-01-27-jekyll-3-9-3-released.markdown @@ -0,0 +1,15 @@ +--- +title: 'Jekyll 3.9.3 Released' +date: 2023-01-27 13:10:25 -0800 +author: parkr +version: 3.9.3 +categories: [release] +--- + +Jekyll 3.9.3 is a bug fix release loosening version restrictions for +dependencies `i18n` and `tzinfo` gems. You can now use Jekyll v3.9 with +newer versions of these gems! + +More details in [the full release notes]({% link _docs/history.md %}#v3-9-3). + +Happy Jekylling! diff --git a/docs/_posts/2023-12-28-jekyll-3-9-4-released.markdown b/docs/_posts/2023-12-28-jekyll-3-9-4-released.markdown new file mode 100644 index 00000000000..544dd99a711 --- /dev/null +++ b/docs/_posts/2023-12-28-jekyll-3-9-4-released.markdown @@ -0,0 +1,14 @@ +--- +title: 'Jekyll 3.9.4 Released' +date: 2023-12-28 14:45:05 -0800 +author: parkr +version: 3.9.4 +categories: [release] +--- + +Hey Jekyllers! + +This release, 3.9.4, is to bring Ruby 3.3 support to Jekyll. You can find +the details in [the changelog]({% link _docs/history.md %}#v3-9-4). + +Happy Jekylling! diff --git a/docs/_posts/2024-02-12-jekyll-3-9-5-released.markdown b/docs/_posts/2024-02-12-jekyll-3-9-5-released.markdown new file mode 100644 index 00000000000..2f52d1f1d6f --- /dev/null +++ b/docs/_posts/2024-02-12-jekyll-3-9-5-released.markdown @@ -0,0 +1,12 @@ +--- +title: 'Jekyll 3.9.5 Released' +date: 2024-02-12 20:24:21 -0800 +author: parkr +version: 3.9.5 +categories: [release] +--- + +This release allows `Jekyll::Page` objects to interact with +`Jekyll::Excerpt`. Previously, excerpts could only be generated for +documents (e.g. collection items like posts), so this brings Page objects +to parity. diff --git a/docs/latest_version.txt b/docs/latest_version.txt index 269aa9c86de..e0d61b5b062 100644 --- a/docs/latest_version.txt +++ b/docs/latest_version.txt @@ -1 +1 @@ -3.8.3 +3.9.4 diff --git a/features/collections.feature b/features/collections.feature index 03f10dc1e6f..6b3939444e6 100644 --- a/features/collections.feature +++ b/features/collections.feature @@ -386,7 +386,23 @@ Feature: Collections When I run jekyll build Then I should get a zero exit status Then the _site directory should exist - And I should see "Second document's output:

Use Jekyll.configuration to build a full configuration for use w/Jekyll.

\n\n

Whatever: foo.bar

" in "_site/index.html" + And I should see "Second document's output:

Use Jekyll.configuration to build a full configuration for use w/Jekyll.

\n\n

Whatever: foo.bar

" in "_site/index.html" + + Scenario: Documents have an output attribute, which is the converted HTML based on site.config + Given I have an "index.html" page that contains "Second document's output: {{ site.documents[2].output }}" + And I have fixture collections + And I have a "_config.yml" file with content: + """ + kramdown: + guess_lang: false + collections: + - methods + """ + And I'm using kramdown v2 + When I run jekyll build + Then I should get a zero exit status + Then the _site directory should exist + And I should see "Second document's output:

Use Jekyll.configuration to build a full configuration for use w/Jekyll.

\n\n

Whatever: foo.bar

" in "_site/index.html" Scenario: Filter documents by where Given I have an "index.html" page that contains "{% assign items = site.methods | where: 'whatever','foo.bar' %}Item count: {{ items.size }}" diff --git a/features/create_sites.feature b/features/create_sites.feature index c1f759316a7..7352e5eefa6 100644 --- a/features/create_sites.feature +++ b/features/create_sites.feature @@ -175,17 +175,17 @@ Feature: Create sites Given I have a _posts directory And I have the following post: | title | date | layout | content | - | entry1 | 2020-12-31 | post | content for entry1. | + | entry1 | 2040-12-31 | post | content for entry1. | | entry2 | 2007-12-31 | post | content for entry2. | When I run jekyll build Then I should get a zero exit status And the _site directory should exist And I should see "content for entry2" in "_site/2007/12/31/entry2.html" - And the "_site/2020/12/31/entry1.html" file should not exist + And the "_site/2040/12/31/entry1.html" file should not exist When I run jekyll build --future Then I should get a zero exit status And the _site directory should exist - And the "_site/2020/12/31/entry1.html" file should exist + And the "_site/2040/12/31/entry1.html" file should exist Scenario: Basic site with layouts, posts and related posts Given I have a _layouts directory diff --git a/features/include_relative_tag.feature b/features/include_relative_tag.feature new file mode 100644 index 00000000000..9cbdcf122e7 --- /dev/null +++ b/features/include_relative_tag.feature @@ -0,0 +1,60 @@ +Feature: include_relative Tag + In order to share content across several closely related pages + As a hacker who likes to blog + I want to be able to include snippets in my site's pages and documents relative to current file + + Scenario: Include a file relative to a post + Given I have a _posts directory + And I have a _posts/snippets directory + And I have the following post: + | title | date | content | + | Star Wars | 2018-09-02 | {% include_relative snippets/welcome_para.md %} | + And I have an "_posts/snippets/welcome_para.md" file that contains "Welcome back Dear Reader!" + When I run jekyll build + Then I should get a zero exit status + And the _site directory should exist + And I should see "Welcome back Dear Reader!" in "_site/2018/09/02/star-wars.html" + + Scenario: Include a nested file relative to a post + Given I have a _posts directory + And I have a _posts/snippets directory + And I have a _posts/snippets/welcome_para directory + And I have the following post: + | title | date | content | + | Star Wars | 2018-09-02 | {% include_relative snippets/welcome_para.md %} | + And I have an "_posts/snippets/welcome_para.md" file that contains "{% include_relative snippets/welcome_para/greeting.md %} Dear Reader!" + And I have an "_posts/snippets/welcome_para/greeting.md" file that contains "Welcome back" + When I run jekyll build + Then I should get a zero exit status + And the _site directory should exist + And I should see "Welcome back Dear Reader!" in "_site/2018/09/02/star-wars.html" + + Scenario: Include a nested file relative to a post as an excerpt + Given I have a _posts directory + And I have a _posts/snippets directory + And I have a _posts/snippets/welcome_para directory + And I have a "_posts/2018-09-02-star-wars.md" file with content: + """ + {% include_relative snippets/welcome_para.md %} + + Hello World + """ + And I have an "_posts/snippets/welcome_para.md" file that contains "{% include_relative snippets/welcome_para/greeting.md %} Dear Reader!" + And I have an "_posts/snippets/welcome_para/greeting.md" file that contains "Welcome back" + And I have an "index.md" page that contains "{% for post in site.posts %}{{ post.excerpt }}{% endfor %}" + When I run jekyll build + Then I should get a zero exit status + And the _site directory should exist + And I should see "Welcome back Dear Reader!" in "_site/2018/09/02/star-wars.html" + And I should see "Welcome back Dear Reader!" in "_site/index.html" + + Scenario: Include a nested file relative to a page at root + Given I have a snippets directory + And I have a snippets/welcome_para directory + And I have a "index.md" page that contains "{% include_relative snippets/welcome_para.md %}" + And I have a "snippets/welcome_para.md" file that contains "{% include_relative snippets/welcome_para/greeting.md %} Dear Reader!" + And I have a "snippets/welcome_para/greeting.md" file that contains "Welcome back" + When I run jekyll build + Then I should get a zero exit status + And the _site directory should exist + And I should see "Welcome back Dear Reader!" in "_site/index.html" diff --git a/features/incremental_rebuild.feature b/features/incremental_rebuild.feature index 2ced57a6d81..2d22d2e1940 100644 --- a/features/incremental_rebuild.feature +++ b/features/incremental_rebuild.feature @@ -67,6 +67,25 @@ Feature: Incremental rebuild And the _site directory should exist And I should see "Basic Site with include tag: Regenerated by Jekyll" in "_site/index.html" + Scenario: Rebuild when a dependency of document in custom collection_dir is changed + Given I have a _includes directory + And I have a configuration file with "collections_dir" set to "collections" + And I have a collections/_posts directory + And I have the following post within the "collections" directory: + | title | date | layout | content | + | Wargames | 2009-03-27 | default | Basic Site with include tag: {% include about.html %} | + And I have an "_includes/about.html" file that contains "Generated by Jekyll" + When I run jekyll build -I + Then I should get a zero exit status + And the _site directory should exist + And I should see "Basic Site with include tag: Generated by Jekyll" in "_site/2009/03/27/wargames.html" + When I wait 1 second + Then I have an "_includes/about.html" file that contains "Regenerated by Jekyll" + When I run jekyll build -I + Then I should get a zero exit status + And the _site directory should exist + And I should see "Basic Site with include tag: Regenerated by Jekyll" in "_site/2009/03/27/wargames.html" + Scenario: A themed-site and incremental regeneration Given I have a configuration file with "theme" set to "test-theme" And I have an "index.md" page that contains "Themed site" diff --git a/features/rendering.feature b/features/rendering.feature index 4c4e28f6cf5..0b42d44ba27 100644 --- a/features/rendering.feature +++ b/features/rendering.feature @@ -5,6 +5,19 @@ Feature: Rendering But I want to make it as simply as possible So render with Liquid and place in Layouts + Scenario: Rendering a site with parentheses in its path name + Given I have a blank site in "omega(beta)" + And I have an "omega(beta)/test.md" page with layout "simple" that contains "Hello World" + And I have an omega(beta)/_includes directory + And I have an "omega(beta)/_includes/head.html" file that contains "Snippet" + And I have a configuration file with "source" set to "omega(beta)" + And I have an omega(beta)/_layouts directory + And I have an "omega(beta)/_layouts/simple.html" file that contains "{% include head.html %}: {{ content }}" + When I run jekyll build --profile + Then I should get a zero exit status + And I should see "Snippet:

Hello World

" in "_site/test.html" + And I should see "_layouts/simple.html" in the build output + Scenario: When receiving bad Liquid Given I have a "index.html" page with layout "simple" that contains "{% include invalid.html %}" And I have a simple layout that contains "{{ content }}" diff --git a/features/site_configuration.feature b/features/site_configuration.feature index 6dc6f5b09fa..362bc0dab3e 100644 --- a/features/site_configuration.feature +++ b/features/site_configuration.feature @@ -203,6 +203,28 @@ Feature: Site configuration And I should see "Post Layout:

content for entry1.

\n built at 2013-04-09T09:22:00-10:00" in "_site/2013/04/09/entry1.html" And I should see "Post Layout:

content for entry2.

\n built at 2013-04-09T13:14:00-10:00" in "_site/2013/04/09/entry2.html" + Scenario: Generate proper dates with explicitly set timezone (using non-half hour offset ) + Given I have a _layouts directory + And I have a page layout that contains "Page Layout: {{ site.posts.size }}" + And I have a post layout that contains "Post Layout: {{ content }} built at {{ page.date | date_to_xmlschema }}" + And I have an "index.html" page with layout "page" that contains "site index page" + And I have a configuration file with: + | key | value | + | timezone | Australia/Eucla | + And I have a _posts directory + And I have the following posts: + | title | date | layout | content | + | entry1 | 2013-04-09 23:22 +0400 | post | content for entry1. | + | entry2 | 2013-04-10 03:14 +0400 | post | content for entry2. | + When I run jekyll build + Then I should get a zero exit status + And the _site directory should exist + And I should see "Page Layout: 2" in "_site/index.html" + And the "_site/2013/04/10/entry1.html" file should exist + And the "_site/2013/04/10/entry2.html" file should exist + And I should see "Post Layout:

content for entry1.

\n built at 2013-04-10T04:07:00\+08:45" in "_site/2013/04/10/entry1.html" + And I should see "Post Layout:

content for entry2.

\n built at 2013-04-10T07:59:00\+08:45" in "_site/2013/04/10/entry2.html" + Scenario: Limit the number of posts generated by most recent date Given I have a _posts directory And I have a configuration file with: diff --git a/features/step_definitions.rb b/features/step_definitions.rb index fd05c68f406..0913a271c67 100644 --- a/features/step_definitions.rb +++ b/features/step_definitions.rb @@ -185,6 +185,12 @@ # +Given("I'm using kramdown v{int}") do |int| + skip_this_scenario unless Kramdown::VERSION.to_i == int.to_i +end + +# + Given(%r!^I wait (\d+) second(s?)$!) do |time, _| sleep(time.to_f) end diff --git a/features/theme.feature b/features/theme.feature index 650c167577e..3941abc8d86 100644 --- a/features/theme.feature +++ b/features/theme.feature @@ -57,6 +57,17 @@ Feature: Writing themes And I should see "From your site." in "_site/assets/application.coffee" And I should see "From your site." in "_site/assets/base.js" + Scenario: A theme with *just* layouts + Given I have a configuration file with "theme" set to "test-theme-skinny" + And I have an "index.html" page with layout "home" that contains "The quick brown fox." + When I run jekyll build + Then I should get a zero exit status + And the _site directory should exist + And I should see "Message: The quick brown fox." in "_site/index.html" + But I should not see "_includes" in the build output + And I should not see "_sass" in the build output + And I should not see "assets" in the build output + Scenario: Requiring dependencies of a theme Given I have a configuration file with "theme" set to "test-dependency-theme" When I run jekyll build diff --git a/jekyll.gemspec b/jekyll.gemspec index e00cdb001ab..9a226e2160a 100644 --- a/jekyll.gemspec +++ b/jekyll.gemspec @@ -33,14 +33,18 @@ Gem::Specification.new do |s| s.add_runtime_dependency("addressable", "~> 2.4") s.add_runtime_dependency("colorator", "~> 1.0") s.add_runtime_dependency("em-websocket", "~> 0.5") - s.add_runtime_dependency("i18n", "~> 0.7") + s.add_runtime_dependency("i18n", ">= 0.7", "< 2") s.add_runtime_dependency("jekyll-sass-converter", "~> 1.0") s.add_runtime_dependency("jekyll-watch", "~> 2.0") - s.add_runtime_dependency("kramdown", "~> 1.14") s.add_runtime_dependency("liquid", "~> 4.0") s.add_runtime_dependency("mercenary", "~> 0.3.3") s.add_runtime_dependency("pathutil", "~> 0.9") rouge_versions = ENV["ROUGE_VERSION"] ? ["~> #{ENV["ROUGE_VERSION"]}"] : [">= 1.7", "< 4"] s.add_runtime_dependency("rouge", *rouge_versions) s.add_runtime_dependency("safe_yaml", "~> 1.0") + + # Depend on kramdown. For kramdown v2, extra gems are required. + # https://kramdown.gettalong.org/news.html#kramdown-200-released + kramdown_versions = ENV["KRAMDOWN_VERSION"] ? ["~> #{ENV["KRAMDOWN_VERSION"]}"] : [">= 1.17", "< 3"] + s.add_runtime_dependency("kramdown", *kramdown_versions) end diff --git a/lib/jekyll/commands/new.rb b/lib/jekyll/commands/new.rb index b123015641e..97549b16d53 100644 --- a/lib/jekyll/commands/new.rb +++ b/lib/jekyll/commands/new.rb @@ -87,12 +87,23 @@ def gemfile_contents gem "jekyll-feed", "~> 0.6" end -# Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] +# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem +# and associated library. +platforms :mingw, :x64_mingw, :mswin, :jruby do + gem "tzinfo", ">= 1", "< 3" + gem "tzinfo-data" +end # Performance-booster for watching directories on Windows -gem "wdm", "~> 0.1.0" if Gem.win_platform? +gem "wdm", "~> 0.1.0", :install_if => Gem.win_platform? + +# kramdown v2 ships without the gfm parser by default. If you're using +# kramdown v1, comment out this line. +gem "kramdown-parser-gfm" +# Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem +# do not have a Java counterpart. +gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] RUBY end diff --git a/lib/jekyll/commands/serve.rb b/lib/jekyll/commands/serve.rb index 7efeb72d496..bffa648edd1 100644 --- a/lib/jekyll/commands/serve.rb +++ b/lib/jekyll/commands/serve.rb @@ -202,6 +202,7 @@ def webrick_opts(opts) :JekyllOptions => opts, :DoNotReverseLookup => true, :MimeTypes => mime_types, + :MimeTypesCharset => mime_types_charset, :DocumentRoot => opts["destination"], :StartCallback => start_callback(opts["detach"]), :StopCallback => stop_callback(opts["detach"]), @@ -379,6 +380,11 @@ def mime_types end private + + def mime_types_charset + SafeYAML.load_file(File.expand_path("serve/mime_types_charset.json", __dir__)) + end + def read_file(source_dir, file_path) File.read(Jekyll.sanitized_path(source_dir, file_path)) end diff --git a/lib/jekyll/commands/serve/mime_types_charset.json b/lib/jekyll/commands/serve/mime_types_charset.json new file mode 100644 index 00000000000..017469b9ccd --- /dev/null +++ b/lib/jekyll/commands/serve/mime_types_charset.json @@ -0,0 +1,71 @@ +{ + "application/javascript": "UTF-8", + "application/json": "UTF-8", + "application/manifest+json": "UTF-8", + "application/vnd.syncml+xml": "UTF-8", + "application/vnd.syncml.dm+wbxml": "UTF-8", + "application/vnd.syncml.dm+xml": "UTF-8", + "application/vnd.syncml.dmddf+xml": "UTF-8", + "application/vnd.wap.wbxml": "UTF-8", + "text/cache-manifest": "UTF-8", + "text/calendar": "UTF-8", + "text/coffeescript": "UTF-8", + "text/css": "UTF-8", + "text/csv": "UTF-8", + "text/html": "UTF-8", + "text/jade": "UTF-8", + "text/jsx": "UTF-8", + "text/less": "UTF-8", + "text/markdown": "UTF-8", + "text/mathml": "UTF-8", + "text/mdx": "UTF-8", + "text/n3": "UTF-8", + "text/plain": "UTF-8", + "text/prs.lines.tag": "UTF-8", + "text/richtext": "UTF-8", + "text/sgml": "UTF-8", + "text/shex": "UTF-8", + "text/slim": "UTF-8", + "text/spdx": "UTF-8", + "text/stylus": "UTF-8", + "text/tab-separated-values": "UTF-8", + "text/troff": "UTF-8", + "text/turtle": "UTF-8", + "text/uri-list": "UTF-8", + "text/vcard": "UTF-8", + "text/vnd.curl": "UTF-8", + "text/vnd.curl.dcurl": "UTF-8", + "text/vnd.curl.mcurl": "UTF-8", + "text/vnd.curl.scurl": "UTF-8", + "text/vnd.familysearch.gedcom": "UTF-8", + "text/vnd.fly": "UTF-8", + "text/vnd.fmi.flexstor": "UTF-8", + "text/vnd.graphviz": "UTF-8", + "text/vnd.in3d.3dml": "UTF-8", + "text/vnd.in3d.spot": "UTF-8", + "text/vnd.sun.j2me.app-descriptor": "UTF-8", + "text/vnd.wap.wml": "UTF-8", + "text/vnd.wap.wmlscript": "UTF-8", + "text/vtt": "UTF-8", + "text/x-asm": "UTF-8", + "text/x-c": "UTF-8", + "text/x-component": "UTF-8", + "text/x-fortran": "UTF-8", + "text/x-handlebars-template": "UTF-8", + "text/x-java-source": "UTF-8", + "text/x-lua": "UTF-8", + "text/x-markdown": "UTF-8", + "text/x-nfo": "UTF-8", + "text/x-opml": "UTF-8", + "text/x-pascal": "UTF-8", + "text/x-processing": "UTF-8", + "text/x-sass": "UTF-8", + "text/x-scss": "UTF-8", + "text/x-setext": "UTF-8", + "text/x-sfv": "UTF-8", + "text/x-suse-ymp": "UTF-8", + "text/x-uuencode": "UTF-8", + "text/x-vcalendar": "UTF-8", + "text/x-vcard": "UTF-8", + "text/yaml": "UTF-8" +} diff --git a/lib/jekyll/commands/serve/servlet.rb b/lib/jekyll/commands/serve/servlet.rb index 567ec313cbe..f3fcf339c1c 100644 --- a/lib/jekyll/commands/serve/servlet.rb +++ b/lib/jekyll/commands/serve/servlet.rb @@ -137,6 +137,7 @@ class Servlet < WEBrick::HTTPServlet::FileHandler def initialize(server, root, callbacks) # So we can access them easily. @jekyll_opts = server.config[:JekyllOptions] + @mime_types_charset = server.config[:MimeTypesCharset] set_defaults super end @@ -172,27 +173,28 @@ def do_GET(req, res) end end - validate_and_ensure_charset(req, res) + conditionally_inject_charset(res) res.header.merge!(@headers) rtn end # rubocop:enable Naming/MethodName - # - private - def validate_and_ensure_charset(_req, res) - key = res.header.keys.grep(%r!content-type!i).first - typ = res.header[key] - unless typ =~ %r!;\s*charset=! - res.header[key] = "#{typ}; charset=#{@jekyll_opts["encoding"]}" - end + # + # Inject charset based on Jekyll config only if our mime-types database contains + # the charset metadata. + # + # Refer `script/vendor-mimes` in the repository for further details. + def conditionally_inject_charset(res) + typ = res.header["content-type"] + return unless @mime_types_charset.key?(typ) + return if %r!;\s*charset=!.match?(typ) + + res.header["content-type"] = "#{typ}; charset=#{@jekyll_opts["encoding"]}" end # - - private def set_defaults hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {}) DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash| diff --git a/lib/jekyll/configuration.rb b/lib/jekyll/configuration.rb index f64264c9362..27c6f5cd34f 100644 --- a/lib/jekyll/configuration.rb +++ b/lib/jekyll/configuration.rb @@ -81,6 +81,7 @@ class Configuration < Hash "smart_quotes" => "lsquo,rsquo,ldquo,rdquo", "input" => "GFM", "hard_wrap" => false, + "guess_lang" => true, "footnote_nr" => 1, "show_warnings" => false, }, diff --git a/lib/jekyll/converters/markdown/kramdown_parser.rb b/lib/jekyll/converters/markdown/kramdown_parser.rb index b7caab551d4..6ed3d7178ad 100644 --- a/lib/jekyll/converters/markdown/kramdown_parser.rb +++ b/lib/jekyll/converters/markdown/kramdown_parser.rb @@ -18,6 +18,7 @@ def initialize(config) @config = config["kramdown"] || {} @highlighter = nil setup + load_dependencies end # Setup and normalize the configuration: @@ -30,6 +31,8 @@ def initialize(config) def setup @config["syntax_highlighter"] ||= highlighter @config["syntax_highlighter_opts"] ||= {} + @config["syntax_highlighter_opts"]["default_lang"] ||= "plaintext" + @config["syntax_highlighter_opts"]["guess_lang"] = @config["guess_lang"] @config["coderay"] ||= {} # XXX: Legacy. modernize_coderay_config make_accessible @@ -47,6 +50,24 @@ def convert(content) end private + + def load_dependencies + return if Kramdown::VERSION.to_i < 2 + if @config["input"] == "GFM" + Jekyll::External.require_with_graceful_fail("kramdown-parser-gfm") + end + + if highlighter == "coderay" + Jekyll::External.require_with_graceful_fail("kramdown-syntax-coderay") + end + + # `mathjax` emgine is bundled within kramdown-2.x and will be handled by + # kramdown itself. + if (math_engine = @config["math_engine"]) && math_engine != "mathjax" + Jekyll::External.require_with_graceful_fail("kramdown-math-#{math_engine}") + end + end + def make_accessible(hash = @config) hash.keys.each do |key| hash[key.to_sym] = hash[key] diff --git a/lib/jekyll/convertible.rb b/lib/jekyll/convertible.rb index bfd03986329..8a851f7c466 100644 --- a/lib/jekyll/convertible.rb +++ b/lib/jekyll/convertible.rb @@ -39,7 +39,7 @@ def read_yaml(base, name, opts = {}) begin self.content = File.read(@path || site.in_source_dir(base, name), - Utils.merged_file_read_opts(site, opts)) + **Utils.merged_file_read_opts(site, opts)) if content =~ Document::YAML_FRONT_MATTER_REGEXP self.content = $POSTMATCH self.data = SafeYAML.load(Regexp.last_match(1)) diff --git a/lib/jekyll/document.rb b/lib/jekyll/document.rb index 061839f13b5..a3971998bab 100644 --- a/lib/jekyll/document.rb +++ b/lib/jekyll/document.rb @@ -266,7 +266,7 @@ def read(opts = {}) else begin merge_defaults - read_content(opts) + read_content(**opts) read_post_data rescue StandardError => e handle_read_error(e) @@ -445,8 +445,8 @@ def merge_defaults end private - def read_content(opts) - self.content = File.read(path, Utils.merged_file_read_opts(site, opts)) + def read_content(**opts) + self.content = File.read(path, **Utils.merged_file_read_opts(site, opts)) if content =~ YAML_FRONT_MATTER_REGEXP self.content = $POSTMATCH data_file = SafeYAML.load(Regexp.last_match(1)) diff --git a/lib/jekyll/drops/site_drop.rb b/lib/jekyll/drops/site_drop.rb index 1cb636d8825..996126829f9 100644 --- a/lib/jekyll/drops/site_drop.rb +++ b/lib/jekyll/drops/site_drop.rb @@ -8,8 +8,7 @@ class SiteDrop < Drop mutable false def_delegator :@obj, :site_data, :data - def_delegators :@obj, :time, :pages, :static_files, :documents, - :tags, :categories + def_delegators :@obj, :time, :pages, :static_files, :tags, :categories private def_delegator :@obj, :config, :fallback_data @@ -39,6 +38,16 @@ def collections @site_collections ||= @obj.collections.values.sort_by(&:label).map(&:to_liquid) end + # `Site#documents` cannot be memoized so that `Site#docs_to_write` can access the + # latest state of the attribute. + # + # Since this method will be called after `Site#pre_render` hook, + # the `Site#documents` array shouldn't thereafter change and can therefore be + # safely memoized to prevent additional computation of `Site#documents`. + def documents + @documents ||= @obj.documents + end + # `{{ site.related_posts }}` is how posts can get posts related to # them, either through LSI if it's enabled, or through the most # recent posts. diff --git a/lib/jekyll/entry_filter.rb b/lib/jekyll/entry_filter.rb index d016e0c2043..91d7961c94b 100644 --- a/lib/jekyll/entry_filter.rb +++ b/lib/jekyll/entry_filter.rb @@ -31,9 +31,12 @@ def relative_to_source(entry) def filter(entries) entries.reject do |e| - unless included?(e) - special?(e) || backup?(e) || excluded?(e) || symlink?(e) - end + # Reject this entry if it is a symlink. + next true if symlink?(e) + # Do not reject this entry if it is included. + next false if included?(e) + # Reject this entry if it is special, a backup file, or excluded. + special?(e) || backup?(e) || excluded?(e) end end diff --git a/lib/jekyll/excerpt.rb b/lib/jekyll/excerpt.rb index 1df15e09a53..82a43f3a85c 100644 --- a/lib/jekyll/excerpt.rb +++ b/lib/jekyll/excerpt.rb @@ -128,36 +128,47 @@ def render_with_liquid? # # Returns excerpt String - LIQUID_TAG_REGEX = %r!{%-?\s*(\w+).+\s*-?%}!m + LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m MKDWN_LINK_REF_REGEX = %r!^ {0,3}\[[^\]]+\]:.+$! def extract_excerpt(doc_content) head, _, tail = doc_content.to_s.partition(doc.excerpt_separator) - # append appropriate closing tag (to a Liquid block), to the "head" if the - # partitioning resulted in leaving the closing tag somewhere in the "tail" - # partition. - if head.include?("{%") - head =~ LIQUID_TAG_REGEX - tag_name = Regexp.last_match(1) + # append appropriate closing tag(s) (for each Liquid block), to the `head` + # if the partitioning resulted in leaving the closing tag somewhere + # in the `tail` partition. - if liquid_block?(tag_name) && head.match(%r!{%-?\s*end#{tag_name}\s*-?%}!).nil? - print_build_warning + if head.include?("{%") + modified = false + tag_names = head.scan(LIQUID_TAG_REGEX) + tag_names.flatten! + tag_names.reverse_each do |tag_name| + next unless liquid_block?(tag_name) + next if head =~ endtag_regex_stash(tag_name) + + modified = true head << "\n{% end#{tag_name} %}" end + print_build_warning if modified end - if tail.empty? - head - else - head.to_s.dup << "\n\n" << tail.scan(MKDWN_LINK_REF_REGEX).join("\n") - end + return head if tail.empty? + + head << "\n\n" << tail.scan(MKDWN_LINK_REF_REGEX).join("\n") end private + def endtag_regex_stash(tag_name) + @endtag_regex_stash ||= {} + @endtag_regex_stash[tag_name] ||= %r!{%-?\s*end#{tag_name}.*?\s*-?%}!m + end + def liquid_block?(tag_name) - Liquid::Template.tags[tag_name].superclass == Liquid::Block + return false unless tag_name.is_a?(String) + return false unless Liquid::Template.tags[tag_name] + + Liquid::Template.tags[tag_name].ancestors.include?(Liquid::Block) rescue NoMethodError Jekyll.logger.error "Error:", "A Liquid tag in the excerpt of #{doc.relative_path} couldn't be " \ @@ -167,12 +178,13 @@ def liquid_block?(tag_name) def print_build_warning Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!" - Jekyll.logger.warn "", - "Found a Liquid block containing separator '#{doc.excerpt_separator}' and has " \ - "been modified with the appropriate closing tag." - Jekyll.logger.warn "", - "Feel free to define a custom excerpt or excerpt_separator in the document's " \ - "Front Matter if the generated excerpt is unsatisfactory." + Jekyll.logger.warn "", "Found a Liquid block containing the excerpt separator" \ + " #{doc.excerpt_separator.inspect}. " + Jekyll.logger.warn "", "The block has been modified with the appropriate" \ + " closing tag." + Jekyll.logger.warn "", "Feel free to define a custom excerpt or" \ + " excerpt_separator in the document's front matter" \ + " if the generated excerpt is unsatisfactory." end end end diff --git a/lib/jekyll/liquid_renderer.rb b/lib/jekyll/liquid_renderer.rb index 55e4e0fb014..39bc639ff9e 100644 --- a/lib/jekyll/liquid_renderer.rb +++ b/lib/jekyll/liquid_renderer.rb @@ -53,7 +53,9 @@ def self.format_error(error, path) private def filename_regex - @filename_regex ||= %r!\A(#{source_dir}/|#{theme_dir}/|\W*)(.*)!i + @filename_regex ||= begin + %r!\A(#{Regexp.escape(source_dir)}/|#{Regexp.escape(theme_dir.to_s)}/|/*)(.*)!i + end end def new_profile_hash diff --git a/lib/jekyll/mime.types b/lib/jekyll/mime.types index af68d359e11..10f713c6ed7 100644 --- a/lib/jekyll/mime.types +++ b/lib/jekyll/mime.types @@ -5,36 +5,47 @@ application/andrew-inset ez application/applixware aw application/atom+xml atom application/atomcat+xml atomcat +application/atomdeleted+xml atomdeleted application/atomsvc+xml atomsvc +application/atsc-dwd+xml dwd +application/atsc-held+xml held +application/atsc-rsat+xml rsat application/bdoc bdoc +application/calendar+xml xcs application/ccxml+xml ccxml +application/cdfx+xml cdfx application/cdmi-capability cdmia application/cdmi-container cdmic application/cdmi-domain cdmid application/cdmi-object cdmio application/cdmi-queue cdmiq +application/cpl+xml cpl application/cu-seeme cu application/dash+xml mpd +application/dash-patch+xml mpp application/davmount+xml davmount application/docbook+xml dbk application/dssc+der dssc application/dssc+xml xdssc -application/ecmascript ecma +application/ecmascript ecma es application/emma+xml emma +application/emotionml+xml emotionml application/epub+zip epub application/exi exi +application/express exp +application/fdt+xml fdt application/font-tdpfr pfr -application/font-woff woff -application/font-woff2 woff2 application/geo+json geojson application/gml+xml gml application/gpx+xml gpx application/gxf gxf application/gzip gz +application/hjson hjson application/hyperstudio stk application/inkml+xml ink inkml application/ipfix ipfix -application/java-archive jar war ear +application/its+xml its +application/java-archive ear jar war application/java-serialized-object ser application/java-vm class application/javascript js mjs @@ -42,6 +53,7 @@ application/json json m application/json5 json5 application/jsonml+json jsonml application/ld+json jsonld +application/lgr+xml lgr application/lost+xml lostxml application/mac-binhex40 hqx application/mac-compactpro cpt @@ -49,32 +61,40 @@ application/mads+xml mads application/manifest+json webmanifest application/marc mrc application/marcxml+xml mrcx -application/mathematica ma nb mb +application/mathematica ma mb nb application/mathml+xml mathml application/mbox mbox +application/media-policy-dataset+xml mpf application/mediaservercontrol+xml mscml application/metalink+xml metalink application/metalink4+xml meta4 application/mets+xml mets +application/mmt-aei+xml maei +application/mmt-usd+xml musd application/mods+xml mods application/mp21 m21 mp21 -application/mp4 mp4s m4p +application/mp4 m4p mp4s application/msword doc dot application/mxf mxf -application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy exe dll deb dmg iso img msi msp msm buffer +application/n-quads nq +application/n-triples nt +application/node cjs +application/octet-stream bin bpk buffer deb deploy dist distz dll dmg dms dump elc exe img iso lrf mar msi msm msp pkg so application/oda oda application/oebps-package+xml opf application/ogg ogx application/omdoc+xml omdoc -application/onenote onetoc onetoc2 onetmp onepkg +application/onenote onepkg onetmp onetoc onetoc2 application/oxps oxps +application/p2p-overlay+xml relo application/patch-ops-error+xml xer application/pdf pdf application/pgp-encrypted pgp -application/pgp-signature asc sig +application/pgp-keys asc +application/pgp-signature sig application/pics-rules prf application/pkcs10 p10 -application/pkcs7-mime p7m p7c +application/pkcs7-mime p7c p7m application/pkcs7-signature p7s application/pkcs8 p8 application/pkix-attr-cert ac @@ -84,14 +104,19 @@ application/pkix-pkipath pkipat application/pkixcmp pki application/pls+xml pls application/postscript ai eps ps +application/provenance+xml provx application/prs.cww cww application/pskc+xml pskcxml -application/rdf+xml rdf +application/raml+yaml raml +application/rdf+xml owl rdf application/reginfo+xml rif application/relax-ng-compact-syntax rnc application/resource-lists+xml rl application/resource-lists-diff+xml rld application/rls-services+xml rs +application/route-apd+xml rapd +application/route-s-tsid+xml sls +application/route-usd+xml rusd application/rpki-ghostbusters gbr application/rpki-manifest mft application/rpki-roa roa @@ -104,9 +129,12 @@ application/scvp-cv-response scs application/scvp-vp-request spq application/scvp-vp-response spp application/sdp sdp +application/senml+xml senmlx +application/sensml+xml sensmlx application/set-payment-initiation setpay application/set-registration-initiation setreg application/shf+xml shf +application/sieve sieve siv application/smil+xml smi smil application/sparql-query rq application/sparql-results+xml srx @@ -115,9 +143,17 @@ application/srgs+xml grxml application/sru+xml sru application/ssdl+xml ssdl application/ssml+xml ssml +application/swid+xml swidtag application/tei+xml tei teicorpus application/thraud+xml tfi application/timestamped-data tsd +application/toml toml +application/trig trig +application/ttml+xml ttml +application/ubjson ubj +application/urc-ressheet+xml rsheet +application/urc-targetdesc+xml td +application/vnd.1000minds.decision-model+xml 1km application/vnd.3gpp.pic-bw-large plb application/vnd.3gpp.pic-bw-small psb application/vnd.3gpp.pic-bw-var pvb @@ -126,12 +162,13 @@ application/vnd.3m.post-it-notes pwn application/vnd.accpac.simply.aso aso application/vnd.accpac.simply.imp imp application/vnd.acucobol acu -application/vnd.acucorp atc acutc +application/vnd.acucorp acutc atc application/vnd.adobe.air-application-installer-package+zip air application/vnd.adobe.formscentral.fcdt fcdt application/vnd.adobe.fxp fxp fxpl application/vnd.adobe.xdp+xml xdp application/vnd.adobe.xfdf xfdf +application/vnd.age age application/vnd.ahead.space ahead application/vnd.airzip.filesecure.azf azf application/vnd.airzip.filesecure.azs azs @@ -143,20 +180,25 @@ application/vnd.anser-web-certificate-issue-initiation cii application/vnd.anser-web-funds-transfer-initiation fti application/vnd.antix.game-component atx application/vnd.apple.installer+xml mpkg +application/vnd.apple.keynote key application/vnd.apple.mpegurl m3u8 +application/vnd.apple.numbers numbers +application/vnd.apple.pages pages application/vnd.apple.pkpass pkpass application/vnd.aristanetworks.swi swi application/vnd.astraea-software.iota iota application/vnd.audiograph aep +application/vnd.balsamiq.bmml+xml bmml application/vnd.blueice.multipass mpm application/vnd.bmi bmi application/vnd.businessobjects rep application/vnd.chemdraw+xml cdxml application/vnd.chipnuts.karaoke-mmd mmd application/vnd.cinderella cdy +application/vnd.citationstyles.style+xml csl application/vnd.claymore cla application/vnd.cloanto.rp9 rp9 -application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.clonk.c4group c4d c4f c4g c4p c4u application/vnd.cluetrust.cartomobile-config c11amc application/vnd.cluetrust.cartomobile-config-pkg c11amz application/vnd.commonspace csp @@ -174,10 +216,11 @@ application/vnd.curl.car car application/vnd.curl.pcurl pcurl application/vnd.dart dart application/vnd.data-vision.rdz rdz -application/vnd.dece.data uvf uvvf uvd uvvd +application/vnd.dbf dbf +application/vnd.dece.data uvd uvf uvvd uvvf application/vnd.dece.ttml+xml uvt uvvt -application/vnd.dece.unspecified uvx uvvx -application/vnd.dece.zip uvz uvvz +application/vnd.dece.unspecified uvvx uvx +application/vnd.dece.zip uvvz uvz application/vnd.denovo.fcselayout-link fe_launch application/vnd.dna dna application/vnd.dolby.mlp mlp @@ -199,10 +242,10 @@ application/vnd.ezpix-album ez2 application/vnd.ezpix-package ez3 application/vnd.fdf fdf application/vnd.fdsn.mseed mseed -application/vnd.fdsn.seed seed dataless +application/vnd.fdsn.seed dataless seed application/vnd.flographit gph application/vnd.fluxtime.clip ftc -application/vnd.framemaker fm frame maker book +application/vnd.framemaker book fm frame maker application/vnd.frogans.fnc fnc application/vnd.frogans.ltf ltf application/vnd.fsc.weblaunch fsc @@ -248,7 +291,7 @@ application/vnd.hp-pcl pcl application/vnd.hp-pclxl pclxl application/vnd.hydrostatix.sof-data sfd-hdstx application/vnd.ibm.minipay mpy -application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.modcap afp list3820 listafp application/vnd.ibm.rights-management irm application/vnd.ibm.secure-container sc application/vnd.iccprofile icc icm @@ -268,7 +311,7 @@ application/vnd.jam jam application/vnd.jcp.javame.midlet-rms rms application/vnd.jisp jisp application/vnd.joost.joda-archive joda -application/vnd.kahootz ktz ktr +application/vnd.kahootz ktr ktz application/vnd.kde.karbon karbon application/vnd.kde.kchart chrt application/vnd.kde.kformula kfo @@ -280,7 +323,7 @@ application/vnd.kde.kword kwd kw application/vnd.kenameaapp htke application/vnd.kidspiration kia application/vnd.kinar kne knp -application/vnd.koan skp skd skt skm +application/vnd.koan skd skm skp skt application/vnd.kodak-descriptor sse application/vnd.las.las+xml lasxml application/vnd.llamagraphics.life-balance.desktop lbd @@ -293,6 +336,7 @@ application/vnd.lotus-organizer org application/vnd.lotus-screencam scm application/vnd.lotus-wordpro lwp application/vnd.macports.portpkg portpkg +application/vnd.mapbox-vector-tile mvt application/vnd.mcd mcd application/vnd.medcalcdata mc1 application/vnd.mediastation.cdkey cdkey @@ -313,7 +357,7 @@ application/vnd.mophun.certificate mpc application/vnd.mozilla.xul+xml xul application/vnd.ms-artgalry cil application/vnd.ms-cab-compressed cab -application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-excel xla xlc xlm xls xlt xlw application/vnd.ms-excel.addin.macroenabled.12 xlam application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb application/vnd.ms-excel.sheet.macroenabled.12 xlsm @@ -326,16 +370,16 @@ application/vnd.ms-officetheme thmx application/vnd.ms-outlook msg application/vnd.ms-pki.seccat cat application/vnd.ms-pki.stl stl -application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-powerpoint pot pps ppt application/vnd.ms-powerpoint.addin.macroenabled.12 ppam application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm application/vnd.ms-powerpoint.slide.macroenabled.12 sldm application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm application/vnd.ms-powerpoint.template.macroenabled.12 potm -application/vnd.ms-project mpp mpt +application/vnd.ms-project mpt application/vnd.ms-word.document.macroenabled.12 docm application/vnd.ms-word.template.macroenabled.12 dotm -application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-works wcm wdb wks wps application/vnd.ms-wpl wpl application/vnd.ms-xpsdocument xps application/vnd.mseq mseq @@ -343,7 +387,7 @@ application/vnd.musician mus application/vnd.muvee.style msty application/vnd.mynfc taglet application/vnd.neurolanguage.nlu nlu -application/vnd.nitf ntf nitf +application/vnd.nitf nitf ntf application/vnd.noblenet-directory nnd application/vnd.noblenet-sealer nns application/vnd.noblenet-web nnw @@ -373,7 +417,9 @@ application/vnd.oasis.opendocument.text-template ott application/vnd.oasis.opendocument.text-web oth application/vnd.olpc-sugar xo application/vnd.oma.dd2+xml dd2 +application/vnd.openblox.game+xml obgx application/vnd.openofficeorg.extension oxt +application/vnd.openstreetmap.data+xml osm application/vnd.openxmlformats-officedocument.presentationml.presentation pptx application/vnd.openxmlformats-officedocument.presentationml.slide sldx application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx @@ -385,7 +431,7 @@ application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx application/vnd.osgeo.mapguide.package mgp application/vnd.osgi.dp dp application/vnd.osgi.subsystem esa -application/vnd.palm pdb pqa oprc +application/vnd.palm oprc pdb pqa application/vnd.pawaafile paw application/vnd.pg.format str application/vnd.pg.osasli ei6 @@ -397,7 +443,8 @@ application/vnd.previewsystems.box box application/vnd.proteus.magazine mgz application/vnd.publishare-delta-tree qps application/vnd.pvi.ptid1 ptid -application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +application/vnd.quark.quarkxpress qwd qwt qxb qxd qxl qxt +application/vnd.rar rar application/vnd.realvnc.bed bed application/vnd.recordare.musicxml mxl application/vnd.recordare.musicxml+xml musicxml @@ -418,7 +465,8 @@ application/vnd.shana.informed.package ipk application/vnd.simtech-mindmapper twd twds application/vnd.smaf mmf application/vnd.smart.teacher teacher -application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.software602.filler.form+xml fo +application/vnd.solent.sdkm+xml sdkd sdkm application/vnd.spotfire.dxp dxp application/vnd.spotfire.sfs sfs application/vnd.stardivision.calc sdc @@ -446,8 +494,9 @@ application/vnd.symbian.install sis si application/vnd.syncml+xml xsm application/vnd.syncml.dm+wbxml bdm application/vnd.syncml.dm+xml xdm +application/vnd.syncml.dmddf+xml ddf application/vnd.tao.intent-module-archive tao -application/vnd.tcpdump.pcap pcap cap dmp +application/vnd.tcpdump.pcap cap dmp pcap application/vnd.tmobile-livetv tmo application/vnd.trid.tpt tpt application/vnd.triscape.mxs mxs @@ -458,7 +507,7 @@ application/vnd.umajin umj application/vnd.unity unityweb application/vnd.uoml+xml uoml application/vnd.vcx vcx -application/vnd.visio vsd vst vss vsw +application/vnd.visio vsd vss vst vsw application/vnd.visionary vis application/vnd.vsf vsf application/vnd.wap.wbxml wbxml @@ -482,6 +531,8 @@ application/vnd.yellowriver-custom-menu cmp application/vnd.zul zir zirz application/vnd.zzazz.deck+xml zaz application/voicexml+xml vxml +application/wasm wasm +application/watcherinfo+xml wif application/widget wgt application/winhlp hlp application/wsdl+xml wsdl @@ -490,15 +541,15 @@ application/x-7z-compressed 7z application/x-abiword abw application/x-ace-compressed ace application/x-arj arj -application/x-authorware-bin aab x32 u32 vox +application/x-authorware-bin aab u32 vox x32 application/x-authorware-map aam application/x-authorware-seg aas application/x-bcpio bcpio application/x-bittorrent torrent application/x-blorb blb blorb application/x-bzip bz -application/x-bzip2 bz2 boz -application/x-cbr cbr cba cbt cbz cb7 +application/x-bzip2 boz bz2 +application/x-cbr cb7 cba cbr cbt cbz application/x-cdlink vcd application/x-cfs-compressed cfs application/x-chat chat @@ -510,7 +561,7 @@ application/x-cpio cpio application/x-csh csh application/x-debian-package udeb application/x-dgc-compressed dgc -application/x-director dir dcr dxr cst cct cxt w3d fgd swa +application/x-director cct cst cxt dcr dir dxr fgd swa w3d application/x-doom wad application/x-dtbncx+xml ncx application/x-dtbook+xml dtb @@ -521,11 +572,9 @@ application/x-eva eva application/x-font-bdf bdf application/x-font-ghostscript gsf application/x-font-linux-psf psf -application/x-font-otf otf application/x-font-pcf pcf application/x-font-snf snf -application/x-font-ttf ttf ttc -application/x-font-type1 pfa pfb pfm afm +application/x-font-type1 afm pfa pfb pfm application/x-freearc arc application/x-futuresplash spl application/x-gca-compressed gca @@ -538,12 +587,13 @@ application/x-httpd-php php application/x-install-instructions install application/x-java-archive-diff jardiff application/x-java-jnlp-file jnlp +application/x-keepass2 kdbx application/x-latex latex application/x-lua-bytecode luac -application/x-lzh-compressed lzh lha +application/x-lzh-compressed lha lzh application/x-makeself run application/x-mie mie -application/x-mobipocket-ebook prc mobi +application/x-mobipocket-ebook mobi prc application/x-ms-application application application/x-ms-shortcut lnk application/x-ms-wmd wmd @@ -553,22 +603,21 @@ application/x-msaccess mdb application/x-msbinder obd application/x-mscardfile crd application/x-msclip clp -application/x-msdownload com bat -application/x-msmediaview mvb m13 m14 -application/x-msmetafile wmf emf emz +application/x-msdownload bat com +application/x-msmediaview m13 m14 mvb +application/x-msmetafile emf emz wmf application/x-msmoney mny application/x-mspublisher pub application/x-msschedule scd application/x-msterminal trm application/x-mswrite wri -application/x-netcdf nc cdf +application/x-netcdf cdf nc application/x-ns-proxy-autoconfig pac application/x-nzb nzb application/x-perl pl pm application/x-pkcs12 p12 pfx application/x-pkcs7-certificates p7b spc application/x-pkcs7-certreqresp p7r -application/x-rar-compressed rar application/x-redhat-package-manager rpm application/x-research-info-systems ris application/x-sea sea @@ -588,7 +637,7 @@ application/x-tar tar application/x-tcl tcl tk application/x-tex tex application/x-tex-tfm tfm -application/x-texinfo texinfo texi +application/x-texinfo texi texinfo application/x-tgif obj application/x-ustar ustar application/x-virtualbox-hdd hdd @@ -601,34 +650,40 @@ application/x-virtualbox-vhd vhd application/x-virtualbox-vmdk vmdk application/x-wais-source src application/x-web-app-manifest+json webapp -application/x-x509-ca-cert der crt pem +application/x-x509-ca-cert crt der pem application/x-xfig fig application/x-xliff+xml xlf application/x-xpinstall xpi application/x-xz xz application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 application/xaml+xml xaml +application/xcap-att+xml xav +application/xcap-caps+xml xca application/xcap-diff+xml xdf +application/xcap-el+xml xel +application/xcap-ns+xml xns application/xenc+xml xenc -application/xhtml+xml xhtml xht -application/xml xml xsl xsd rng +application/xhtml+xml xht xhtml +application/xml rng xml xsd xsl application/xml-dtd dtd application/xop+xml xop application/xproc+xml xpl application/xslt+xml xslt application/xspf+xml xspf -application/xv+xml mxml xhvml xvml xvm +application/xv+xml mxml xhvml xvm xvml application/yang yang application/yin+xml yin application/zip zip audio/3gpp 3gpp audio/adpcm adp +audio/amr amr audio/basic au snd -audio/midi mid midi kar rmi +audio/midi kar mid midi rmi +audio/mobile-xmf mxmf audio/mp3 mp3 audio/mp4 m4a mp4a -audio/mpeg mpga mp2 mp2a m2a m3a -audio/ogg oga ogg spx +audio/mpeg m2a m3a mp2 mp2a mpga +audio/ogg oga ogg opus spx audio/s3m s3m audio/silk sil audio/vnd.dece.audio uva uvva @@ -645,14 +700,14 @@ audio/vnd.rip rip audio/wav wav audio/webm weba audio/x-aac aac -audio/x-aiff aif aiff aifc +audio/x-aiff aif aifc aiff audio/x-caf caf audio/x-flac flac audio/x-matroska mka audio/x-mpegurl m3u audio/x-ms-wax wax audio/x-ms-wma wma -audio/x-pn-realaudio ram ra +audio/x-pn-realaudio ra ram audio/x-pn-realaudio-plugin rmp audio/xm xm chemical/x-cdx cdx @@ -661,22 +716,57 @@ chemical/x-cmdf cmdf chemical/x-cml cml chemical/x-csml csml chemical/x-xyz xyz +font/collection ttc +font/otf otf +font/ttf ttf +font/woff woff +font/woff2 woff2 +image/aces exr image/apng apng +image/avci avci +image/avcs avcs +image/avif avif image/bmp bmp image/cgm cgm +image/dicom-rle drle +image/fits fits image/g3fax g3 image/gif gif +image/heic heic +image/heic-sequence heics +image/heif heif +image/heif-sequence heifs +image/hej2k hej2 +image/hsj2 hsj2 image/ief ief -image/jpeg jpeg jpg jpe +image/jls jls +image/jp2 jp2 jpg2 +image/jpeg jpe jpeg jpg +image/jph jph +image/jphc jhc +image/jpm jpm +image/jpx jpf jpx +image/jxr jxr +image/jxra jxra +image/jxrs jxrs +image/jxs jxs +image/jxsc jxsc +image/jxsi jxsi +image/jxss jxss image/ktx ktx +image/ktx2 ktx2 image/png png image/prs.btif btif +image/prs.pti pti image/sgi sgi image/svg+xml svg svgz -image/tiff tiff tif +image/t38 t38 +image/tiff tif tiff +image/tiff-fx tfx image/vnd.adobe.photoshop psd -image/vnd.dece.graphic uvi uvvi uvg uvvg -image/vnd.djvu djvu djv +image/vnd.airzip.accelerator.azv azv +image/vnd.dece.graphic uvg uvi uvvg uvvi +image/vnd.djvu djv djvu image/vnd.dvb.subtitle sub image/vnd.dwg dwg image/vnd.dxf dxf @@ -685,21 +775,25 @@ image/vnd.fpx fpx image/vnd.fst fst image/vnd.fujixerox.edmics-mmr mmr image/vnd.fujixerox.edmics-rlc rlc +image/vnd.microsoft.icon ico +image/vnd.ms-dds dds image/vnd.ms-modi mdi image/vnd.ms-photo wdp image/vnd.net-fpx npx +image/vnd.pco.b16 b16 +image/vnd.tencent.tap tap +image/vnd.valve.source.texture vtf image/vnd.wap.wbmp wbmp image/vnd.xiff xif +image/vnd.zbrush.pcx pcx image/webp webp image/x-3ds 3ds image/x-cmu-raster ras image/x-cmx cmx -image/x-freehand fh fhc fh4 fh5 fh7 -image/x-icon ico +image/x-freehand fh fh4 fh5 fh7 fhc image/x-jng jng image/x-mrsid-image sid -image/x-pcx pcx -image/x-pict pic pct +image/x-pict pct pic image/x-portable-anymap pnm image/x-portable-bitmap pbm image/x-portable-graymap pgm @@ -709,18 +803,35 @@ image/x-tga tga image/x-xbitmap xbm image/x-xpixmap xpm image/x-xwindowdump xwd +message/disposition-notification disposition-notification +message/global u8msg +message/global-delivery-status u8dsn +message/global-disposition-notification u8mdn +message/global-headers u8hdr message/rfc822 eml mime +message/vnd.wfa.wsc wsc +model/3mf 3mf model/gltf+json gltf model/gltf-binary glb -model/iges igs iges -model/mesh msh mesh silo +model/iges iges igs +model/mesh mesh msh silo +model/mtl mtl +model/step+xml stpx +model/step+zip stpz +model/step-xml+zip stpxz model/vnd.collada+xml dae model/vnd.dwf dwf model/vnd.gdl gdl model/vnd.gtw gtw model/vnd.mts mts +model/vnd.opengex ogex +model/vnd.parasolid.transmit.binary x_b +model/vnd.parasolid.transmit.text x_t +model/vnd.sap.vds vds +model/vnd.usdz+zip usdz +model/vnd.valve.source.compiled-map bsp model/vnd.vtu vtu -model/vrml wrl vrml +model/vrml vrml wrl model/x3d+binary x3db x3dbz model/x3d+vrml x3dv x3dvz model/x3d+xml x3d x3dz @@ -729,22 +840,24 @@ text/calendar ics if text/coffeescript coffee litcoffee text/css css text/csv csv -text/hjson hjson -text/html html htm shtml +text/html htm html shtml text/jade jade text/jsx jsx text/less less text/markdown markdown md text/mathml mml +text/mdx mdx text/n3 n3 -text/plain txt text conf def list log in ini +text/plain conf def in ini list log text txt text/prs.lines.tag dsc text/richtext rtx -text/sgml sgml sgm +text/sgml sgm sgml +text/shex shex text/slim slim slm -text/stylus stylus styl +text/spdx spdx +text/stylus styl stylus text/tab-separated-values tsv -text/troff t tr roff man me ms +text/troff man me ms roff t tr text/turtle ttl text/uri-list uri uris urls text/vcard vcard @@ -752,6 +865,7 @@ text/vnd.curl curl text/vnd.curl.dcurl dcurl text/vnd.curl.mcurl mcurl text/vnd.curl.scurl scurl +text/vnd.familysearch.gedcom ged text/vnd.fly fly text/vnd.fmi.flexstor flx text/vnd.graphviz gv @@ -761,10 +875,10 @@ text/vnd.sun.j2me.app-descriptor jad text/vnd.wap.wml wml text/vnd.wap.wmlscript wmls text/vtt vtt -text/x-asm s asm -text/x-c c cc cxx cpp h hh dic +text/x-asm asm s +text/x-c c cc cpp cxx dic h hh text/x-component htc -text/x-fortran f for f77 f90 +text/x-fortran f f77 f90 for text/x-handlebars-template hbs text/x-java-source java text/x-lua lua @@ -787,14 +901,15 @@ video/3gpp2 3g2 video/h261 h261 video/h263 h263 video/h264 h264 +video/iso.segment m4s video/jpeg jpgv -video/jpm jpm jpgm +video/jpm jpgm video/mj2 mj2 mjp2 video/mp2t ts video/mp4 mp4 mp4v mpg4 -video/mpeg mpeg mpg mpe m1v m2v +video/mpeg m1v m2v mpe mpeg mpg video/ogg ogv -video/quicktime qt mov +video/quicktime mov qt video/vnd.dece.hd uvh uvvh video/vnd.dece.mobile uvm uvvm video/vnd.dece.pd uvp uvvp @@ -802,7 +917,7 @@ video/vnd.dece.sd uvs uv video/vnd.dece.video uvv uvvv video/vnd.dvb.file dvb video/vnd.fvt fvt -video/vnd.mpegurl mxu m4u +video/vnd.mpegurl m4u mxu video/vnd.ms-playready.media.pyv pyv video/vnd.uvvu.mp4 uvu uvvu video/vnd.vivo viv @@ -811,7 +926,7 @@ video/x-f4v f4v video/x-fli fli video/x-flv flv video/x-m4v m4v -video/x-matroska mkv mk3d mks +video/x-matroska mk3d mks mkv video/x-mng mng video/x-ms-asf asf asx video/x-ms-vob vob diff --git a/lib/jekyll/page.rb b/lib/jekyll/page.rb index caea9cd924e..b8b8e4492ff 100644 --- a/lib/jekyll/page.rb +++ b/lib/jekyll/page.rb @@ -183,5 +183,20 @@ def trigger_hooks(hook_name, *args) def write? true end + + # The Page excerpt_separator, from the YAML Front-Matter or site + # default excerpt_separator value + # + # Returns the document excerpt_separator + def excerpt_separator + (data["excerpt_separator"] || site.config["excerpt_separator"]).to_s + end + + # Whether to generate an excerpt + # + # Returns true if the excerpt separator is configured. + def generate_excerpt? + !excerpt_separator.empty? + end end end diff --git a/lib/jekyll/readers/data_reader.rb b/lib/jekyll/readers/data_reader.rb index 445d548802b..ebd2f67adbd 100644 --- a/lib/jekyll/readers/data_reader.rb +++ b/lib/jekyll/readers/data_reader.rb @@ -54,16 +54,14 @@ def read_data_to(dir, data) def read_data_file(path) case File.extname(path).downcase when ".csv" - CSV.read(path, { + CSV.read(path, :headers => true, - :encoding => site.config["encoding"], - }).map(&:to_hash) + :encoding => site.config["encoding"]).map(&:to_hash) when ".tsv" - CSV.read(path, { + CSV.read(path, :col_sep => "\t", :headers => true, - :encoding => site.config["encoding"], - }).map(&:to_hash) + :encoding => site.config["encoding"]).map(&:to_hash) else SafeYAML.load_file(path) end diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb index 25257a64c0d..44bacc9047c 100644 --- a/lib/jekyll/site.rb +++ b/lib/jekyll/site.rb @@ -314,15 +314,15 @@ def relative_permalinks_are_deprecated # # Returns an Array of Documents which should be written def docs_to_write - @docs_to_write ||= documents.select(&:write?) + documents.select(&:write?) end # Get all the documents # # Returns an Array of all Documents def documents - collections.reduce(Set.new) do |docs, (_, collection)| - docs + collection.docs + collection.files + collections.each_with_object(Set.new) do |(_, collection), set| + set.merge(collection.docs).merge(collection.files) end.to_a end diff --git a/lib/jekyll/stevenson.rb b/lib/jekyll/stevenson.rb index bbec66171f6..5ab4495ce95 100644 --- a/lib/jekyll/stevenson.rb +++ b/lib/jekyll/stevenson.rb @@ -3,13 +3,10 @@ module Jekyll class Stevenson < ::Logger def initialize - @progname = nil - @level = DEBUG - @default_formatter = Formatter.new - @logdev = $stdout - @formatter = proc do |_, _, _, msg| + formatter = proc do |_, _, _, msg| msg.to_s end + super($stdout, :formatter => formatter) end def add(severity, message = nil, progname = nil) diff --git a/lib/jekyll/tags/include.rb b/lib/jekyll/tags/include.rb index 0ee983dc177..49339b1d86c 100644 --- a/lib/jekyll/tags/include.rb +++ b/lib/jekyll/tags/include.rb @@ -22,7 +22,7 @@ class IncludeTag < Liquid::Tag !mx FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z! - VALID_FILENAME_CHARS = %r!^[\w/\.-]+$! + VALID_FILENAME_CHARS = %r!^[\w/.\-()+~\#@]+$! INVALID_SEQUENCES = %r![./]{2,}! def initialize(tag_name, markup, tokens) @@ -147,12 +147,17 @@ def render(context) end def add_include_to_dependency(site, path, context) - if context.registers[:page] && context.registers[:page].key?("path") - site.regenerator.add_dependency( - site.in_source_dir(context.registers[:page]["path"]), - path - ) - end + page = context.registers[:page] + return unless page + return unless page.key?("path") + + absolute_path = \ + if page["collection"] + site.in_source_dir(site.config["collections_dir"], page["path"]) + else + site.in_source_dir(page["path"]) + end + site.regenerator.add_dependency(absolute_path, path) end def load_cached_partial(path, context) @@ -191,7 +196,7 @@ def realpath_prefixed_with?(path, dir) # This method allows to modify the file content by inheriting from the class. def read_file(file, context) - File.read(file, file_read_opts(context)) + File.read(file, **file_read_opts(context)) end private @@ -224,6 +229,7 @@ def page_path(context) else File.join(site.config["collections_dir"], page_payload["path"]) end + resource_path.sub!(%r!/#excerpt\z!, "") site.in_source_dir File.dirname(resource_path) end end diff --git a/lib/jekyll/theme.rb b/lib/jekyll/theme.rb index a21b4bdfea1..8b28fbb47dc 100644 --- a/lib/jekyll/theme.rb +++ b/lib/jekyll/theme.rb @@ -56,12 +56,28 @@ def path_for(folder) end def realpath_for(folder) - File.realpath(Jekyll.sanitized_path(root, folder.to_s)) - rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP - Jekyll.logger.warn "Invalid theme folder:", folder + # This resolves all symlinks for the theme subfolder and then ensures + # that the directory remains inside the theme root. This prevents the + # use of symlinks for theme subfolders to escape the theme root. + # However, symlinks are allowed to point to other directories within the theme. + Jekyll.sanitized_path(root, File.realpath(Jekyll.sanitized_path(root, folder.to_s))) + rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP => e + log_realpath_exception(e, folder) nil end + def log_realpath_exception(err, folder) + return if err.is_a?(Errno::ENOENT) + + case err + when Errno::EACCES + Jekyll.logger.error "Theme error:", "Directory '#{folder}' is not accessible." + when Errno::ELOOP + Jekyll.logger.error "Theme error:", + "Directory '#{folder}' includes a symbolic link loop." + end + end + def gemspec @gemspec ||= Gem::Specification.find_by_name(name) rescue Gem::LoadError diff --git a/lib/jekyll/utils/platforms.rb b/lib/jekyll/utils/platforms.rb index 6665527a726..0748b0e3c4a 100644 --- a/lib/jekyll/utils/platforms.rb +++ b/lib/jekyll/utils/platforms.rb @@ -70,9 +70,9 @@ def linux? private def proc_version @proc_version ||= begin - Pathutil.new( + File.read( "/proc/version" - ).read + ).downcase rescue Errno::ENOENT nil end diff --git a/lib/jekyll/utils/win_tz.rb b/lib/jekyll/utils/win_tz.rb index 239650f71fe..ad277d3a6a5 100644 --- a/lib/jekyll/utils/win_tz.rb +++ b/lib/jekyll/utils/win_tz.rb @@ -11,64 +11,35 @@ module WinTZ # timezone - the IANA Time Zone specified in "_config.yml" # # Returns a string that ultimately re-defines ENV["TZ"] in Windows - def calculate(timezone) + def calculate(timezone, now = Time.now) External.require_with_graceful_fail("tzinfo") unless defined?(TZInfo) tz = TZInfo::Timezone.get(timezone) - difference = Time.now.to_i - tz.now.to_i + + # + # Use period_for_utc and utc_total_offset instead of + # period_for and observed_utc_offset for compatibility with tzinfo v1. + offset = tz.period_for_utc(now.getutc).utc_total_offset + # # POSIX style definition reverses the offset sign. # e.g. Eastern Standard Time (EST) that is 5Hrs. to the 'west' of Prime Meridian # is denoted as: # EST+5 (or) EST+05:00 - # Reference: http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html - sign = difference < 0 ? "-" : "+" - offset = sign == "-" ? "+" : "-" unless difference.zero? - # - # convert the difference (in seconds) to hours, as a rational number, and perform - # a modulo operation on it. - modulo = modulo_of(rational_hour(difference)) + # Reference: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + sign = offset.positive? ? "-" : "+" + + rational_hours = offset.abs.to_r / 3600 + hours = rational_hours.to_i + minutes = ((rational_hours - hours) * 60).to_i + # - # Format the hour as a two-digit number. - # Establish the minutes based on modulo expression. - hh = format("%02d", absolute_hour(difference).ceil) - mm = modulo.zero? ? "00" : "30" + # Format the hours and minutes as two-digit numbers. + time = format("%02d:%02d", :hours => hours, :minutes => minutes) - Jekyll.logger.debug "Timezone:", "#{timezone} #{offset}#{hh}:#{mm}" + Jekyll.logger.debug "Timezone:", "#{timezone} #{sign}#{time}" # # Note: The 3-letter-word below doesn't have a particular significance. - "WTZ#{sign}#{hh}:#{mm}" - end - - private - - # Private: Convert given seconds to an hour as a rational number. - # - # seconds - supplied as an integer, it is converted to a rational number. - # 3600 - no. of seconds in an hour. - # - # Returns a rational number. - def rational_hour(seconds) - seconds.to_r / 3600 - end - - # Private: Convert given seconds to an hour as an absolute number. - # - # seconds - supplied as an integer, it is converted to its absolute. - # 3600 - no. of seconds in an hour. - # - # Returns an integer. - def absolute_hour(seconds) - seconds.abs / 3600 - end - - # Private: Perform a modulo operation on a given fraction. - # - # fraction - supplied as a rational number, its numerator is divided - # by its denominator and the remainder returned. - # - # Returns an integer. - def modulo_of(fraction) - fraction.numerator % fraction.denominator + "WTZ#{sign}#{time}" end end end diff --git a/lib/jekyll/version.rb b/lib/jekyll/version.rb index 9a62ec6f3af..b0116735fbd 100644 --- a/lib/jekyll/version.rb +++ b/lib/jekyll/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Jekyll - VERSION = "3.8.3".freeze + VERSION = "3.9.5".freeze end diff --git a/script/default-site b/script/default-site index 0504fd3815e..061b265a66b 100755 --- a/script/default-site +++ b/script/default-site @@ -13,6 +13,15 @@ pushd tmp/default-site echo "$0: respecifying the jekyll install location" ruby -e "contents = File.read('Gemfile'); File.write('Gemfile', contents.sub(/gem \"jekyll\".*\\n/, 'gem \"jekyll\", path: \"../../\"'))" +if [ -n "$KRAMDOWN_VERSION" ]; then + echo "$0: respecifying the kramdown version" + ruby -e "contents = File.read('Gemfile'); File.write('Gemfile', contents.sub(/gem \"kramdown-parser-gfm\".*\\n/, ''))" + echo "gem 'kramdown', '~> $KRAMDOWN_VERSION'" >> Gemfile +fi +if [ -n "$ROUGE_VERSION" ]; then + echo "$0: respecifying the rouge version" + echo "gem 'rouge', '~> $ROUGE_VERSION'" >> Gemfile +fi echo "$0: installing default site dependencies" BUNDLE_GEMFILE=Gemfile bundle install echo "$0: building the default site" diff --git a/script/profile-docs b/script/profile-docs new file mode 100755 index 00000000000..234782677e1 --- /dev/null +++ b/script/profile-docs @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# +# Build Jekyll's Documentation site in 'debug' mode and outputs the site's profile stats. +# Helps detecting *hard* breaking-changes (`jekyll build` aborts) and optimizations +# in the `build` process. +# +# Usage: bash script/profile-docs + +SOURCE_DIR=$PWD/docs +bundle exec jekyll build -s $SOURCE_DIR -d $SOURCE_DIR/_site --profile --trace --verbose diff --git a/script/vendor-mimes b/script/vendor-mimes index 6ea9c377a64..7cb7785c71e 100755 --- a/script/vendor-mimes +++ b/script/vendor-mimes @@ -2,16 +2,41 @@ # Vendors the MIME type config from the mime-db list # usage: script/vendor-mimes +require 'colorator' require 'json' require 'open-uri' -config = File.expand_path "../lib/jekyll/mime.types", __dir__ +# ---- Helpers ---- -# Create an array of vendored mimetype => [extensions] -mimes = {} -json = open('https://raw.githubusercontent.com/jshttp/mime-db/master/db.json').read +{ + :info => :cyan, + :success => :green, + :error => :red, +}.each do |type, color| + define_method("log_#{type}") do |msg| + puts " #{msg}".send(color) + end +end + +# ---- + +json = begin + log_info "Reading remote data.." + URI.open("https://raw.githubusercontent.com/jshttp/mime-db/master/db.json").read +rescue StandardError => e + log_error "Error reading remote data!" + log_error e.message + log_error "Aborting." + exit 1 +end + +log_info "Parsing remote data.." data = JSON.parse(json) data.reject! { |mime, meta| meta["extensions"].nil? || meta["extensions"].empty? } + +log_info "Generating interim mime data-hashes.." +mimes = {} +charset_data = {} data.each do |mime, meta| # Normalize extensions and mime-types mime = mime.downcase.strip @@ -23,8 +48,15 @@ data.each do |mime, meta| next if extensions.empty? mimes[mime] = [] if mimes[mime].nil? mimes[mime].concat extensions + + # Extract mime-types with "charset" metadata + charset_data[mime] = meta["charset"] if meta.key?("charset") + + # Assign `UTF-8` charset for mime-types under the `text` domain if not already assigned upstream + charset_data[mime] ||= "UTF-8" if mime.start_with?("text/") end +log_info "Formatting primary hash and writing to file.." strlen = mimes.keys.max_by(&:length).length output = "" output << "# Woah there. Do not edit this file directly.\n" @@ -32,4 +64,14 @@ output << "# This file is generated automatically by script/vendor-mimes.\n\n" mimes = mimes.sort_by { |k,v| k } output << mimes.map { |mime,extensions| "#{mime.ljust(strlen)} #{extensions.join(" ")}" }.join("\n") +config = File.expand_path "../lib/jekyll/mime.types", __dir__ File.write(config, output) +log_info "Done! See: #{config.inspect.white}" + +# --- Generate JSON file from charset_data ---- +puts + +log_info "Dumping mimetype-charset mapping as JSON.." +json_file = File.expand_path "../lib/jekyll/commands/serve/mime_types_charset.json", __dir__ +File.write(json_file, JSON.pretty_generate(charset_data) + "\n") +log_success "and done! See: #{json_file.inspect.white}" diff --git a/test/fixtures/test-theme-skinny/_layouts/default.html b/test/fixtures/test-theme-skinny/_layouts/default.html new file mode 100644 index 00000000000..837a4dc7696 --- /dev/null +++ b/test/fixtures/test-theme-skinny/_layouts/default.html @@ -0,0 +1,11 @@ + + + + + Skinny + + +

Hello World

+ {{ content }} + + diff --git a/test/fixtures/test-theme-skinny/_layouts/home.html b/test/fixtures/test-theme-skinny/_layouts/home.html new file mode 100644 index 00000000000..6d9ce5c7ef1 --- /dev/null +++ b/test/fixtures/test-theme-skinny/_layouts/home.html @@ -0,0 +1,5 @@ +--- +layout: default +--- + +Message: {{ content }} diff --git a/test/fixtures/test-theme-skinny/test-theme-skinny.gemspec b/test/fixtures/test-theme-skinny/test-theme-skinny.gemspec new file mode 100644 index 00000000000..84f59b9d709 --- /dev/null +++ b/test/fixtures/test-theme-skinny/test-theme-skinny.gemspec @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +Gem::Specification.new do |s| + s.name = "test-theme-skinny" + s.version = "0.1.0" + s.licenses = ["MIT"] + s.summary = "This is a theme with just layouts used to test Jekyll" + s.authors = ["Jekyll"] + s.files = ["lib/example.rb"] + s.homepage = "https://github.com/jekyll/jekyll" +end diff --git a/test/fixtures/test-theme-symlink/test-theme-symlink.gemspec b/test/fixtures/test-theme-symlink/test-theme-symlink.gemspec new file mode 100644 index 00000000000..b0a915e3308 --- /dev/null +++ b/test/fixtures/test-theme-symlink/test-theme-symlink.gemspec @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +Gem::Specification.new do |s| + s.name = "test-theme-symlink" + s.version = "0.1.0" + s.licenses = ["MIT"] + s.summary = "This is a theme with a symlink used to test Jekyll" + s.authors = ["Jekyll"] + s.files = ["lib/example.rb"] + s.homepage = "https://github.com/jekyll/jekyll" +end diff --git a/test/helper.rb b/test/helper.rb index aa94be13e61..66dface5db5 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -195,6 +195,15 @@ def skip_if_windows(msg = nil) skip msg.to_s.magenta end end + + def symlink_if_allowed(target, sym_file) + FileUtils.ln_sf(target, sym_file) + rescue Errno::EACCES + skip "Permission denied for creating a symlink to #{target.inspect} " \ + "on this machine".magenta + rescue NotImplementedError => error + skip error.to_s.magenta + end end class FakeLogger @@ -202,7 +211,6 @@ def <<(str); end end module TestWEBrick - module_function def mount_server(&block) @@ -231,6 +239,7 @@ def config :ServerType => Thread, :Logger => WEBrick::Log.new(logger), :AccessLog => [[logger, ""]], + :MimeTypesCharset => Jekyll::Commands::Serve.send(:mime_types_charset), :JekyllOptions => {}, } end diff --git a/test/source/_includes/params@2.0.html b/test/source/_includes/params@2.0.html new file mode 100644 index 00000000000..65a00018ca6 --- /dev/null +++ b/test/source/_includes/params@2.0.html @@ -0,0 +1,7 @@ +{{include.param}} + + \ No newline at end of file diff --git a/test/source/_plugins/custom_block.rb b/test/source/_plugins/custom_block.rb new file mode 100644 index 00000000000..eee0fbaadaa --- /dev/null +++ b/test/source/_plugins/custom_block.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# For testing excerpt handling of custom tags + +module Jekyll + class DoNothingBlock < Liquid::Block + end + + class DoNothingOther < Liquid::Tag + end +end + +Liquid::Template.register_tag("do_nothing", Jekyll::DoNothingBlock) +Liquid::Template.register_tag("do_nothing_other", Jekyll::DoNothingOther) diff --git a/test/source/_posts/2018-01-28-closed-liquid-block-excerpt.markdown b/test/source/_posts/2018-01-28-closed-liquid-block-excerpt.markdown index 991ebf84e5b..a2c9fe56d5a 100644 --- a/test/source/_posts/2018-01-28-closed-liquid-block-excerpt.markdown +++ b/test/source/_posts/2018-01-28-closed-liquid-block-excerpt.markdown @@ -2,10 +2,23 @@ layout: post --- -{% if - page.layout == "post" %} -You’ll find this post in your `_posts` directory. -To add new posts, simply add a file in the `_posts` directory. -{% endif %} +{% + highlight + ruby +%} +{% assign foo = 'foobar' %} +{% raw +%} +def print_hi(name) + puts "Hi, #{name}" +end +print_hi('Tom') +#=> prints 'Hi, Tom' to STDOUT. +{% + endraw +%} +{% + endhighlight +%} So let's talk business. diff --git a/test/source/_posts/2018-01-28-open-liquid-block-excerpt.markdown b/test/source/_posts/2018-01-28-open-liquid-block-excerpt.markdown index bffe45f0b7b..24c2e0eb04d 100644 --- a/test/source/_posts/2018-01-28-open-liquid-block-excerpt.markdown +++ b/test/source/_posts/2018-01-28-open-liquid-block-excerpt.markdown @@ -2,10 +2,20 @@ layout: post --- -{% if page.layout == "post" %} - You’ll find this post in your `_posts` directory. +{% + highlight + ruby +%} +{% assign foo = 'foobar' %} +{% raw +%} +def print_hi(name) + puts "Hi, #{name}" +end -{% else %} +print_hi('Tom') +#=> prints 'Hi, Tom' to STDOUT. +{% endraw %} +{% endhighlight %} - To add new posts, simply add a file in the `_posts` directory. -{% endif %} +So let's talk business. diff --git a/test/source/_posts/2018-11-15-excerpt-liquid-block.md b/test/source/_posts/2018-11-15-excerpt-liquid-block.md new file mode 100644 index 00000000000..7995d9db6a0 --- /dev/null +++ b/test/source/_posts/2018-11-15-excerpt-liquid-block.md @@ -0,0 +1,29 @@ +--- +title: liquid_block excerpt test with open tags in excerpt +layout: post +--- + +{% assign company = "Yoyodyne" %} +{% do_nothing_other %} +{% do_nothing %} + {% unless false %} + {% for i in (1..10) %} + {% if true %} + {% raw %} + EVIL! PURE AND SIMPLE FROM THE EIGHTH DIMENSION! + {% endraw %} + {% elsif false %} + No matter where you go, there you are. + {% break %} + {% else %} + {% case company %} + {% when "Yoyodyne" %} + Buckaroo Banzai + {% else %} + {% continue %} + + {% endcase %} + {% endif %} + {% endfor %} + {% endunless %} +{% enddo_nothing %} diff --git a/test/source/page_with_excerpt.md b/test/source/page_with_excerpt.md new file mode 100644 index 00000000000..4abcfa55744 --- /dev/null +++ b/test/source/page_with_excerpt.md @@ -0,0 +1,7 @@ +--- +title: I am a page with an excerpt +--- + +I am the excerpt + +I am the remainder of the page diff --git a/test/source/symlink-test/symlinked-file-outside-source b/test/source/symlink-test/symlinked-file-outside-source new file mode 120000 index 00000000000..3594e94c04d --- /dev/null +++ b/test/source/symlink-test/symlinked-file-outside-source @@ -0,0 +1 @@ +/etc/passwd \ No newline at end of file diff --git a/test/test_commands_serve.rb b/test/test_commands_serve.rb index ce9f1c65c8a..f82b7f96b2b 100644 --- a/test/test_commands_serve.rb +++ b/test/test_commands_serve.rb @@ -5,7 +5,6 @@ require "helper" require "httpclient" require "openssl" -require "thread" require "tmpdir" class TestCommandsServe < JekyllUnitTest @@ -44,6 +43,8 @@ def serve(opts) context "using LiveReload" do setup do + skip_if_windows "EventMachine support on Windows is limited" + @temp_dir = Dir.mktmpdir("jekyll_livereload_test") @destination = File.join(@temp_dir, "_site") Dir.mkdir(@destination) || flunk("Could not make directory #{@destination}") @@ -94,7 +95,6 @@ def serve(opts) end should "serve livereload.js over HTTP on the default LiveReload port" do - skip_if_windows "EventMachine support on Windows is limited" opts = serve(@standard_options) content = @client.get_content( "http://#{opts["host"]}:#{opts["livereload_port"]}/livereload.js" @@ -103,7 +103,6 @@ def serve(opts) end should "serve nothing else over HTTP on the default LiveReload port" do - skip_if_windows "EventMachine support on Windows is limited" opts = serve(@standard_options) res = @client.get("http://#{opts["host"]}:#{opts["livereload_port"]}/") assert_equal(400, res.status_code) @@ -111,7 +110,6 @@ def serve(opts) end should "insert the LiveReload script tags" do - skip_if_windows "EventMachine support on Windows is limited" opts = serve(@standard_options) content = @client.get_content( "http://#{opts["host"]}:#{opts["port"]}/#{opts["baseurl"]}/hello.html" @@ -124,7 +122,6 @@ def serve(opts) end should "apply the max and min delay options" do - skip_if_windows "EventMachine support on Windows is limited" opts = serve(@standard_options.merge( "livereload_max_delay" => "1066", "livereload_min_delay" => "3" @@ -155,9 +152,7 @@ def serve(opts) end should "label itself" do - assert_equal( - @merc.name, :serve - ) + assert_equal :serve, @merc.name end should "have aliases" do @@ -191,21 +186,21 @@ def serve(opts) end should "use user destinations" do - assert_equal "foo", custom_opts({ "destination" => "foo" })[ + assert_equal "foo", custom_opts("destination" => "foo")[ :DocumentRoot ] end should "use user port" do # WHAT?!?!1 Over 9000? That's impossible. - assert_equal 9001, custom_opts({ "port" => 9001 })[ + assert_equal 9001, custom_opts("port" => 9001)[ :Port ] end should "use empty directory index list when show_dir_listing is true" do opts = { "show_dir_listing" => true } - assert custom_opts(opts)[:DirectoryIndex].empty? + assert_empty custom_opts(opts)[:DirectoryIndex] end should "keep config between build and serve" do @@ -237,21 +232,21 @@ def serve(opts) expect(Jekyll::Commands::Serve).to receive(:start_up_webrick) end should "set the site url by default to `http://localhost:4000`" do - @merc.execute(:serve, { "watch" => false, "url" => "https://jekyllrb.com/" }) + @merc.execute(:serve, "watch" => false, "url" => "https://jekyllrb.com/") assert_equal 1, Jekyll.sites.count assert_equal "http://localhost:4000", Jekyll.sites.first.config["url"] end should "take `host`, `port` and `ssl` into consideration if set" do - @merc.execute(:serve, { + @merc.execute(:serve, "watch" => false, "host" => "example.com", "port" => "9999", "url" => "https://jekyllrb.com/", "ssl_cert" => "foo", - "ssl_key" => "bar", - }) + "ssl_key" => "bar" + ) assert_equal 1, Jekyll.sites.count assert_equal "https://example.com:9999", Jekyll.sites.first.config["url"] @@ -262,7 +257,7 @@ def serve(opts) should "not update the site url" do expect(Jekyll).to receive(:env).and_return("production") expect(Jekyll::Commands::Serve).to receive(:start_up_webrick) - @merc.execute(:serve, { "watch" => false, "url" => "https://jekyllrb.com/" }) + @merc.execute(:serve, "watch" => false, "url" => "https://jekyllrb.com/") assert_equal 1, Jekyll.sites.count assert_equal "https://jekyllrb.com/", Jekyll.sites.first.config["url"] @@ -271,26 +266,26 @@ def serve(opts) context "verbose" do should "debug when verbose" do - assert_equal custom_opts({ "verbose" => true })[:Logger].level, 5 + assert_equal 5, custom_opts("verbose" => true)[:Logger].level end should "warn when not verbose" do - assert_equal custom_opts({})[:Logger].level, 3 + assert_equal 3, custom_opts({})[:Logger].level end end context "enabling SSL" do should "raise if enabling without key or cert" do assert_raises RuntimeError do - custom_opts({ - "ssl_key" => "foo", - }) + custom_opts( + "ssl_key" => "foo" + ) end assert_raises RuntimeError do - custom_opts({ - "ssl_key" => "foo", - }) + custom_opts( + "ssl_key" => "foo" + ) end end @@ -299,16 +294,16 @@ def serve(opts) expect(OpenSSL::X509::Certificate).to receive(:new).and_return("c1") allow(File).to receive(:read).and_return("foo") - result = custom_opts({ + result = custom_opts( "ssl_cert" => "foo", "source" => "bar", "enable_ssl" => true, - "ssl_key" => "bar", - }) + "ssl_key" => "bar" + ) assert result[:SSLEnable] - assert_equal result[:SSLPrivateKey], "c2" - assert_equal result[:SSLCertificate], "c1" + assert_equal "c2", result[:SSLPrivateKey] + assert_equal "c1", result[:SSLCertificate] end end end @@ -317,7 +312,7 @@ def serve(opts) allow(Jekyll::Commands::Serve).to receive(:start_up_webrick) expect(Jekyll).to receive(:configuration).once.and_call_original - @merc.execute(:serve, { "watch" => false }) + @merc.execute(:serve, "watch" => false) end end end diff --git a/test/test_entry_filter.rb b/test/test_entry_filter.rb index c9025092318..aa600f81ec9 100644 --- a/test/test_entry_filter.rb +++ b/test/test_entry_filter.rb @@ -5,7 +5,7 @@ class TestEntryFilter < JekyllUnitTest context "Filtering entries" do setup do - @site = Site.new(site_configuration) + @site = fixture_site end should "filter entries" do @@ -87,7 +87,7 @@ class TestEntryFilter < JekyllUnitTest # no support for symlinks on Windows skip_if_windows "Jekyll does not currently support symlinks on Windows." - site = Site.new(site_configuration("safe" => true)) + site = fixture_site("safe" => true) site.reader.read_directories("symlink-test") assert_equal %w(main.scss symlinked-file).length, site.pages.length @@ -99,11 +99,22 @@ class TestEntryFilter < JekyllUnitTest # no support for symlinks on Windows skip_if_windows "Jekyll does not currently support symlinks on Windows." - site = Site.new(site_configuration) + @site.reader.read_directories("symlink-test") + refute_equal [], @site.pages + refute_equal [], @site.static_files + end + + should "include only safe symlinks in safe mode even when included" do + # no support for symlinks on Windows + skip_if_windows "Jekyll does not currently support symlinks on Windows." + site = fixture_site("safe" => true, "include" => ["symlinked-file-outside-source"]) site.reader.read_directories("symlink-test") - refute_equal [], site.pages - refute_equal [], site.static_files + + # rubocop:disable Performance/FixedSize + assert_equal %w(main.scss symlinked-file).length, site.pages.length + refute_includes site.static_files.map(&:name), "symlinked-file-outside-source" + # rubocop:enable Performance/FixedSize end end diff --git a/test/test_excerpt.rb b/test/test_excerpt.rb index 24647decada..97cc4524549 100644 --- a/test/test_excerpt.rb +++ b/test/test_excerpt.rb @@ -10,6 +10,10 @@ def setup_post(file) }).tap(&:read) end + def setup_page + Page.new(@site, @site.in_source_dir, "", "page_with_excerpt.md") + end + def do_render(document) @site.layouts = { "default" => Layout.new(@site, source_dir("_layouts"), "simple.html"), @@ -185,12 +189,17 @@ def do_render(document) @post = setup_post("2018-01-28-open-liquid-block-excerpt.markdown") @excerpt = @post.data["excerpt"] - assert_includes @post.content, "{% if" - refute_includes @post.content.split("\n\n")[0], "{% endif %}" + head = @post.content.split("\n\n")[0] + + assert_includes @post.content, "{%\n highlight\n" + assert_includes @post.content, "{% raw" + refute_includes head, "{% endraw %}" + refute_includes head, "{% endhighlight %}" end should "be appended to as necessary and generated" do - assert_includes @excerpt.content, "{% endif %}" + assert_includes @excerpt.content, "{% endraw %}" + assert_includes @excerpt.content, "{% endhighlight %}" assert_equal true, @excerpt.is_a?(Jekyll::Excerpt) end end @@ -202,13 +211,19 @@ def do_render(document) @post = setup_post("2018-01-28-closed-liquid-block-excerpt.markdown") @excerpt = @post.data["excerpt"] - assert_includes @post.content, "{% if" - assert_includes @post.content.split("\n\n")[0], "{% endif %}" + head = @post.content.split("\n\n")[0] + + assert_includes @post.content, "{%\n highlight\n" + assert_includes @post.content, "{% raw" + assert_includes head, "{%\n endraw\n%}" + assert_includes head, "{%\n endhighlight\n%}" end should "not be appended to but generated as is" do - assert_includes @excerpt.content, "{% endif %}" - refute_includes @excerpt.content, "{% endif %}\n\n{% endif %}" + assert_includes @excerpt.content, "{%\n endraw\n%}" + assert_includes @excerpt.content, "{%\n endhighlight\n%}" + refute_includes @excerpt.content, "{%\n endraw\n%}\n\n{% endraw %}" + refute_includes @excerpt.content, "{%\n endhighlight\n%}\n\n{% endhighlight %}" assert_equal true, @excerpt.is_a?(Jekyll::Excerpt) end end @@ -264,4 +279,43 @@ def do_render(document) assert_equal true, @excerpt.is_a?(Jekyll::Excerpt) end end + + context "An excerpt with Liquid tags" do + setup do + clear_dest + @site = fixture_site + @post = setup_post("2018-11-15-excerpt-liquid-block.md") + @excerpt = @post.data["excerpt"] + + assert_includes @post.content.split("\n\n")[0].strip, "{% continue %}" + assert_equal true, Jekyll::DoNothingBlock.ancestors.include?(Liquid::Block) + assert_equal false, Jekyll::DoNothingOther.ancestors.include?(Liquid::Block) + assert_match "Jekyll::DoNothingBlock", Liquid::Template.tags["do_nothing"].name + assert_match "Jekyll::DoNothingOther", Liquid::Template.tags["do_nothing_other"].name + end + + should "close open block tags, including custom tags, and ignore others" do + assert_includes @excerpt.content, "{% endcase %}" + assert_includes @excerpt.content, "{% endif %}" + assert_includes @excerpt.content, "{% endfor %}" + assert_includes @excerpt.content, "{% endunless %}" + assert_includes @excerpt.content, "{% enddo_nothing %}" + refute_includes @excerpt.content, "{% enddo_nothing_other %}" + assert_equal true, @excerpt.is_a?(Jekyll::Excerpt) + end + end + + context "On a page" do + setup do + clear_dest + @site = fixture_site + @page = setup_page + @excerpt = Jekyll::Excerpt.new(@page) + end + + + should "produce a proper excerpt" do + assert_equal @excerpt.content, "I am the excerpt\n\n" + end + end end diff --git a/test/test_filters.rb b/test/test_filters.rb index a3dd142ad3e..2045bd602f7 100644 --- a/test/test_filters.rb +++ b/test/test_filters.rb @@ -809,7 +809,7 @@ def to_liquid "The list of grouped items for '' is not an Array." ) # adjust array.size to ignore symlinked page in Windows - qty = Utils::Platforms.really_windows? ? 14 : 15 + qty = Utils::Platforms.really_windows? ? 15 : 16 assert_equal qty, g["items"].size end end @@ -1007,7 +1007,7 @@ def to_liquid "The list of grouped items for '' is not an Array." ) # adjust array.size to ignore symlinked page in Windows - qty = Utils::Platforms.really_windows? ? 14 : 15 + qty = Utils::Platforms.really_windows? ? 15 : 16 assert_equal qty, g["items"].size end end diff --git a/test/test_generated_site.rb b/test/test_generated_site.rb index 7ce093536ff..2c03046b229 100644 --- a/test/test_generated_site.rb +++ b/test/test_generated_site.rb @@ -11,12 +11,12 @@ class TestGeneratedSite < JekyllUnitTest @site.process @index = File.read( dest_dir("index.html"), - Utils.merged_file_read_opts(@site, {}) + **Utils.merged_file_read_opts(@site, {}) ) end should "ensure post count is as expected" do - assert_equal 57, @site.posts.size + assert_equal 58, @site.posts.size end should "insert site.posts into the index" do diff --git a/test/test_kramdown.rb b/test/test_kramdown.rb index f68bb17ce78..47deaed4f82 100644 --- a/test/test_kramdown.rb +++ b/test/test_kramdown.rb @@ -3,10 +3,17 @@ require "helper" class TestKramdown < JekyllUnitTest + def fixture_converter(config) + site_config = Utils.deep_merge_hashes({ "markdown" => "kramdown" }, config) + site = fixture_site(site_config) + converter = site.find_converter_instance(Jekyll::Converters::Markdown) + converter.setup + converter + end + context "kramdown" do setup do @config = { - "markdown" => "kramdown", "kramdown" => { "smart_quotes" => "lsquo,rsquo,ldquo,rdquo", "entity_output" => "as_char", @@ -29,12 +36,11 @@ class TestKramdown < JekyllUnitTest @config["kramdown"]["syntax_highlighter_opts"].keys @config = Jekyll.configuration(@config) - @markdown = Converters::Markdown.new(@config) - @markdown.setup + @converter = fixture_converter(@config) end should "fill symbolized keys into config for compatibility with kramdown" do - kramdown_config = @markdown.instance_variable_get(:@parser) + kramdown_config = @converter.instance_variable_get(:@parser) .instance_variable_get(:@config) @kramdown_config_keys.each do |key| @@ -54,20 +60,70 @@ class TestKramdown < JekyllUnitTest end should "run Kramdown" do - assert_equal "

Some Header

", @markdown.convert("# Some Header #").strip + assert_equal "

Some Header

", @converter.convert("# Some Header #").strip end should "should log kramdown warnings" do allow_any_instance_of(Kramdown::Document).to receive(:warnings).and_return(["foo"]) expect(Jekyll.logger).to receive(:warn).with("Kramdown warning:", "foo") - @markdown.convert("Something") + @converter.convert("Something") + end + + should "render fenced code blocks with syntax highlighting" do + result = nokogiri_fragment(@converter.convert(<<~MARKDOWN)) + ~~~ruby + puts "Hello World" + ~~~ + MARKDOWN + div_highlight = Rouge.version.to_i == 1 ? "" : ">div.highlight" + selector = "div.highlighter-rouge#{div_highlight}>pre.highlight>code" + refute(result.css(selector).empty?, result.to_html) + end + + context "when configured" do + setup do + @source = <<~TEXT + ## Code Sample + + def ruby_fu + "Hello" + end + TEXT + end + + should "have 'plaintext' as the default syntax_highlighter language" do + converter = fixture_converter(@config) + parser = converter.instance_variable_get(:@parser) + parser_config = parser.instance_variable_get(:@config) + + assert_equal "plaintext", parser_config.dig("syntax_highlighter_opts", "default_lang") + end + + should "accept the specified default syntax_highlighter language" do + override = { + "kramdown" => { + "syntax_highlighter_opts" => { + "default_lang" => "yaml", + }, + }, + } + converter = fixture_converter(Utils.deep_merge_hashes(@config, override)) + parser = converter.instance_variable_get(:@parser) + parser_config = parser.instance_variable_get(:@config) + + assert_equal "yaml", parser_config.dig("syntax_highlighter_opts", "default_lang") + refute_match %r!
(“|“)Pit(’|’)hy(”|”)<\/p>!, - @markdown.convert(%("Pit'hy")).strip + converter.convert(%("Pit'hy")).strip ) end @@ -78,37 +134,23 @@ class TestKramdown < JekyllUnitTest "smart_quotes" => "lsaquo,rsaquo,laquo,raquo", }, } - - markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, override)) + converter = fixture_converter(Utils.deep_merge_hashes(@config, override)) assert_match %r!

(«|«)Pit(›|›)hy(»|»)<\/p>!, \ - markdown.convert(%("Pit'hy")).strip + converter.convert(%("Pit'hy")).strip end end - should "render fenced code blocks with syntax highlighting" do - result = nokogiri_fragment(@markdown.convert(Utils.strip_heredoc(<<-MARKDOWN))) - ~~~ruby - puts "Hello World" - ~~~ - MARKDOWN - div_highlight = "" - div_highlight = ">div.highlight" unless Utils::Rouge.old_api? - selector = "div.highlighter-rouge#{div_highlight}>pre.highlight>code" - refute result.css(selector).empty? - end - context "when a custom highlighter is chosen" do should "use the chosen highlighter if it's available" do override = { "highlighter" => nil, - "markdown" => "kramdown", "kramdown" => { - "syntax_highlighter" => :coderay, + "syntax_highlighter" => "coderay", }, } - markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, override)) - result = nokogiri_fragment(markdown.convert(Utils.strip_heredoc(<<-MARKDOWN))) + converter = fixture_converter(Utils.deep_merge_hashes(@config, override)) + result = nokogiri_fragment(converter.convert(<<~MARKDOWN)) ~~~ruby puts "Hello World" ~~~ @@ -120,7 +162,6 @@ class TestKramdown < JekyllUnitTest should "support legacy enable_coderay... for now" do override = { - "markdown" => "kramdown", "kramdown" => { "enable_coderay" => true, }, @@ -128,8 +169,9 @@ class TestKramdown < JekyllUnitTest @config.delete("highlighter") @config["kramdown"].delete("syntax_highlighter") - markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, override)) - result = nokogiri_fragment(markdown.convert(Utils.strip_heredoc(<<-MARKDOWN))) + + converter = fixture_converter(Utils.deep_merge_hashes(@config, override)) + result = nokogiri_fragment(converter.convert(<<~MARKDOWN)) ~~~ruby puts "Hello World" ~~~ @@ -141,24 +183,26 @@ class TestKramdown < JekyllUnitTest end should "move coderay to syntax_highlighter_opts" do - original = Kramdown::Document.method(:new) - markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, { + override = { "higlighter" => nil, - "markdown" => "kramdown", "kramdown" => { "syntax_highlighter" => "coderay", "coderay" => { "hello" => "world", }, }, - })) + } + original = Kramdown::Document.method(:new) + converter = fixture_converter( + Utils.deep_merge_hashes(@config, override) + ) expect(Kramdown::Document).to receive(:new) do |arg1, hash| assert_equal hash["syntax_highlighter_opts"]["hello"], "world" original.call(arg1, hash) end - markdown.convert("hello world") + converter.convert("hello world") end end end diff --git a/test/test_layout_reader.rb b/test/test_layout_reader.rb index 96d2045a148..805bbac8747 100644 --- a/test/test_layout_reader.rb +++ b/test/test_layout_reader.rb @@ -31,5 +31,52 @@ class TestLayoutReader < JekyllUnitTest assert_equal LayoutReader.new(@site).layout_directory, source_dir("blah/_layouts") end end + + context "when a layout is a symlink" do + setup do + symlink_if_allowed("/etc/passwd", source_dir("_layouts", "symlink.html")) + + @site = fixture_site( + "safe" => true, + "include" => ["symlink.html"] + ) + end + + teardown do + FileUtils.rm_f(source_dir("_layouts", "symlink.html")) + end + + should "only read the layouts which are in the site" do + skip_if_windows "Jekyll does not currently support symlinks on Windows." + + layouts = LayoutReader.new(@site).read + + refute layouts.key?("symlink"), "Should not read the symlinked layout" + end + end + + context "with a theme" do + setup do + symlink_if_allowed("/etc/passwd", theme_dir("_layouts", "theme-symlink.html")) + @site = fixture_site( + "include" => ["theme-symlink.html"], + "theme" => "test-theme", + "safe" => true + ) + end + + teardown do + FileUtils.rm_f(theme_dir("_layouts", "theme-symlink.html")) + end + + should "not read a symlink'd theme" do + skip_if_windows "Jekyll does not currently support symlinks on Windows." + + layouts = LayoutReader.new(@site).read + + refute layouts.key?("theme-symlink"), \ + "Should not read symlinked layout from theme" + end + end end end diff --git a/test/test_rdiscount.rb b/test/test_rdiscount.rb index 7116c29a238..796ee81dda6 100644 --- a/test/test_rdiscount.rb +++ b/test/test_rdiscount.rb @@ -28,16 +28,16 @@ class TestRdiscount < JekyllUnitTest should "render toc" do toc = <<-TOC - +

Header 1

- +

Header 2

diff --git a/test/test_redcarpet.rb b/test/test_redcarpet.rb index 51da49c58e4..ae7c88fa63b 100644 --- a/test/test_redcarpet.rb +++ b/test/test_redcarpet.rb @@ -47,6 +47,9 @@ class TestRedcarpet < JekyllUnitTest context "with pygments enabled" do setup do + unless system("command", "-v", "python") + skip "Skipping as 'python' is not available" + end @markdown = Converters::Markdown.new @config.merge( { "highlighter" => "pygments" } ) diff --git a/test/test_site.rb b/test/test_site.rb index 0af32fcbeb6..a5419b6bdff 100644 --- a/test/test_site.rb +++ b/test/test_site.rb @@ -231,6 +231,7 @@ def generate(site) index.html info.md main.scss + page_with_excerpt.md properties.html sitemap.xml static_files.html diff --git a/test/test_tags.rb b/test/test_tags.rb index ae75c0245e4..8a41914569c 100644 --- a/test/test_tags.rb +++ b/test/test_tags.rb @@ -167,10 +167,10 @@ def highlight_block_with_opts(options_string) context "with the pygments highlighter" do setup do - if jruby? - then skip( - "JRuby does not support Pygments." - ) + skip("JRuby does not support Pygments.") if jruby? + + unless system("command", "-v", "python") + skip "Skipping as 'python' is not available" end end @@ -329,7 +329,7 @@ def highlight_block_with_opts(options_string) %() + %() + - %() + + %() + %(
) + %(
1\n
test
test\n
), @result ) @@ -476,7 +476,7 @@ def highlight_block_with_opts(options_string) expected = <<-EOS

This is not yet highlighted

\n
1
-
test
\n +
test\n
\n

This should not be highlighted, right?

EOS assert_match(expected, @result) @@ -1093,6 +1093,49 @@ def highlight_block_with_opts(options_string) end end + context "with include file with special characters without params" do + setup do + content = <<~CONTENT + --- + title: special characters + --- + + {% include params@2.0.html %} + CONTENT + create_post(content, + "permalink" => "pretty", + "source" => source_dir, + "destination" => dest_dir, + "read_posts" => true) + end + + should "include file with empty parameters" do + assert_match "", @result + end + end + + context "with include file with special characters with params" do + setup do + content = <<~CONTENT + --- + title: special characters + --- + + {% include params@2.0.html param1="foobar" param2="bazbar" %} + CONTENT + create_post(content, + "permalink" => "pretty", + "source" => source_dir, + "destination" => dest_dir, + "read_posts" => true) + end + + should "include file with empty parameters" do + assert_match "
  • param1 = foobar
  • ", @result + assert_match "
  • param2 = bazbar
  • ", @result + end + end + context "with custom includes directory" do setup do content = < "test-theme-symlink", + "theme-color" => "black" + ) + ThemeAssetsReader.new(site).read + + assert_empty site.static_files, "static file should not have been picked up" + ensure + FileUtils.rm_rf(tmp_dir) + FileUtils.rm_rf(File.join(theme_dir, "assets")) + end + end + end end diff --git a/test/test_win_tz.rb b/test/test_win_tz.rb new file mode 100644 index 00000000000..5e7eb896769 --- /dev/null +++ b/test/test_win_tz.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require "helper" + +class TestWinTz < JekyllUnitTest + [["America/New_York", "WTZ+05:00"], ["Europe/Paris", "WTZ-01:00"]].each do |tz, expected| + should "use base offset in winter for #{tz}" do + result = Jekyll::Utils::WinTZ.calculate(tz, Time.utc(2021, 1, 1)) + assert_equal expected, result + end + end + + [["America/New_York", "WTZ+04:00"], ["Europe/Paris", "WTZ-02:00"]].each do |tz, expected| + should "apply DST in summer for #{tz}" do + result = Jekyll::Utils::WinTZ.calculate(tz, Time.utc(2021, 7, 1)) + assert_equal expected, result + end + end + + [["Australia/Eucla", "WTZ-08:45"], ["Pacific/Marquesas", "WTZ+09:30"]].each do |tz, expected| + should "handle non zero minutes for #{tz}" do + result = Jekyll::Utils::WinTZ.calculate(tz, Time.utc(2021, 1, 1)) + assert_equal expected, result + end + end + + should "return zero for UTC" do + result = Jekyll::Utils::WinTZ.calculate("UTC") + assert_equal "WTZ+00:00", result + end +end