diff --git a/README.md b/README.md index 0ade4ca..bb3f3aa 100644 --- a/README.md +++ b/README.md @@ -85,17 +85,30 @@ It is also possible to not override the values but instead specify the field nam ```js export default { modules: [ + '@nuxt/content', ['nuxt-content-git', { createdAtName: 'gitCreatedAt', updatedAtName: 'gitUpdatedAt', }], - '@nuxt/content', ], } ``` Then you can access them via `doc.gitCreatedAt` and `doc.gitUpdatedAt`. +## Nuxt 2 + +For Nuxt 2 you need to add the module _before_ `@nuxt/content`: + +```js +export default { + modules: [ + 'nuxt-content-git', + '@nuxt/content', + }, +} +``` + ## Deployment The module uses the Git history to calculate the dates. That is why the history also needs to be checked out when deploying the project to live. During local development the repository is usually deeply cloned. But CI systems like GitHub Actions often only do a shallow clone for performance reasons, which will result in wrong dates. diff --git a/package.json b/package.json index fc29b86..571d701 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "fs-extra": "^11.1.1", "nuxt": "^3.5.3", "nuxt-dev-ready": "^2.0.1", + "ora": "^6.3.1", "output-files": "^2.0.0", "tree-kill-promise": "^3.0.14" }, diff --git a/src/index.js b/src/index.js index 0296590..f4944e4 100644 --- a/src/index.js +++ b/src/index.js @@ -1,16 +1,39 @@ -import { addServerPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' +import { + addServerPlugin, + createResolver, + isNuxt3 as isNuxt3Try, +} from '@nuxt/kit' +import P from 'path' + +import setVariables from './set-variables.js' const resolver = createResolver(import.meta.url) -export default defineNuxtModule({ - setup: (options, nuxt) => { - nuxt.options.runtimeConfig.nuxtContentGit = { - createdAtName: 'createdAt', - updatedAtName: 'updatedAt', - ...nuxt.options.runtimeConfig.nuxtContentGit, - ...nuxt.options.nuxtContentGit, - ...options, - } +export default function (options, nuxt) { + let isNuxt3 = true + try { + isNuxt3 = isNuxt3Try() + } catch { + isNuxt3 = false + } + nuxt = nuxt || this + options = { + createdAtName: 'createdAt', + updatedAtName: 'updatedAt', + ...(isNuxt3 && nuxt.options.runtimeConfig.nuxtContentGit), + ...nuxt.options.nuxtContentGit, + ...options, + } + if (isNuxt3) { + nuxt.options.runtimeConfig.nuxtContentGit = options addServerPlugin(resolver.resolve('./server-plugin.js')) - }, -}) + } else { + this.nuxt.hook('content:file:beforeInsert', (file, database) => + setVariables( + file, + P.join(database.dir, `${file.path}${file.extension}`), + options, + ), + ) + } +} diff --git a/src/index.spec.js b/src/index.spec.js index 08fa930..6eb18f3 100644 --- a/src/index.spec.js +++ b/src/index.spec.js @@ -1,11 +1,18 @@ -import { endent, first, last, pick, property } from '@dword-design/functions' +import { + endent, + first, + last, + pick, + property, +} from '@dword-design/functions' import tester from '@dword-design/tester' import testerPluginTmpDir from '@dword-design/tester-plugin-tmp-dir' import axios from 'axios' import packageName from 'depcheck-package-name' -import { execaCommand } from 'execa' +import { execa, execaCommand } from 'execa' import fs from 'fs-extra' import nuxtDevReady from 'nuxt-dev-ready' +import ora from 'ora' import outputFiles from 'output-files' import P from 'path' import simpleGit from 'simple-git' @@ -99,6 +106,58 @@ export default tester( await kill(nuxt.pid) } }, + nuxt2: async () => { + await execaCommand('git init') + await execaCommand('git config user.email "foo@bar.de"') + await execaCommand('git config user.name "foo"') + await outputFiles({ + 'content/home.md': '', + 'nuxt.config.js': endent` + export default { + modules: [ + '~/../src/index.js', + '${packageName`@nuxt/content`}', + ], + } + `, + }) + await execaCommand('git add .') + await execaCommand('git commit -m init') + await fs.outputFile('content/home.md', 'foo') + await execaCommand('git add .') + await execaCommand('git commit -m update') + + const git = simpleGit() + + const log = await git.log({ + file: P.join('content', 'home.md'), + }) + + const createdAt = new Date(log.all |> last |> property('date')) + + const updatedAt = new Date(log.latest.date) + await fs.remove('node_modules') + await fs.symlink( + P.join('..', 'node_modules', '.cache', 'nuxt2', 'node_modules'), + 'node_modules', + ) + + const nuxt = execa(P.join('node_modules', '.bin', 'nuxt'), ['dev']) + try { + await nuxtDevReady() + expect( + axios.get('http://localhost:3000/_content/home') + |> await + |> property('data') + |> pick(['createdAt', 'updatedAt']), + ).toEqual({ + createdAt: createdAt.toISOString(), + updatedAt: updatedAt.toISOString(), + }) + } finally { + await kill(nuxt.pid) + } + }, works: async () => { await execaCommand('git init') await execaCommand('git config user.email "foo@bar.de"') @@ -149,7 +208,17 @@ export default tester( [ testerPluginTmpDir(), { - before: () => execaCommand('base prepublishOnly'), + before: async () => { + const spinner = ora('Installing Nuxt 2').start() + await fs.outputFile( + P.join('node_modules', '.cache', 'nuxt2', 'package.json'), + JSON.stringify({}), + ) + await execaCommand('yarn add nuxt@^2 @nuxt/content@^1', { + cwd: P.join('node_modules', '.cache', 'nuxt2'), + }) + spinner.stop() + }, }, { beforeEach: async () => { diff --git a/src/server-plugin.js b/src/server-plugin.js index 78d6759..6a0154a 100644 --- a/src/server-plugin.js +++ b/src/server-plugin.js @@ -1,20 +1,15 @@ -import { last } from '@dword-design/functions' import P from 'path' -import simpleGit from 'simple-git' import { defineNitroPlugin, useRuntimeConfig } from '#imports' -export default defineNitroPlugin(nitroApp => { - const options = useRuntimeConfig().nuxtContentGit - nitroApp.hooks.hook('content:file:afterParse', async file => { - const git = simpleGit() +import setVariables from './set-variables.js' - const log = await git.log({ - file: P.join('content', file._file), - }) - file[options.createdAtName] = - log.all.length > 0 ? new Date(last(log.all).date) : undefined - file[options.updatedAtName] = - log.latest === null ? undefined : new Date(log.latest.date) - }) -}) +export default defineNitroPlugin(nitroApp => + nitroApp.hooks.hook('content:file:afterParse', file => + setVariables( + file, + P.join('content', file._file), + useRuntimeConfig().nuxtContentGit, + ), + ), +) diff --git a/src/set-variables.js b/src/set-variables.js new file mode 100644 index 0000000..421ef43 --- /dev/null +++ b/src/set-variables.js @@ -0,0 +1,14 @@ +import { last } from '@dword-design/functions' +import simpleGit from 'simple-git' + +export default async (file, path, options) => { + const git = simpleGit() + + const log = await git.log({ + file: path, + }) + file[options.createdAtName] = + log.all.length > 0 ? new Date(last(log.all).date) : file.createdAt + file[options.updatedAtName] = + log.latest === null ? file.updatedAt : new Date(log.latest.date) +} diff --git a/yarn.lock b/yarn.lock index 387ea64..b6c85f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3233,6 +3233,11 @@ ansi-regex@^5.0.0, ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -3792,6 +3797,15 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" +bl@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-5.1.0.tgz#183715f678c7188ecef9fe475d90209400624273" + integrity sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ== + dependencies: + buffer "^6.0.3" + inherits "^2.0.4" + readable-stream "^3.4.0" + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -3889,6 +3903,14 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + builtin-modules@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" @@ -4105,7 +4127,7 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^5.2.0: +chalk@^5.0.0, chalk@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== @@ -4219,7 +4241,14 @@ cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-spinners@^2.5.0: +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + +cli-spinners@^2.5.0, cli-spinners@^2.6.1: version "2.9.0" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.0.tgz#5881d0ad96381e117bbe07ad91f2008fe6ffd8db" integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g== @@ -7416,7 +7445,7 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -7923,6 +7952,11 @@ is-interactive@^1.0.0: resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== +is-interactive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90" + integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ== + is-invalid-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-invalid-path/-/is-invalid-path-0.1.0.tgz#307a855b3cf1a938b44ea70d2c61106053714f34" @@ -8148,7 +8182,7 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-unicode-supported@^1.2.0: +is-unicode-supported@^1.1.0, is-unicode-supported@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714" integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ== @@ -9234,6 +9268,14 @@ log-symbols@4.1.0, log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +log-symbols@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-5.1.0.tgz#a20e3b9a5f53fac6aeb8e2bb22c07cf2c8f16d93" + integrity sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA== + dependencies: + chalk "^5.0.0" + is-unicode-supported "^1.1.0" + longest-streak@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" @@ -11064,6 +11106,21 @@ ora@^5.4.1: strip-ansi "^6.0.0" wcwidth "^1.0.1" +ora@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-6.3.1.tgz#a4e9e5c2cf5ee73c259e8b410273e706a2ad3ed6" + integrity sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ== + dependencies: + chalk "^5.0.0" + cli-cursor "^4.0.0" + cli-spinners "^2.6.1" + is-interactive "^2.0.0" + is-unicode-supported "^1.1.0" + log-symbols "^5.1.0" + stdin-discarder "^0.1.0" + strip-ansi "^7.0.1" + wcwidth "^1.0.1" + os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -12583,6 +12640,14 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -13279,6 +13344,13 @@ std-env@^3.3.2, std-env@^3.3.3: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.3.3.tgz#a54f06eb245fdcfef53d56f3c0251f1d5c3d01fe" integrity sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg== +stdin-discarder@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.1.0.tgz#22b3e400393a8e28ebf53f9958f3880622efde21" + integrity sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ== + dependencies: + bl "^5.0.0" + stop-iteration-iterator@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" @@ -13414,6 +13486,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@4.0.0, strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878"