diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e83dfeb3df..faac4b06cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0 - name: Set up Ruby - uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0 + uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1.288.0 with: bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Run tests diff --git a/.github/workflows/schedule-doc-report.yml b/.github/workflows/schedule-doc-report.yml index f5d1eb1213..b642089ec6 100644 --- a/.github/workflows/schedule-doc-report.yml +++ b/.github/workflows/schedule-doc-report.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0 - name: Set up Ruby - uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0 + uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1.288.0 with: bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Generate report diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 953d3e0256..555b6a0c78 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Set up Ruby - uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0 + uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1.288.0 with: bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Run tests diff --git a/.ruby-version b/.ruby-version index 2aa5131992..7921bd0c89 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.4.7 +3.4.8 diff --git a/.tool-versions b/.tool-versions index 3f03c7a73d..58766197c0 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -ruby 3.4.7 +ruby 3.4.8 diff --git a/COPYRIGHT b/COPYRIGHT index 374054bdbf..ad89869379 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,4 +1,4 @@ -Copyright 2013-2025 Thibaut Courouble and other contributors +Copyright 2013-2026 Thibaut Courouble and other contributors This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/Gemfile b/Gemfile index 9893bb5774..c2a38a7a71 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source 'https://rubygems.org' -ruby '3.4.7' +ruby '3.4.8' gem 'activesupport', require: false gem 'html-pipeline' diff --git a/Gemfile.lock b/Gemfile.lock index 0dc3ed1f8e..6d257a9e4e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -191,7 +191,7 @@ DEPENDENCIES yajl-ruby RUBY VERSION - ruby 3.4.7p58 + ruby 3.4.8p72 BUNDLED WITH 2.4.6 diff --git a/README.md b/README.md index fcdb677d84..cf6c735a76 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ Made something cool? Feel free to open a PR to add a new row to this table! You ## Copyright / License -Copyright 2013–2025 Thibaut Courouble and [other contributors](https://github.com/freeCodeCamp/devdocs/graphs/contributors) +Copyright 2013–2026 Thibaut Courouble and [other contributors](https://github.com/freeCodeCamp/devdocs/graphs/contributors) This software is licensed under the terms of the Mozilla Public License v2.0. See the [COPYRIGHT](./COPYRIGHT) and [LICENSE](./LICENSE) files. diff --git a/assets/javascripts/lib/license.js b/assets/javascripts/lib/license.js index 15b42c98f4..e4c3c0103a 100644 --- a/assets/javascripts/lib/license.js +++ b/assets/javascripts/lib/license.js @@ -1,5 +1,5 @@ /* - * Copyright 2013-2025 Thibaut Courouble and other contributors + * Copyright 2013-2026 Thibaut Courouble and other contributors * * This source code is licensed under the terms of the Mozilla * Public License, v. 2.0, a copy of which may be obtained at: diff --git a/assets/javascripts/news.json b/assets/javascripts/news.json index 1f821abae4..8db945d488 100644 --- a/assets/javascripts/news.json +++ b/assets/javascripts/news.json @@ -1,4 +1,8 @@ [ + [ + "2026-02-14", + "New documentation: CouchDB" + ], [ "2025-10-19", "New documentations: Lit, Graphviz, Bun" diff --git a/assets/javascripts/templates/pages/about_tmpl.js b/assets/javascripts/templates/pages/about_tmpl.js index e3142da5fc..d8780005e6 100644 --- a/assets/javascripts/templates/pages/about_tmpl.js +++ b/assets/javascripts/templates/pages/about_tmpl.js @@ -32,7 +32,7 @@ app.templates.aboutPage = function () {

