diff --git a/demos/plugins/docs-link-update.js b/demos/plugins/docs-link-update.js deleted file mode 100644 index ede38fc89..000000000 --- a/demos/plugins/docs-link-update.js +++ /dev/null @@ -1,41 +0,0 @@ -// TODO: move into plugins folder as TS file. -const { - registerPlugin, - configValidator, - logWarn, - yellow -} = require('@scullyio/scully'); -const { JSDOM } = require('jsdom'); - -const docsLink = async (html, options) => { - try { - const dom = new JSDOM(html); - const { window } = dom; - const anchors = [...window.document.querySelectorAll('[href]')]; - anchors.forEach(a => { - const href = a.getAttribute('href'); - if ( - href && - href.toLowerCase().endsWith('.md') && - !href.toLowerCase().startsWith('http') - ) { - const newRef = `/docs/${href.slice(0, -3)}`; - a.setAttribute('href', newRef); - } - if (href && href.startsWith('#')) { - const newRef = `${options.route}${href}`; - a.setAttribute('href', newRef); - } - }); - return dom.serialize(); - } catch (e) { - logWarn( - `error in docsLink, didn't parse for route "${yellow(route.route)}"` - ); - } - // in case of failure return unchanged HTML to keep flow going - return html; -}; - -const validator = async config => []; -registerPlugin('render', 'docsLink', docsLink, validator); diff --git a/libs/plugins/docs-link-update/.eslintrc b/libs/plugins/docs-link-update/.eslintrc new file mode 100644 index 000000000..1655d7292 --- /dev/null +++ b/libs/plugins/docs-link-update/.eslintrc @@ -0,0 +1 @@ +{ "extends": "../../../.eslintrc", "rules": {}, "ignorePatterns": ["!**/*"] } diff --git a/libs/plugins/docs-link-update/README.md b/libs/plugins/docs-link-update/README.md new file mode 100644 index 000000000..c8967cbcc --- /dev/null +++ b/libs/plugins/docs-link-update/README.md @@ -0,0 +1,5 @@ +# scully-plugin-docs-link-update + +This is a helper plugin for people using the scully-content plugin with links to other markdown files +If looks for the `[href]` attribute. If the link in there starts with `#` it will put the full route in front of it, so that links _inside_ the page starts working when it's hosted. +It also looks for relative links that end with `.md` and do not start with `http`. For those links it updates the url so it will contain an url relative to the page the link is on. diff --git a/libs/plugins/docs-link-update/jest.config.js b/libs/plugins/docs-link-update/jest.config.js new file mode 100644 index 000000000..fd69dea36 --- /dev/null +++ b/libs/plugins/docs-link-update/jest.config.js @@ -0,0 +1,9 @@ +module.exports = { + name: 'plugins-docs-link-update', + preset: '../../../jest.config.js', + transform: { + '^.+\\.[tj]sx?$': 'ts-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], + coverageDirectory: '../../../coverage/libs/plugins/docs-link-update', +}; diff --git a/libs/plugins/docs-link-update/package.json b/libs/plugins/docs-link-update/package.json new file mode 100644 index 000000000..46bdde2cd --- /dev/null +++ b/libs/plugins/docs-link-update/package.json @@ -0,0 +1,10 @@ +{ + "name": "@scullyio/scully-plugin-docs-link-update", + "version": "0.0.1", + "peerDependencies": { + "@scullyio/scully": "*" + }, + "dependencies": { + "jsdom": "^16.2.2" + } +} diff --git a/libs/plugins/docs-link-update/src/index.ts b/libs/plugins/docs-link-update/src/index.ts new file mode 100644 index 000000000..a8b79c9a6 --- /dev/null +++ b/libs/plugins/docs-link-update/src/index.ts @@ -0,0 +1 @@ +export * from './lib/plugins-docs-link-update'; diff --git a/libs/plugins/docs-link-update/src/lib/plugins-docs-link-update.spec.ts b/libs/plugins/docs-link-update/src/lib/plugins-docs-link-update.spec.ts new file mode 100644 index 000000000..5ba16f89a --- /dev/null +++ b/libs/plugins/docs-link-update/src/lib/plugins-docs-link-update.spec.ts @@ -0,0 +1,7 @@ +import { pluginsDocsLinkUpdate } from './plugins-docs-link-update'; + +describe('pluginsDocsLinkUpdate', () => { + it('should work', () => { + expect(pluginsDocsLinkUpdate()).toEqual('plugins-docs-link-update'); + }); +}); diff --git a/libs/plugins/docs-link-update/src/lib/plugins-docs-link-update.ts b/libs/plugins/docs-link-update/src/lib/plugins-docs-link-update.ts new file mode 100644 index 000000000..4beda8019 --- /dev/null +++ b/libs/plugins/docs-link-update/src/lib/plugins-docs-link-update.ts @@ -0,0 +1,32 @@ +import { HandledRoute, logWarn, registerPlugin, yellow } from '@scullyio/scully'; +import { JSDOM } from 'jsdom'; + +export const docLink = 'docsLink'; + +const docsLinkPlugin = async (html: string, options: HandledRoute): Promise => { + try { + const dom = new JSDOM(html); + const { window } = dom; + const anchors = Array.from(window.document.querySelectorAll('[href]')); + anchors.forEach((a) => { + const href = a.getAttribute('href'); + if (href && href.toLowerCase().endsWith('.md') && !href.toLowerCase().startsWith('http')) { + const myBase = options.route.substring(0, options.route.lastIndexOf('/')); + const newRef = `${myBase}/${href.slice(0, -3)}`; + a.setAttribute('href', newRef); + } + if (href && href.startsWith('#')) { + const newRef = `${options.route}${href}`; + a.setAttribute('href', newRef); + } + }); + return dom.serialize(); + } catch (e) { + logWarn(`error in docsLink, didn't parse for route "${yellow(options.route)}"`); + } + // in case of failure return unchanged HTML to keep flow going + return html; +}; + +const validator = async (config) => []; +registerPlugin('render', docLink, docsLinkPlugin, validator); diff --git a/libs/plugins/docs-link-update/tsconfig.json b/libs/plugins/docs-link-update/tsconfig.json new file mode 100644 index 000000000..08c7db8c9 --- /dev/null +++ b/libs/plugins/docs-link-update/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "types": ["node", "jest"] + }, + "include": ["**/*.ts"] +} diff --git a/libs/plugins/docs-link-update/tsconfig.lib.json b/libs/plugins/docs-link-update/tsconfig.lib.json new file mode 100644 index 000000000..9c463b51e --- /dev/null +++ b/libs/plugins/docs-link-update/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "outDir": "../../../dist/out-tsc", + "declaration": true, + "rootDir": "./src", + "types": ["node"] + }, + "exclude": ["**/*.spec.ts"], + "include": ["**/*.ts"] +} diff --git a/libs/plugins/docs-link-update/tsconfig.spec.json b/libs/plugins/docs-link-update/tsconfig.spec.json new file mode 100644 index 000000000..65aff5094 --- /dev/null +++ b/libs/plugins/docs-link-update/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": ["**/*.spec.ts", "**/*.spec.tsx", "**/*.spec.js", "**/*.spec.jsx", "**/*.d.ts"] +} diff --git a/libs/scully/src/lib/renderPlugins/executePlugins.ts b/libs/scully/src/lib/renderPlugins/executePlugins.ts index 4e926674c..3d6d0b645 100644 --- a/libs/scully/src/lib/renderPlugins/executePlugins.ts +++ b/libs/scully/src/lib/renderPlugins/executePlugins.ts @@ -15,11 +15,11 @@ const executePluginsForRoute = async (route: HandledRoute) => { try { const prResult = await preRender(route); if (prResult === false) { - logError(`prerender stopped rendering for "${yellow(route.route)}". This route is skipped.`); + logError(`The prerender function stopped rendering for "${yellow(route.route)}". This route is skipped.`); return ''; } } catch (e) { - logError(`prerender trowed during rendering for "${yellow(route.route)}". This route is skipped.`); + logError(`The prerender function errorred out during rendering for "${yellow(route.route)}". This route is skipped.`); /** abort when prerender throws */ return ''; } diff --git a/nx.json b/nx.json index 6006c90e2..687710c23 100644 --- a/nx.json +++ b/nx.json @@ -51,6 +51,9 @@ }, "plugins-google-analytics": { "tags": [] + }, + "plugins-docs-link-update": { + "tags": [] } } } diff --git a/scully.scully-docs.config.ts b/scully.scully-docs.config.ts index 7aef85e39..0b3de33be 100644 --- a/scully.scully-docs.config.ts +++ b/scully.scully-docs.config.ts @@ -1,8 +1,8 @@ import { ScullyConfig, setPluginConfig, prod } from '@scullyio/scully'; import { DisableAngular } from 'scully-plugin-disable-angular'; -import './demos/plugins/docs-link-update'; import { LogRocket } from '@scullyio/plugins/logrocket'; import { GoogleAnalytics } from '@scullyio/plugins/google-analytics'; +import { docLink } from '@scullyio/scully-plugin-docs-link-update'; setPluginConfig('md', { enableSyntaxHighlighting: true }); @@ -37,7 +37,7 @@ export const config: ScullyConfig = { routes: { '/docs/:slug': { type: 'contentFolder', - postRenderers: ['docsLink', ...defaultPostRenderers], + postRenderers: [docLink, ...defaultPostRenderers], slug: { folder: './docs', }, diff --git a/tests/jest/src/__tests__/__snapshots__/docsThere.spec.ts.snap b/tests/jest/src/__tests__/__snapshots__/docsThere.spec.ts.snap index 45c8ab042..b433689ca 100644 --- a/tests/jest/src/__tests__/__snapshots__/docsThere.spec.ts.snap +++ b/tests/jest/src/__tests__/__snapshots__/docsThere.spec.ts.snap @@ -1117,7 +1117,7 @@ exports[`docsSite should have content for all markdown files check html for mark href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/default.min.css" >