diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4bd573b6..004fb1fe 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Deno environment uses: denoland/setup-deno@v1 with: - deno-version: v1.x + deno-version: v1.38.5 - name: Verify formatting if: matrix.os == 'ubuntu-latest' diff --git a/CHANGELOG.md b/CHANGELOG.md index c2b95ce8..de57e82a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project try to adheres to [Semantic Versioning](https://semver.org/). Go to the `v1` branch to see the changelog of Lume 1. +## [2.0.2] - 2024-01-01 +### Added +- Add critical log on rare case where developer forget to export the Site instance in the `_config.ts` + +### Changed +- `decap_cms` plugin: Add a script in the homepage to redirect to /admin/ + when an invite token or recovery token is detected from netlify identity. +- `getOptionsFromCli` is moved from `mod.ts` to `utils/cli_options.ts` [#535], [#540]. + +### Fixed +- `sitemap` plugin: Add the `xmlns` namespace for localized urls. +- Files with all caps extensions are ignored [#542]. +- `multilanguage` plugin: + - Fix error of two pages with the same id, type and lang. + - Fix the error of a page with lang, but undefined id. +- Removed unused `imagick` dependency. +- Added `Lume.PaginateResult` type. +- Apply merge data strategies between multiple _data files/folders in the same folder. +- Date recovery from Git repositories [#544]. +- Updated dependencies: `std`, `esbuild`, `liquid`, `postcssNesting`, `react-dom` types, `sharp`, `svgo`, `vento`, `tailwindcss`, `minify_html`, `unocss`, `sass`. + ## [2.0.1] - 2023-12-10 ### Added - `mdx` plugin: New `rehypeOptions` option [#517] @@ -184,6 +205,11 @@ Go to the `v1` branch to see the changelog of Lume 1. [#523]: https://github.com/lumeland/lume/issues/523 [#525]: https://github.com/lumeland/lume/issues/525 [#526]: https://github.com/lumeland/lume/issues/526 +[#535]: https://github.com/lumeland/lume/issues/535 +[#540]: https://github.com/lumeland/lume/issues/540 +[#542]: https://github.com/lumeland/lume/issues/542 +[#544]: https://github.com/lumeland/lume/issues/544 +[2.0.2]: https://github.com/lumeland/lume/compare/v2.0.1...v2.0.2 [2.0.1]: https://github.com/lumeland/lume/compare/v2.0.0...v2.0.1 [2.0.0]: https://github.com/lumeland/lume/releases/tag/v2.0.0 diff --git a/LICENSE b/LICENSE index 15ab6e07..28127e9f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 - Oscar Otero +Copyright (c) 2024 - Oscar Otero Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/cli/run.ts b/cli/run.ts index bc0923c5..a454dcf9 100644 --- a/cli/run.ts +++ b/cli/run.ts @@ -48,6 +48,12 @@ export async function createSite(config?: string): Promise { if (url) { log.info(`Loading config file ${url}`); const mod = await import(url); + if (!mod.default) { + log.critical( + `[Lume] Missing Site instance! Ensure your config file does export the Site instance as default.`, + ); + throw new Error("Site instance is not found"); + } return mod.default; } diff --git a/core/formats.ts b/core/formats.ts index 947c404a..feb7e537 100644 --- a/core/formats.ts +++ b/core/formats.ts @@ -37,7 +37,7 @@ export default class Formats { /** Assign a value to a extension */ set(format: Format, override = true): void { - const { ext } = format; + const ext = format.ext.toLowerCase(); const existing = this.entries.get(ext); if (existing) { @@ -70,21 +70,23 @@ export default class Formats { /** Returns a format by extension */ get(extension: string): Format | undefined { - return this.entries.get(extension); + return this.entries.get(extension.toLowerCase()); } /** Delete a format */ delete(extension: string): void { - this.entries.delete(extension); + this.entries.delete(extension.toLowerCase()); } /** Returns if a format exists */ has(extension: string): boolean { - return this.entries.has(extension); + return this.entries.has(extension.toLowerCase()); } /** Search and return the associated format for a path */ search(path: string): Format | undefined { + path = path.toLowerCase(); + for (const format of this.entries.values()) { if (path.endsWith(format.ext)) { return format; diff --git a/core/processors.ts b/core/processors.ts index 72a95370..06548a98 100644 --- a/core/processors.ts +++ b/core/processors.ts @@ -33,10 +33,12 @@ export default class Processors { } } -/** A (pre)processor */ +/** + * Processor callback is used in both (pre)process methods. + */ export type Processor = ( - pages: Page[], - allpages: Page[], + filteredPages: Page[], + allPages: Page[], ) => void | false | Promise; function pageMatches(exts: Extensions, page: Page): boolean { diff --git a/core/source.ts b/core/source.ts index 13220599..0c715a58 100644 --- a/core/source.ts +++ b/core/source.ts @@ -160,23 +160,30 @@ export default class Source { const [basename, date] = parseDateFromFilename(dir.name); // Load the _data files - const currentData: Partial = date ? { date } : {}; + const dirDatas: RawData[] = []; for (const entry of dir.children.values()) { if ( (entry.type === "file" && entry.name.startsWith("_data.")) || (entry.type === "directory" && entry.name === "_data") ) { - Object.assign(currentData, await this.dataLoader.load(entry)); + const loaded = await this.dataLoader.load(entry); + if (loaded) { + dirDatas.push(loaded); + } } } + if (date) { + dirDatas.push({ date }); + } + // Merge directory data const dirData = mergeData( parentData, { basename }, this.scopedData.get(dir.path) || {}, - currentData, + ...dirDatas, ) as Partial; path = posix.join(path, dirData.basename!); diff --git a/core/utils/cli_options.ts b/core/utils/cli_options.ts new file mode 100644 index 00000000..9c47edb6 --- /dev/null +++ b/core/utils/cli_options.ts @@ -0,0 +1,42 @@ +import { parseArgs } from "../../deps/cli.ts"; +import type { DeepPartial } from "./object.ts"; +import type { SiteOptions } from "../site.ts"; + +export function getOptionsFromCli(): DeepPartial { + const options = parseArgs(Deno.args, { + string: ["src", "dest", "location", "port"], + boolean: ["serve", "open"], + alias: { dev: "d", serve: "s", port: "p", open: "o" }, + ["--"]: true, + }); + + const overrides: DeepPartial = {}; + + if (options.src) { + overrides.src = options.src; + } + + if (options.dest) { + overrides.dest = options.dest; + } + + if (options.location) { + overrides.location = new URL(options.location); + } else if (options.serve) { + overrides.location = new URL(`http://localhost:${options.port || 3000}/`); + } + + if (options.port) { + (overrides.server ||= {}).port = parseInt(options.port); + + if (overrides.location) { + overrides.location.port = options.port; + } + } + + if (options.open) { + (overrides.server ||= {}).open = options.open; + } + + return overrides; +} diff --git a/core/utils/date.ts b/core/utils/date.ts index e9808f3a..f7337b2e 100644 --- a/core/utils/date.ts +++ b/core/utils/date.ts @@ -20,7 +20,7 @@ export function getGitDate( const str = new TextDecoder().decode(stdout); if (str) { - return parseDate(parseInt(str)); + return parseDate(parseInt(str) * 1000); } } diff --git a/deps/assert.ts b/deps/assert.ts index 55cefed1..03f30fa0 100644 --- a/deps/assert.ts +++ b/deps/assert.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/assert/mod.ts"; +export * from "https://deno.land/std@0.210.0/assert/mod.ts"; diff --git a/deps/base64.ts b/deps/base64.ts index 0d288473..91e3c6f1 100644 --- a/deps/base64.ts +++ b/deps/base64.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/encoding/base64.ts"; +export * from "https://deno.land/std@0.210.0/encoding/base64.ts"; diff --git a/deps/cli.ts b/deps/cli.ts index e2618acf..7b8910c8 100644 --- a/deps/cli.ts +++ b/deps/cli.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/cli/mod.ts"; +export * from "https://deno.land/std@0.210.0/cli/mod.ts"; diff --git a/deps/colors.ts b/deps/colors.ts index 1af00ff2..a0026567 100644 --- a/deps/colors.ts +++ b/deps/colors.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/fmt/colors.ts"; +export * from "https://deno.land/std@0.210.0/fmt/colors.ts"; diff --git a/deps/crypto.ts b/deps/crypto.ts index e7417fab..ae1c7dd0 100644 --- a/deps/crypto.ts +++ b/deps/crypto.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/crypto/mod.ts"; +export * from "https://deno.land/std@0.210.0/crypto/mod.ts"; diff --git a/deps/date.ts b/deps/date.ts index e7b64504..09969d01 100644 --- a/deps/date.ts +++ b/deps/date.ts @@ -1 +1,2 @@ -export * from "npm:date-fns@2.30.0"; +export { format } from "npm:date-fns@2.30.0"; +export type { Locale } from "npm:date-fns@2.30.0"; diff --git a/deps/esbuild.ts b/deps/esbuild.ts index da329468..6e84cec1 100644 --- a/deps/esbuild.ts +++ b/deps/esbuild.ts @@ -1 +1 @@ -export * from "https://deno.land/x/esbuild@v0.19.9/mod.js"; +export * from "https://deno.land/x/esbuild@v0.19.11/mod.js"; diff --git a/deps/front_matter.ts b/deps/front_matter.ts index 89b8c555..e6241bf6 100644 --- a/deps/front_matter.ts +++ b/deps/front_matter.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/front_matter/any.ts"; +export * from "https://deno.land/std@0.210.0/front_matter/any.ts"; diff --git a/deps/fs.ts b/deps/fs.ts index 25e7bf99..9624f51e 100644 --- a/deps/fs.ts +++ b/deps/fs.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/fs/mod.ts"; +export * from "https://deno.land/std@0.210.0/fs/mod.ts"; diff --git a/deps/hex.ts b/deps/hex.ts index 161a08d4..c39092b8 100644 --- a/deps/hex.ts +++ b/deps/hex.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/encoding/hex.ts"; +export * from "https://deno.land/std@0.210.0/encoding/hex.ts"; diff --git a/deps/http.ts b/deps/http.ts index 9b337d14..fdd3630d 100644 --- a/deps/http.ts +++ b/deps/http.ts @@ -1 +1 @@ -export { serveFile } from "https://deno.land/std@0.208.0/http/file_server.ts"; +export { serveFile } from "https://deno.land/std@0.210.0/http/file_server.ts"; diff --git a/deps/imagick.ts b/deps/imagick.ts deleted file mode 100644 index 1494dad4..00000000 --- a/deps/imagick.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "https://deno.land/x/imagemagick_deno@0.0.26/mod.ts"; -import { initialize } from "https://deno.land/x/imagemagick_deno@0.0.26/mod.ts"; - -await initialize(); diff --git a/deps/jsonc.ts b/deps/jsonc.ts index 59d250cf..da261626 100644 --- a/deps/jsonc.ts +++ b/deps/jsonc.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/jsonc/mod.ts"; +export * from "https://deno.land/std@0.210.0/jsonc/mod.ts"; diff --git a/deps/liquid.ts b/deps/liquid.ts index 5006b694..a875c7d0 100644 --- a/deps/liquid.ts +++ b/deps/liquid.ts @@ -1,7 +1,7 @@ -export * from "npm:liquidjs@10.9.4"; -export type { LiquidOptions } from "npm:liquidjs@10.9.4/dist/src/liquid-options"; +export * from "npm:liquidjs@10.10.0"; +export type { LiquidOptions } from "npm:liquidjs@10.10.0/dist/src/liquid-options"; export type { TagClass, TagImplOptions, Template, -} from "npm:liquidjs@10.9.4/dist/src/template"; +} from "npm:liquidjs@10.10.0/dist/src/template"; diff --git a/deps/log.ts b/deps/log.ts index f7d34645..9c1076d6 100644 --- a/deps/log.ts +++ b/deps/log.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/log/mod.ts"; +export * from "https://deno.land/std@0.210.0/log/mod.ts"; diff --git a/deps/media_types.ts b/deps/media_types.ts index d70eb7c0..02d3e56b 100644 --- a/deps/media_types.ts +++ b/deps/media_types.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.208.0/media_types/mod.ts"; +export * from "https://deno.land/std@0.210.0/media_types/mod.ts"; diff --git a/deps/minify_html.ts b/deps/minify_html.ts index c925cedf..3917f30b 100644 --- a/deps/minify_html.ts +++ b/deps/minify_html.ts @@ -1,10 +1,10 @@ // https://github.com/wilsonzlin/minify-html -export { minify } from "https://wilsonl.in/minify-html/deno/0.11.1/index.js"; -import initWasm from "https://wilsonl.in/minify-html/deno/0.11.1/index.js"; +export { minify } from "https://wilsonl.in/minify-html/deno/0.15.0/index.js"; +import initWasm from "https://wilsonl.in/minify-html/deno/0.15.0/index.js"; import { read } from "../core/utils/read.ts"; // Initialize the WASM module -const url = "https://wilsonl.in/minify-html/deno/0.11.1/index_bg.wasm"; +const url = "https://wilsonl.in/minify-html/deno/0.15.0/index_bg.wasm"; const wasm = await read(url, true); await initWasm(wasm); @@ -27,6 +27,15 @@ export interface Options { /** Keep all comments. */ keep_comments?: boolean; + /** Keep SSI comments. */ + keep_ssi_comments?: boolean; + + /** When `{{`, `{#`, or `{%` are seen in content, all source code until the subsequent matching closing `}}`, `#}`, or `%}` respectively gets piped through untouched. */ + preserve_brace_template_syntax?: boolean; + + /** When `<%` is seen in content, all source code until the subsequent matching closing `%>` gets piped through untouched. */ + preserve_chevron_percent_template_syntax?: boolean; + /** If enabled, content in ` + ', @@ -171,7 +172,7 @@ local_backend: false Admin - + ', @@ -188,5 +189,40 @@ local_backend: false remote: undefined, }, }, + { + content: ' +

Hello world

+', + data: { + basename: "index", + children: "

Hello world

+", + content: "# Hello world +", + date: [], + decap_cms: [ + "backend", + "media_folder", + "public_folder", + ], + mergedKeys: [ + "tags", + ], + page: [ + "src", + "data", + ], + paginate: "paginate", + search: [], + tags: "Array(0)", + url: "/", + }, + src: { + asset: false, + ext: ".md", + path: "/index", + remote: undefined, + }, + }, ] `; diff --git a/tests/__snapshots__/minify_html.test.ts.snap b/tests/__snapshots__/minify_html.test.ts.snap index 06a641af..2526d3a6 100644 --- a/tests/__snapshots__/minify_html.test.ts.snap +++ b/tests/__snapshots__/minify_html.test.ts.snap @@ -114,7 +114,7 @@ snapshot[`minify_html plugin 2`] = `[]`; snapshot[`minify_html plugin 3`] = ` [ { - content: \`Document

Hello World

\`, + content: 'Document

Hello World

', data: { basename: "index", children: \` diff --git a/tests/__snapshots__/sitemap.test.ts.snap b/tests/__snapshots__/sitemap.test.ts.snap index 9aa4cebf..88264c17 100644 --- a/tests/__snapshots__/sitemap.test.ts.snap +++ b/tests/__snapshots__/sitemap.test.ts.snap @@ -157,7 +157,7 @@ Sitemap: https://example.com/sitemap.xml", }, { content: ' - + https://example.com/overrided-page2/ 2020-06-21T00:00:00.000Z @@ -182,7 +182,7 @@ Sitemap: https://example.com/sitemap.xml", data: { basename: "sitemap", content: ' - + https://example.com/overrided-page2/ 2020-06-21T00:00:00.000Z @@ -657,7 +657,7 @@ Sitemap: https://example.com/sitemap.xml", }, { content: ' - + https://example.com/en/ @@ -730,7 +730,7 @@ Sitemap: https://example.com/sitemap.xml", data: { basename: "sitemap", content: ' - + https://example.com/en/ diff --git a/tests/__snapshots__/tailwindcss.test.ts.snap b/tests/__snapshots__/tailwindcss.test.ts.snap index 0227ee1c..8dfc7dd1 100644 --- a/tests/__snapshots__/tailwindcss.test.ts.snap +++ b/tests/__snapshots__/tailwindcss.test.ts.snap @@ -969,7 +969,7 @@ snapshot[`postcss plugin 3`] = ` }, { content: "/* -! tailwindcss v3.3.6 | MIT License | https://tailwindcss.com +! tailwindcss v3.4.0 | MIT License | https://tailwindcss.com *//* 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) @@ -996,17 +996,20 @@ snapshot[`postcss plugin 3`] = ` 4. Use the user's configured \`sans\` font-family by default. 5. Use the user's configured \`sans\` font-feature-settings by default. 6. Use the user's configured \`sans\` font-variation-settings by default. +7. Disable tap highlights on iOS */ -html { +html, +:host { line-height: 1.5; /* 1 */ -webkit-text-size-adjust: 100%; /* 2 */ -moz-tab-size: 4; /* 3 */ -o-tab-size: 4; tab-size: 4; /* 3 */ - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"; /* 4 */ + font-family: ui-sans-serif, system-ui, sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"; /* 4 */ font-feature-settings: normal; /* 5 */ font-variation-settings: normal; /* 6 */ + -webkit-tap-highlight-color: transparent; /* 7 */ } /* @@ -1753,7 +1756,7 @@ video { text-align: justify; } .font-sans { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"; + font-family: ui-sans-serif, system-ui, sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"; } .text-2xl { font-size: 1.5rem; diff --git a/tests/__snapshots__/transform_images.test.ts.snap b/tests/__snapshots__/transform_images.test.ts.snap index 76c0a289..ea9d0129 100644 --- a/tests/__snapshots__/transform_images.test.ts.snap +++ b/tests/__snapshots__/transform_images.test.ts.snap @@ -123,7 +123,7 @@ snapshot[`Image transform plugin 1`] = ` src: [ "/", "/_data.yml", - "/lume.png", + "/lume.PNG", ], } `; diff --git a/tests/assets/decap_cms/index.md b/tests/assets/decap_cms/index.md new file mode 100644 index 00000000..716ed142 --- /dev/null +++ b/tests/assets/decap_cms/index.md @@ -0,0 +1 @@ +# Hello world diff --git a/tests/assets/transform_images/lume.png b/tests/assets/transform_images/lume.PNG similarity index 100% rename from tests/assets/transform_images/lume.png rename to tests/assets/transform_images/lume.PNG diff --git a/tests/decap_cms.test.ts b/tests/decap_cms.test.ts index 5d50ffc1..c4a0e9d3 100644 --- a/tests/decap_cms.test.ts +++ b/tests/decap_cms.test.ts @@ -9,6 +9,7 @@ Deno.test("Decap CMS plugin", async (t) => { site.use(decapCMS({ local: false, + identity: "netlify", })); await build(site);