- Copyright 2013–2025 Thibaut Courouble and other contributors
+ Copyright 2013–2026 Thibaut Courouble and other contributors
This software is licensed under the terms of the Mozilla Public License v2.0.
You may obtain a copy of the source code at github.com/freeCodeCamp/devdocs.
For more information, see the COPYRIGHT diff --git a/assets/stylesheets/application.css.scss b/assets/stylesheets/application.css.scss index 12247d4405..289867076a 100644 --- a/assets/stylesheets/application.css.scss +++ b/assets/stylesheets/application.css.scss @@ -3,7 +3,7 @@ //= depend_on sprites/docs.json /*! - * Copyright 2013-2025 Thibaut Courouble and other contributors + * Copyright 2013-2026 Thibaut Courouble and other contributors * * This source code is licensed under the terms of the Mozilla * Public License, v. 2.0, a copy of which may be obtained at: diff --git a/assets/stylesheets/components/_environment.scss b/assets/stylesheets/components/_environment.scss new file mode 100644 index 0000000000..d994d69378 --- /dev/null +++ b/assets/stylesheets/components/_environment.scss @@ -0,0 +1,3 @@ +._hide-in-development { + +} diff --git a/assets/stylesheets/global/_icons.scss b/assets/stylesheets/global/_icons.scss new file mode 100644 index 0000000000..4f7476a375 --- /dev/null +++ b/assets/stylesheets/global/_icons.scss @@ -0,0 +1,32 @@ + + +%svg-icon { + display: inline-block; + vertical-align: top; + width: 1rem; + height: 1rem; + pointer-events: none; + fill: currentColor; +} + +%doc-icon { + content: ''; + display: block; + width: 1rem; + height: 1rem; + background-image: image-url('sprites/docs.png'); + background-size: 15rem 15rem; +} + +@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) { + %doc-icon { background-image: image-url('sprites/docs@2x.png'); } +} + +html._theme-dark { + %darkIconFix { + filter: invert(100%) grayscale(100%); + -webkit-filter: invert(100%) grayscale(100%); + } +} + +._icon-angular:before { background-position: -0rem -0rem; }._icon-angularjs:before { background-position: -1rem -0rem; }._icon-ansible:before { background-position: -2rem -0rem; }._icon-apache_http_server:before { background-position: -3rem -0rem; @extend %darkIconFix !optional; }._icon-apache_pig:before { background-position: -4rem -0rem; }._icon-astro:before { background-position: -5rem -0rem; @extend %darkIconFix !optional; }._icon-async:before { background-position: -6rem -0rem; }._icon-axios:before { background-position: -7rem -0rem; }._icon-babel:before { background-position: -8rem -0rem; }._icon-backbone:before { background-position: -9rem -0rem; @extend %darkIconFix !optional; }._icon-bash:before { background-position: -10rem -0rem; }._icon-bazel:before { background-position: -11rem -0rem; }._icon-bluebird:before { background-position: -12rem -0rem; }._icon-bootstrap:before { background-position: -13rem -0rem; }._icon-bottle:before { background-position: -14rem -0rem; }._icon-bower:before { background-position: -0rem -1rem; }._icon-bun:before { background-position: -1rem -1rem; }._icon-c:before { background-position: -2rem -1rem; }._icon-cpp:before { background-position: -3rem -1rem; }._icon-cakephp:before { background-position: -4rem -1rem; }._icon-chai:before { background-position: -5rem -1rem; }._icon-chef:before { background-position: -6rem -1rem; }._icon-click:before { background-position: -7rem -1rem; @extend %darkIconFix !optional; }._icon-clojure:before { background-position: -8rem -1rem; }._icon-cmake:before { background-position: -9rem -1rem; }._icon-codeception:before { background-position: -10rem -1rem; }._icon-codeceptjs:before { background-position: -11rem -1rem; }._icon-codeigniter:before { background-position: -12rem -1rem; }._icon-coffeescript:before { background-position: -13rem -1rem; @extend %darkIconFix !optional; }._icon-composer:before { background-position: -14rem -1rem; }._icon-cordova:before { background-position: -0rem -2rem; }._icon-crystal:before { background-position: -1rem -2rem; @extend %darkIconFix !optional; }._icon-css:before { background-position: -2rem -2rem; }._icon-cypress:before { background-position: -3rem -2rem; }._icon-d:before { background-position: -4rem -2rem; }._icon-d3:before { background-position: -5rem -2rem; }._icon-dart:before { background-position: -6rem -2rem; }._icon-date_fns:before { background-position: -7rem -2rem; @extend %darkIconFix !optional; }._icon-deno:before { background-position: -8rem -2rem; }._icon-django:before { background-position: -9rem -2rem; }._icon-django_rest_framework:before { background-position: -10rem -2rem; @extend %darkIconFix !optional; }._icon-docker:before { background-position: -11rem -2rem; }._icon-dojo:before { background-position: -12rem -2rem; }._icon-drupal:before { background-position: -13rem -2rem; }._icon-duckdb:before { background-position: -14rem -2rem; }._icon-eigen3:before { background-position: -0rem -3rem; @extend %darkIconFix !optional; }._icon-electron:before { background-position: -1rem -3rem; }._icon-elisp:before { background-position: -2rem -3rem; }._icon-elixir:before { background-position: -3rem -3rem; }._icon-ember:before { background-position: -4rem -3rem; }._icon-enzyme:before { background-position: -0rem -8rem; }._icon-erlang:before { background-position: -5rem -3rem; }._icon-es_toolkit:before { background-position: -6rem -3rem; }._icon-esbuild:before { background-position: -7rem -3rem; }._icon-eslint:before { background-position: -8rem -3rem; }._icon-express:before { background-position: -9rem -3rem; }._icon-falcon:before { background-position: -10rem -3rem; }._icon-fastapi:before { background-position: -11rem -3rem; @extend %darkIconFix !optional; }._icon-fish:before { background-position: -12rem -3rem; }._icon-flask:before { background-position: -13rem -3rem; }._icon-flow:before { background-position: -14rem -3rem; }._icon-fluture:before { background-position: -0rem -4rem; }._icon-gcc:before { background-position: -1rem -4rem; }._icon-git:before { background-position: -2rem -4rem; }._icon-gnu_fortran:before { background-position: -3rem -4rem; }._icon-gnu_make:before { background-position: -4rem -4rem; @extend %darkIconFix !optional; }._icon-gnu_cobol:before { background-position: -5rem -4rem; @extend %darkIconFix !optional; }._icon-gnuplot:before { background-position: -6rem -4rem; }._icon-go:before { background-position: -7rem -4rem; }._icon-godot:before { background-position: -8rem -4rem; }._icon-graphite:before { background-position: -0rem -8rem; }._icon-graphviz:before { background-position: -9rem -4rem; @extend %darkIconFix !optional; }._icon-groovy:before { background-position: -10rem -4rem; }._icon-grunt:before { background-position: -11rem -4rem; }._icon-gtk:before { background-position: -12rem -4rem; }._icon-hammerspoon:before { background-position: -13rem -4rem; }._icon-handlebars:before { background-position: -14rem -4rem; @extend %darkIconFix !optional; }._icon-hapi:before { background-position: -0rem -5rem; }._icon-haproxy:before { background-position: -1rem -5rem; }._icon-haskell:before { background-position: -2rem -5rem; @extend %darkIconFix !optional; }._icon-haxe:before { background-position: -3rem -5rem; }._icon-homebrew:before { background-position: -4rem -5rem; }._icon-html:before { background-position: -5rem -5rem; }._icon-htmx:before { background-position: -6rem -5rem; @extend %darkIconFix !optional; }._icon-http:before { background-position: -7rem -5rem; }._icon-i3:before { background-position: -8rem -5rem; }._icon-immutable:before { background-position: -9rem -5rem; @extend %darkIconFix !optional; }._icon-influxdata:before { background-position: -10rem -5rem; @extend %darkIconFix !optional; }._icon-jasmine:before { background-position: -11rem -5rem; }._icon-javascript:before { background-position: -12rem -5rem; }._icon-jekyll:before { background-position: -13rem -5rem; }._icon-jest:before { background-position: -14rem -5rem; }._icon-jinja:before { background-position: -0rem -6rem; @extend %darkIconFix !optional; }._icon-joi:before { background-position: -1rem -6rem; @extend %darkIconFix !optional; }._icon-jq:before { background-position: -2rem -6rem; @extend %darkIconFix !optional; }._icon-jquery:before { background-position: -3rem -6rem; }._icon-jquerymobile:before { background-position: -4rem -6rem; }._icon-jqueryui:before { background-position: -5rem -6rem; }._icon-jsdoc:before { background-position: -0rem -8rem; }._icon-julia:before { background-position: -6rem -6rem; @extend %darkIconFix !optional; }._icon-knockout:before { background-position: -7rem -6rem; }._icon-koa:before { background-position: -0rem -8rem; }._icon-kotlin:before { background-position: -8rem -6rem; }._icon-kubectl:before { background-position: -9rem -6rem; @extend %darkIconFix !optional; }._icon-kubernetes:before { background-position: -10rem -6rem; }._icon-laravel:before { background-position: -11rem -6rem; }._icon-latex:before { background-position: -12rem -6rem; @extend %darkIconFix !optional; }._icon-leaflet:before { background-position: -13rem -6rem; }._icon-less:before { background-position: -14rem -6rem; }._icon-man:before { background-position: -0rem -7rem; }._icon-liquid:before { background-position: -1rem -7rem; }._icon-lit:before { background-position: -2rem -7rem; }._icon-lodash:before { background-position: -3rem -7rem; }._icon-lua:before { background-position: -4rem -7rem; @extend %darkIconFix !optional; }._icon-love:before { background-position: -5rem -7rem; }._icon-mariadb:before { background-position: -6rem -7rem; }._icon-marionette:before { background-position: -7rem -7rem; }._icon-markdown:before { background-position: -8rem -7rem; @extend %darkIconFix !optional; }._icon-matplotlib:before { background-position: -9rem -7rem; }._icon-meteor:before { background-position: -10rem -7rem; @extend %darkIconFix !optional; }._icon-mocha:before { background-position: -11rem -7rem; }._icon-modernizr:before { background-position: -12rem -7rem; }._icon-moment:before { background-position: -13rem -7rem; @extend %darkIconFix !optional; }._icon-moment_timezone:before { background-position: -14rem -7rem; }._icon-mongoose:before { background-position: -0rem -8rem; }._icon-nextjs:before { background-position: -1rem -8rem; @extend %darkIconFix !optional; }._icon-nginx:before { background-position: -2rem -8rem; }._icon-nginx_lua_module:before { background-position: -0rem -8rem; }._icon-nim:before { background-position: -3rem -8rem; @extend %darkIconFix !optional; }._icon-nix:before { background-position: -4rem -8rem; }._icon-node:before { background-position: -5rem -8rem; }._icon-nokogiri:before { background-position: -6rem -8rem; @extend %darkIconFix !optional; }._icon-npm:before { background-position: -7rem -8rem; }._icon-numpy:before { background-position: -8rem -8rem; }._icon-nushell:before { background-position: -9rem -8rem; }._icon-ocaml:before { background-position: -10rem -8rem; }._icon-octave:before { background-position: -11rem -8rem; }._icon-opengl:before { background-position: -12rem -8rem; }._icon-openjdk:before { background-position: -13rem -8rem; }._icon-openlayers:before { background-position: -14rem -8rem; }._icon-opentsdb:before { background-position: -0rem -9rem; }._icon-padrino:before { background-position: -1rem -9rem; }._icon-pandas:before { background-position: -2rem -9rem; @extend %darkIconFix !optional; }._icon-perl:before { background-position: -3rem -9rem; }._icon-phalcon:before { background-position: -4rem -9rem; }._icon-phaser:before { background-position: -5rem -9rem; }._icon-phoenix:before { background-position: -6rem -9rem; }._icon-php:before { background-position: -7rem -9rem; }._icon-phpunit:before { background-position: -8rem -9rem; }._icon-playwright:before { background-position: -9rem -9rem; }._icon-point_cloud_library:before { background-position: -10rem -9rem; }._icon-pony:before { background-position: -11rem -9rem; }._icon-postgresql:before { background-position: -12rem -9rem; }._icon-prettier:before { background-position: -13rem -9rem; @extend %darkIconFix !optional; }._icon-pug:before { background-position: -14rem -9rem; }._icon-puppeteer:before { background-position: -0rem -10rem; }._icon-pygame:before { background-position: -1rem -10rem; }._icon-python:before { background-position: -2rem -10rem; }._icon-pytorch:before { background-position: -3rem -10rem; }._icon-q:before { background-position: -4rem -10rem; }._icon-qt:before { background-position: -5rem -10rem; }._icon-qunit:before { background-position: -6rem -10rem; }._icon-r:before { background-position: -7rem -10rem; }._icon-ramda:before { background-position: -8rem -10rem; @extend %darkIconFix !optional; }._icon-react:before { background-position: -9rem -10rem; }._icon-react_bootstrap:before { background-position: -10rem -10rem; }._icon-react_native:before { background-position: -11rem -10rem; }._icon-react_router:before { background-position: -12rem -10rem; @extend %darkIconFix !optional; }._icon-reactivex:before { background-position: -13rem -10rem; }._icon-redis:before { background-position: -14rem -10rem; }._icon-redux:before { background-position: -0rem -11rem; @extend %darkIconFix !optional; }._icon-relay:before { background-position: -1rem -11rem; }._icon-requests:before { background-position: -2rem -11rem; }._icon-requirejs:before { background-position: -3rem -11rem; }._icon-rethinkdb:before { background-position: -4rem -11rem; }._icon-ruby:before { background-position: -5rem -11rem; }._icon-minitest:before { background-position: -0rem -8rem; }._icon-rails:before { background-position: -6rem -11rem; }._icon-rust:before { background-position: -7rem -11rem; @extend %darkIconFix !optional; }._icon-rxjs:before { background-position: -8rem -11rem; }._icon-saltstack:before { background-position: -9rem -11rem; @extend %darkIconFix !optional; }._icon-sanctuary:before { background-position: -10rem -11rem; }._icon-sanctuary_def:before { background-position: -11rem -11rem; }._icon-sanctuary_type_classes:before { background-position: -12rem -11rem; }._icon-sass:before { background-position: -13rem -11rem; }._icon-scala:before { background-position: -14rem -11rem; }._icon-scikit_image:before { background-position: -0rem -12rem; }._icon-scikit_learn:before { background-position: -1rem -12rem; }._icon-sequelize:before { background-position: -2rem -12rem; }._icon-sinon:before { background-position: -3rem -12rem; }._icon-socketio:before { background-position: -4rem -12rem; }._icon-spring_boot:before { background-position: -5rem -12rem; }._icon-sqlite:before { background-position: -6rem -12rem; }._icon-statsmodels:before { background-position: -7rem -12rem; }._icon-browser_support_tables:before { background-position: -0rem -8rem; }._icon-svelte:before { background-position: -8rem -12rem; }._icon-svg:before { background-position: -9rem -12rem; }._icon-symfony:before { background-position: -10rem -12rem; }._icon-tailwindcss:before { background-position: -11rem -12rem; }._icon-tcl_tk:before { background-position: -12rem -12rem; }._icon-tcllib:before { background-position: -13rem -12rem; }._icon-tensorflow:before { background-position: -14rem -12rem; }._icon-tensorflow_cpp:before { background-position: -0rem -13rem; }._icon-terraform:before { background-position: -1rem -13rem; @extend %darkIconFix !optional; }._icon-threejs:before { background-position: -2rem -13rem; @extend %darkIconFix !optional; }._icon-trio:before { background-position: -3rem -13rem; }._icon-twig:before { background-position: -4rem -13rem; }._icon-typescript:before { background-position: -5rem -13rem; }._icon-underscore:before { background-position: -6rem -13rem; @extend %darkIconFix !optional; }._icon-vagrant:before { background-position: -7rem -13rem; }._icon-varnish:before { background-position: -8rem -13rem; }._icon-vertx:before { background-position: -9rem -13rem; }._icon-vite:before { background-position: -10rem -13rem; }._icon-vitest:before { background-position: -11rem -13rem; }._icon-vue:before { background-position: -12rem -13rem; }._icon-vue_router:before { background-position: -13rem -13rem; }._icon-vueuse:before { background-position: -14rem -13rem; }._icon-vuex:before { background-position: -0rem -14rem; }._icon-vulkan:before { background-position: -1rem -14rem; @extend %darkIconFix !optional; }._icon-wagtail:before { background-position: -2rem -14rem; @extend %darkIconFix !optional; }._icon-dom:before { background-position: -3rem -14rem; }._icon-web_extensions:before { background-position: -0rem -8rem; }._icon-webpack:before { background-position: -4rem -14rem; }._icon-werkzeug:before { background-position: -5rem -14rem; }._icon-wordpress:before { background-position: -6rem -14rem; @extend %darkIconFix !optional; }._icon-xslt_xpath:before { background-position: -0rem -8rem; }._icon-yarn:before { background-position: -7rem -14rem; }._icon-yii:before { background-position: -8rem -14rem; }._icon-zig:before { background-position: -9rem -14rem; }._icon-zsh:before { background-position: -10rem -14rem; } diff --git a/lib/docs/filters/axios/clean_html.rb b/lib/docs/filters/axios/clean_html.rb index ab71d1ad4c..e772344e3a 100644 --- a/lib/docs/filters/axios/clean_html.rb +++ b/lib/docs/filters/axios/clean_html.rb @@ -7,6 +7,7 @@ def call end @doc = at_css('main > .body') css('.links').remove + css('.sponsors_container').remove css('pre').each do |node| node.content = node.content node['data-language'] = node['class'][/lang-(\w+)/, 1] diff --git a/lib/docs/filters/couchdb/clean_html.rb b/lib/docs/filters/couchdb/clean_html.rb new file mode 100644 index 0000000000..7c30aea4fa --- /dev/null +++ b/lib/docs/filters/couchdb/clean_html.rb @@ -0,0 +1,29 @@ +module Docs + class Couchdb + class CleanHtmlFilter < Filter + def call + css('.section-number').remove + css('.headerlink').remove + + css('.sig-name').each do |node| + node.name = 'code' + end + + css('pre').each do |node| + node.content = node.content.strip + + classes = node.parent.parent.classes + if classes.include? 'highlight-bash' + node['data-language'] = 'bash' + else + node['data-language'] = 'javascript' + end + + node.parent.parent.replace(node) + end + + doc + end + end + end +end diff --git a/lib/docs/filters/couchdb/entries.rb b/lib/docs/filters/couchdb/entries.rb new file mode 100644 index 0000000000..3d03a9616e --- /dev/null +++ b/lib/docs/filters/couchdb/entries.rb @@ -0,0 +1,53 @@ +module Docs + class Couchdb + class EntriesFilter < Docs::EntriesFilter + SLUG_MAP = { + 'api' => 'API', + 'json' => 'JSON Structures', + 'cluster' => 'Cluster Management', + 'replication' => 'Replication', + 'maintenance' => 'Maintenance', + 'partitioned' => 'Partitioned Databases' + } + + def get_name + at_css('h1').content.gsub(/\P{ASCII}/, '').split('.').last + end + + def get_type + if slug.start_with?('ddocs/views') + 'Views' + elsif slug.start_with?('ddocs') + 'Design Documents' + else + SLUG_MAP[slug[/^(.+?)[-\/]/, 1]] || name + end + end + + def additional_entries + needs_breakup = [ + 'JSON Structure Reference', + 'Design Documents', + 'Partitioned Databases' + ] + + if needs_breakup.include?(name) + entries = [] + + css('section > section').each do |node| + h2 = node.at_css('h2') + + if h2.present? + name = node.at_css('h2').content.split('.').last + entries << [name, node['id']] + end + end + + entries + else + [] + end + end + end + end +end diff --git a/lib/docs/filters/htmx/clean_html.rb b/lib/docs/filters/htmx/clean_html.rb index 4c14c6aad3..95a3107327 100644 --- a/lib/docs/filters/htmx/clean_html.rb +++ b/lib/docs/filters/htmx/clean_html.rb @@ -2,6 +2,7 @@ module Docs class Htmx class CleanHtmlFilter < Filter def call + css('.ad').remove css('.zola-anchor').remove doc.prepend_child("

htmx

") if root_page? css('div:contains("NEWS:")').remove diff --git a/lib/docs/filters/ocaml/clean_html.rb b/lib/docs/filters/ocaml/clean_html.rb index 83bb86a0b1..b333094bc0 100644 --- a/lib/docs/filters/ocaml/clean_html.rb +++ b/lib/docs/filters/ocaml/clean_html.rb @@ -2,6 +2,7 @@ module Docs class Ocaml class CleanHtmlFilter < Filter def call + @doc = at_css('.api') || doc css('#sidebar').remove diff --git a/lib/docs/filters/phpunit/clean_html.rb b/lib/docs/filters/phpunit/clean_html.rb index dacb15874b..8bbf619a87 100644 --- a/lib/docs/filters/phpunit/clean_html.rb +++ b/lib/docs/filters/phpunit/clean_html.rb @@ -9,14 +9,16 @@ def call node['data-language'] = 'php' end + # When extracting strings, filter out non-ASCII chars that mysteriously get added. + if slug.match(/assertion|annotations|configuration/) css('h2').each do |node| - node['id'] = node.content + node['id'] = node.content.gsub(/\P{ASCII}/, '') end end - css('h1').each do |node| - node.content = node.content.gsub(/\d*\./, '').strip + css('h1', 'h2', 'h3').each do |node| + node.content = node.content.gsub(/\d*\. |\P{ASCII}/, '') end doc diff --git a/lib/docs/filters/phpunit/entries.rb b/lib/docs/filters/phpunit/entries.rb index fd426be6c7..793b815010 100644 --- a/lib/docs/filters/phpunit/entries.rb +++ b/lib/docs/filters/phpunit/entries.rb @@ -7,8 +7,9 @@ def get_name end def get_type + name.gsub!(/\P{ASCII}/, '') if name.in? ['Assertions', 'Annotations', 'The XML Configuration File'] - name + name.gsub('The ', '') else 'Guides' end @@ -17,11 +18,10 @@ def get_type def additional_entries return [] if type == 'Guides' - css('h2').map do |node| - [node.content, node['id']] + css('h3').map do |node| + [node.content.gsub('The ', ''), node['id'] || node.ancestors('section[id]').first['id']] end end - end end end diff --git a/lib/docs/filters/vite/clean_html.rb b/lib/docs/filters/vite/clean_html.rb index c19745ca3e..5b3efa9431 100644 --- a/lib/docs/filters/vite/clean_html.rb +++ b/lib/docs/filters/vite/clean_html.rb @@ -24,6 +24,8 @@ def call node.remove end + css('.vp-code-group > .tabs').remove + css('.lang').remove css('.line-numbers-wrapper').remove css('pre').each do |node| diff --git a/lib/docs/filters/vue_router/clean_html.rb b/lib/docs/filters/vue_router/clean_html.rb index d7fa396863..64e55c294a 100644 --- a/lib/docs/filters/vue_router/clean_html.rb +++ b/lib/docs/filters/vue_router/clean_html.rb @@ -2,10 +2,15 @@ module Docs class VueRouter class CleanHtmlFilter < Filter def call - @doc = at_css('main') + @doc = at_css('main > div:only-child > div:only-child', 'main', '.main') + css('p + h1').each do |node| + # breadcrumbs + node.previous_element.remove + end # Remove unneeded elements - css('.bit-sponsor, .header-anchor').remove + css('.bit-sponsor, .header-anchor', '.rulekit', 'div[hidden]', '.sponsors_outer').remove + css('.vp-code-group > .tabs').remove css('.custom-block').each do |node| node.name = 'blockquote' @@ -14,6 +19,12 @@ def call title.name = 'strong' unless title.nil? end + css('span.lang').remove + css('pre > code:first-child').each do |node| + node.parent['data-language'] = 'js' + node.parent.content = node.css('.line').map(&:content).join("\n") + end + # Remove data-v-* attributes css('*').each do |node| node.attributes.each_key do |attribute| diff --git a/lib/docs/filters/vue_router/entries.rb b/lib/docs/filters/vue_router/entries.rb index 11c5e8a068..1f1ae8f40e 100644 --- a/lib/docs/filters/vue_router/entries.rb +++ b/lib/docs/filters/vue_router/entries.rb @@ -3,7 +3,8 @@ class VueRouter class EntriesFilter < Docs::EntriesFilter def get_name name = at_css('h1').content - name.sub! %r{#\s*}, '' + name.sub! %r{#\s*|\s*\u200B\s*}, '' + name.strip! name end @@ -18,6 +19,7 @@ def include_default_entry? end def additional_entries + return [] return [] unless subpath.start_with?('api') entries = [ @@ -29,14 +31,18 @@ def additional_entries css('h3').each do |node| entry_name = node.content.strip + entry_name.sub! %r{#\s*|\s*\u200B\s*}, '' # Get the previous h2 title title = node - title = title.previous_element until title.name == 'h2' - title = title.content.strip - title.sub! %r{#\s*}, '' - - entry_name.sub! %r{#\s*}, '' + begin + title = title.previous_element until title.name == 'h2' + title = title.content.strip + title.sub! %r{#\s*}, '' + rescue + title = '' + entry_name = "#{name}.#{entry_name}" + end case title when 'Router Construction Options' diff --git a/lib/docs/scrapers/axios.rb b/lib/docs/scrapers/axios.rb index c29b41ba6c..84869f850b 100644 --- a/lib/docs/scrapers/axios.rb +++ b/lib/docs/scrapers/axios.rb @@ -5,7 +5,7 @@ class Axios < UrlScraper home: 'hthttps://axios-http.com/', code: 'https://github.com/axios/axios' } - self.release = '1.9.0' + self.release = '1.13.5' self.base_url = "https://axios-http.com/docs/" self.initial_paths = %w(index intro) options[:skip] = %w(sponsor) diff --git a/lib/docs/scrapers/couchdb.rb b/lib/docs/scrapers/couchdb.rb new file mode 100644 index 0000000000..a077e195a1 --- /dev/null +++ b/lib/docs/scrapers/couchdb.rb @@ -0,0 +1,39 @@ +module Docs + class Couchdb < UrlScraper + self.name = 'CouchDB' + self.type = 'couchdb' + self.root_path = 'index.html' + + self.links = { + home: 'https://couchdb.apache.org/', + code: 'https://github.com/apache/couchdb' + } + + html_filters.push 'couchdb/clean_html', 'couchdb/entries' + + options[:container] = 'div[itemprop=articleBody]' + options[:only_patterns] = [ + /api\//, + /cluster\//, + /ddocs\//, + /replication\//, + /maintenance\//, + /partitioned-dbs\//, + /json\-structure*/ + ] + options[:rate_limit] = 50 # Docs are subject to Cloudflare limiters. + options[:attribution] = <<-HTML + Copyright © 2025 The Apache Software Foundation — Licensed under the Apache License 2.0 + HTML + + version '3.5' do + self.release = '3.5.1' + self.base_url = "https://docs.couchdb.org/en/#{self.release}" + end + + def get_latest_version(opts) + doc = fetch_doc('https://couchdb.apache.org/', opts) + doc.at_css('.download-pane > h2').content.split(' ').last + end + end +end diff --git a/lib/docs/scrapers/fish.rb b/lib/docs/scrapers/fish.rb index d74ed975ab..0895deb8c0 100644 --- a/lib/docs/scrapers/fish.rb +++ b/lib/docs/scrapers/fish.rb @@ -12,12 +12,36 @@ class Fish < UrlScraper # https://fishshell.com/docs/current/license.html options[:attribution] = <<-HTML - © 2005-2009 Axel Liljencrantz, 2009-2025 fish-shell contributors
+ © 2005-2009 Axel Liljencrantz, 2009-2026 fish-shell contributors
Licensed under the GNU General Public License, version 2. HTML + version '4.4' do + self.release = '4.4.0' + self.base_url = "https://fishshell.com/docs/#{version}/" + + options[:skip].concat %w(genindex.html relnotes.html) + html_filters.push 'sphinx/clean_html', 'fish/clean_html_sphinx', 'fish/entries_sphinx' + end + + version '4.3' do + self.release = '4.3.3' + self.base_url = "https://fishshell.com/docs/#{version}/" + + options[:skip].concat %w(genindex.html relnotes.html) + html_filters.push 'sphinx/clean_html', 'fish/clean_html_sphinx', 'fish/entries_sphinx' + end + + version '4.2' do + self.release = '4.2.1' + self.base_url = "https://fishshell.com/docs/#{version}/" + + options[:skip].concat %w(genindex.html relnotes.html) + html_filters.push 'sphinx/clean_html', 'fish/clean_html_sphinx', 'fish/entries_sphinx' + end + version '4.1' do - self.release = '4.1.0' + self.release = '4.1.2' self.base_url = "https://fishshell.com/docs/#{version}/" options[:skip].concat %w(genindex.html relnotes.html) diff --git a/lib/docs/scrapers/git.rb b/lib/docs/scrapers/git.rb index fd3e64be5f..a9f2a1fcf4 100644 --- a/lib/docs/scrapers/git.rb +++ b/lib/docs/scrapers/git.rb @@ -1,7 +1,7 @@ module Docs class Git < UrlScraper self.type = 'git' - self.release = '2.52.0' + self.release = '2.53.0' self.base_url = 'https://git-scm.com/docs' self.initial_paths = %w( /git.html @@ -41,12 +41,12 @@ class Git < UrlScraper options[:container] = '#content' options[:only_patterns] = [/\A\/[^\/]+\z/] - options[:skip] = %w(/howto-index.html) + options[:skip] = %w(/api-index /howto-index) # https://github.com/git/git?tab=License-1-ov-file#readme # NOT https://github.com/git/git-scm.com/blob/gh-pages/MIT-LICENSE.txt options[:attribution] = <<-HTML - © 2005–2025 Linus Torvalds and others
+ © 2005–2026 Linus Torvalds and others
Licensed under the GNU General Public License version 2. HTML diff --git a/lib/docs/scrapers/htmx.rb b/lib/docs/scrapers/htmx.rb index 719277b2b9..ec1f51e07d 100644 --- a/lib/docs/scrapers/htmx.rb +++ b/lib/docs/scrapers/htmx.rb @@ -7,27 +7,35 @@ class Htmx < UrlScraper home: 'https://htmx.org/', code: 'https://github.com/bigskysoftware/htmx' } - self.release = '1.9.10' - self.base_url = "https://htmx.org/" self.initial_paths = %w(reference/) html_filters.push 'htmx/entries', 'htmx/clean_html' options[:trailing_slash] = true - options[:container] = '.content' + options[:container] = '.content' options[:download_images] = false options[:skip_patterns] = [ - /\Aessays/, - /\Aexamples/, - /\Amigration-guide/, - /\Aposts/, - ] + /\Aessays/, + /\Aexamples/, + /\Amigration-guide/, + /\Aposts/, + ] - # https://github.com/bigskysoftware/htmx/blob/master/LICENSE + # https://github.com/bigskysoftware/htmx/blob/master/LICENSE options[:attribution] = <<-HTML - Licensed under the Zero-Clause BSD License. + Licensed under the Zero-Clause BSD License. HTML + version do + self.release = '2.0.7' + self.base_url = "https://htmx.org/" + end + + version '1' do + self.release = '1.9.12' + self.base_url = "https://v1.htmx.org/" + end + def get_latest_version(opts) get_npm_version('htmx.org', opts) end diff --git a/lib/docs/scrapers/i3.rb b/lib/docs/scrapers/i3.rb index 899a718acf..2f80785c74 100644 --- a/lib/docs/scrapers/i3.rb +++ b/lib/docs/scrapers/i3.rb @@ -3,7 +3,7 @@ class I3 < UrlScraper self.name = 'i3' self.type = 'simple' self.slug = 'i3' - self.release = '4.24' + self.release = '4.25.1' self.base_url = 'https://i3wm.org/docs/userguide.html' self.links = { home: 'https://i3wm.org/', diff --git a/lib/docs/scrapers/ocaml.rb b/lib/docs/scrapers/ocaml.rb index 97a25a9413..10ba166c23 100644 --- a/lib/docs/scrapers/ocaml.rb +++ b/lib/docs/scrapers/ocaml.rb @@ -21,11 +21,11 @@ class Ocaml < UrlScraper ] options[:attribution] = <<-HTML - © 1995-2024 INRIA. + © 1995-2025 INRIA. HTML version '' do - self.release = '5.3' + self.release = '5.4' self.base_url = "https://ocaml.org/manual/#{self.release}/" end diff --git a/lib/docs/scrapers/phpunit.rb b/lib/docs/scrapers/phpunit.rb index 12efbbfcba..5b7830c4f5 100644 --- a/lib/docs/scrapers/phpunit.rb +++ b/lib/docs/scrapers/phpunit.rb @@ -24,7 +24,7 @@ class Phpunit < UrlScraper FILTERS = %w(phpunit/clean_html phpunit/entries title) version do - self.release = '12.0' + self.release = '12.5' self.base_url = "https://docs.phpunit.de/en/#{release}/" html_filters.push FILTERS diff --git a/lib/docs/scrapers/postgresql.rb b/lib/docs/scrapers/postgresql.rb index 38ac56a06e..760ac0dc80 100644 --- a/lib/docs/scrapers/postgresql.rb +++ b/lib/docs/scrapers/postgresql.rb @@ -52,12 +52,12 @@ class Postgresql < UrlScraper /\Aunsupported-features/ ] options[:attribution] = <<-HTML - © 1996–2025 The PostgreSQL Global Development Group
+ © 1996–2026 The PostgreSQL Global Development Group
Licensed under the PostgreSQL License. HTML version '18' do - self.release = '18.0' + self.release = '18.2' self.base_url = "https://www.postgresql.org/docs/#{version}/" end @@ -70,7 +70,7 @@ class Postgresql < UrlScraper self.release = '16.1' self.base_url = "https://www.postgresql.org/docs/#{version}/" end - + version '15' do self.release = '15.4' self.base_url = "https://www.postgresql.org/docs/#{version}/" diff --git a/lib/docs/scrapers/rust.rb b/lib/docs/scrapers/rust.rb index 7fa65e6569..83b1533767 100644 --- a/lib/docs/scrapers/rust.rb +++ b/lib/docs/scrapers/rust.rb @@ -3,7 +3,7 @@ module Docs class Rust < UrlScraper self.type = 'rust' - self.release = '1.91.1' + self.release = '1.93.1' self.base_url = 'https://doc.rust-lang.org/' self.root_path = 'book/index.html' self.initial_paths = %w( diff --git a/lib/docs/scrapers/vite.rb b/lib/docs/scrapers/vite.rb index 1a55691376..f6619d3a57 100644 --- a/lib/docs/scrapers/vite.rb +++ b/lib/docs/scrapers/vite.rb @@ -11,7 +11,7 @@ class Vite < UrlScraper options[:root_title] = 'Vite' options[:attribution] = <<-HTML - © 2019–present, Yuxi (Evan) You and Vite contributors
+ © 2019-present, VoidZero Inc. and Vite contributors
Licensed under the MIT License. HTML @@ -22,7 +22,7 @@ class Vite < UrlScraper html_filters.push 'vite/entries', 'vite/clean_html' version do - self.release = '7.1.2' + self.release = '7.3.1' self.base_url = 'https://vite.dev/' end diff --git a/lib/docs/scrapers/vitest.rb b/lib/docs/scrapers/vitest.rb index ab7a3d1bb3..379f48c1c7 100644 --- a/lib/docs/scrapers/vitest.rb +++ b/lib/docs/scrapers/vitest.rb @@ -13,19 +13,23 @@ class Vitest < UrlScraper options[:skip] = %w(blog) options[:attribution] = <<-HTML - © 2021-Present Anthony Fu
- © 2021-Present Matias Capeletto
+ © 2021-Present VoidZero Inc. and Vitest contributors
Licensed under the MIT License. HTML self.initial_paths = %w(guide/) html_filters.push 'vitest/entries', 'vite/clean_html' - + version do - self.release = '3.0.8' + self.release = '4.0.17' self.base_url = 'https://vitest.dev/' end - + + version '3' do + self.release = '3.2.4' + self.base_url = 'https://vitest.dev/' + end + version '2' do self.release = '2.1.9' self.base_url = 'https://v2.vitest.dev/' diff --git a/lib/docs/scrapers/vue.rb b/lib/docs/scrapers/vue.rb index 158a546b19..7e9171b578 100644 --- a/lib/docs/scrapers/vue.rb +++ b/lib/docs/scrapers/vue.rb @@ -14,12 +14,12 @@ class Vue < UrlScraper options[:replace_paths] = { 'guide/' => 'guide/index.html' } options[:attribution] = <<-HTML - © 2013–present Yuxi Evan You
+ © 2018-present, Yuxi (Evan) You and Vue contributors
Licensed under the MIT License. HTML version '3' do - self.release = '3.5.18' + self.release = '3.5.28' self.base_url = 'https://vuejs.org/' self.initial_paths = %w(guide/introduction.html) html_filters.push 'vue/entries_v3', 'vue/clean_html' diff --git a/lib/docs/scrapers/vue_router.rb b/lib/docs/scrapers/vue_router.rb index 3456fd59db..7e4ee6ed1e 100644 --- a/lib/docs/scrapers/vue_router.rb +++ b/lib/docs/scrapers/vue_router.rb @@ -16,10 +16,15 @@ class VueRouter < UrlScraper ] options[:attribution] = <<-HTML - © 2013–present Evan You
+ © 2014-present Evan You, Eduardo San Martin Morote
Licensed under the MIT License. HTML + version '5' do + self.release = '5.0.2' + self.base_url = 'https://router.vuejs.org/' + end + version '4' do self.release = '4.0.12' self.base_url = 'https://next.router.vuejs.org/' diff --git a/public/icons/docs/couchdb/16.png b/public/icons/docs/couchdb/16.png new file mode 100644 index 0000000000..7cae0c8b51 Binary files /dev/null and b/public/icons/docs/couchdb/16.png differ diff --git a/public/icons/docs/couchdb/16@2x.png b/public/icons/docs/couchdb/16@2x.png new file mode 100644 index 0000000000..81dc55b202 Binary files /dev/null and b/public/icons/docs/couchdb/16@2x.png differ diff --git a/public/icons/docs/couchdb/SOURCE b/public/icons/docs/couchdb/SOURCE new file mode 100644 index 0000000000..86560405ed --- /dev/null +++ b/public/icons/docs/couchdb/SOURCE @@ -0,0 +1 @@ +https://docs.couchdb.org/en/stable/_static/favicon.ico diff --git a/public/icons/docs/vite/16.png b/public/icons/docs/vite/16.png index 90ffa78658..a081c7b8c1 100644 Binary files a/public/icons/docs/vite/16.png and b/public/icons/docs/vite/16.png differ diff --git a/public/icons/docs/vite/16@2x.png b/public/icons/docs/vite/16@2x.png index 375fb680ed..e8d199489b 100644 Binary files a/public/icons/docs/vite/16@2x.png and b/public/icons/docs/vite/16@2x.png differ diff --git a/public/icons/docs/vite/SOURCE b/public/icons/docs/vite/SOURCE index f1fe46eefe..f7b304f1f2 100644 --- a/public/icons/docs/vite/SOURCE +++ b/public/icons/docs/vite/SOURCE @@ -1 +1 @@ -https://vitejs.dev/logo.svg +https://vite.dev/logo-without-border.svg diff --git a/public/icons/docs/vitest/16.png b/public/icons/docs/vitest/16.png index fd44a6bb81..7fbe9bee38 100644 Binary files a/public/icons/docs/vitest/16.png and b/public/icons/docs/vitest/16.png differ diff --git a/public/icons/docs/vitest/16@2x.png b/public/icons/docs/vitest/16@2x.png index 051339ca94..6b72ed130d 100644 Binary files a/public/icons/docs/vitest/16@2x.png and b/public/icons/docs/vitest/16@2x.png differ diff --git a/public/icons/docs/vitest/SOURCE b/public/icons/docs/vitest/SOURCE index 911a2163a4..0cf0aaabab 100644 --- a/public/icons/docs/vitest/SOURCE +++ b/public/icons/docs/vitest/SOURCE @@ -1 +1,2 @@ https://vitest.dev/logo.svg +https://vitest.dev/favicon.ico