Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP/RFC: Plugin Support #265

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions layouts/categories/default.ejs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<!DOCTYPE html>
<html>
<%console.log(">>>>>>>>>>>>>>>>>>>", 'hi', locals.externalScripts) %>
<%- include('partials/head') %>
<body>
<h1 class="visually-hidden">Default template</h1>
Expand Down
4 changes: 2 additions & 2 deletions layouts/pages/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
<%- include('partials/search', {style: 'homepage', focus: 'autofocus', msgOnFocus: template('search.placeholder')}) %>

<div class="featured-cat">
<% if (modules.length) {
<% if (modules.length) {
modules.forEach((module, i, all) => {
%>
<%- include('partials/landingModule', module) %>
<% })
<% })
} else { %>
<!-- Eventually we might display a warning here about why this space is empty. -->
<% } %>
Expand Down
9 changes: 7 additions & 2 deletions layouts/partials/head.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<link rel="stylesheet"
href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/default.min.css">
<% if (locals.externalStyles) { locals.externalStyles.forEach(styleSrc => { %>
<link rel="stylesheet" href="<%= styleSrc %>">
<% })} %>

<% if (locals.inlineCSS) { %>
<style type="text/css"><%- inlineCSS %></style>
Expand All @@ -19,6 +20,10 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.js"></script>
<script src="/assets/scripts/main.js" charset="utf-8"></script>
<% } %>
<% console.log('LOCALS', locals.externalScripts) %>
<% if (locals.externalScripts) { locals.externalScripts.forEach(scriptSrc => { %>
<script src="<%= scriptSrc %>"></script>
<% })} %>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<link rel="shortcut icon" href="<%- template('branding.favicon') %>" type="image/x-icon" />
</head>
32 changes: 32 additions & 0 deletions library-plugin-syntax-highlight/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const hljs = require('highlight.js')

const externalStyles = ['//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/default.min.css']

const csp = {
styleSrc: ['cdnjs.cloudflare.com']
}

const transform = (html) => {
// find preprocessed code blocks
html = html.replace(/<pre><code>(.|\n)*?<\/code><\/pre>/igm, (match) => {
// try to find language hint within text block
const [, lang, codeText] = match.match(/^<pre><code>(.+)?\n((.|\n)*)<\/code><\/pre>/) || []

// remove language hint if it exists
if (lang) match = match.replace(`${lang}`, '')

// if supported by highlight.js, highlight!
if (lang && hljs.getLanguage(lang)) {
const highlighted = hljs.highlight(lang, codeText, true)
return `<pre><code data-lang="${highlighted.language}">${highlighted.value}</code></pre>`
}
return match
})
return html
}

module.exports = {
externalStyles,
transform,
csp
}
13 changes: 13 additions & 0 deletions library-plugin-syntax-highlight/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions library-plugin-syntax-highlight/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "library-plugin-syntax-highlight",
"version": "1.0.0",
"description": "A plugin for Library to highlight the syntax of code blocks\"",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "Apache-2.0",
"dependencies": {
"highlight.js": "^11.0.0"
}
}
22 changes: 15 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"google-auth-library": "^3.1.1",
"googleapis": "^48.0.0",
"helmet-csp": "^2.10.0",
"highlight.js": "^10.4.1",
"js-yaml": "^3.14.0",
"lodash": "^4.17.21",
"mime-types": "^2.1.27",
Expand All @@ -30,7 +29,8 @@
"slugify": "^1.4.5",
"unescape": "^1.0.1",
"winston": "^2.4.5",
"xlsx": "^0.16.7"
"xlsx": "^0.16.7",
"library-plugin-syntax-highlight": "file:./library-plugin-syntax-highlight"
},
"devDependencies": {
"concurrently": "^5.2.0",
Expand Down
13 changes: 13 additions & 0 deletions server/csp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const {csps} = require('./plugins')

const csp = {
defaultSrc: ["'self'", ...csps.flatMap((csp) => csp.defaultSrc || [])],
scriptSrc: ["'self'", "'unsafe-inline'", "cdnjs.cloudflare.com", "*.google-analytics.com", ...csps.flatMap((csp) => csp.scriptSrc || [])],
styleSrc: ["'self'", "'unsafe-inline'", "fonts.googleapis.com", "maxcdn.bootstrapcdn.com", "*.googleusercontent.com", ...csps.flatMap((csp) => csp.styleSrc || [])],
fontSrc: ["'self'", "fonts.gstatic.com", "maxcdn.bootstrapcdn.com", ...csps.flatMap((csp) => csp.fontSrc || [])],
imgSrc: ["'self'", "data:", "*.googleusercontent.com", "*.google-analytics.com", ...csps.flatMap((csp) => csp.imgSrc || [])],
frameSrc: ["'self'","data:","*.youtube.com", ...csps.flatMap((csp) => csp.iframeSrc || [])],
objectSrc: ["'none'", ...csps.flatMap((csp) => csp.objectSrc || [])]
}

module.exports = csp
9 changes: 0 additions & 9 deletions server/csp.json

This file was deleted.

12 changes: 2 additions & 10 deletions server/formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ const pretty = require('pretty')
const cheerio = require('cheerio')
const qs = require('querystring')
const unescape = require('unescape')
const hljs = require('highlight.js')
const list = require('./list')
const {transforms} = require('./plugins');

/* Your one stop shop for all your document processing needs. */

Expand Down Expand Up @@ -107,16 +107,7 @@ function formatCode(html) {
html = html.replace(/```(.*?)```/ig, (match, content) => {
// strip interior <p> tags added by google
content = content.replace(/(?:<\/p><p>|<br\/?>)/g, '\n').replace(/<\/?p>/g, '').trim()
// try to find language hint within text block
const [, lang] = content.match(/^([^\n]+)\n(.+)/) || []
if (lang) content = content.replace(`${lang}\n`, '')

const formattedContent = formatCodeContent(content)
if (lang && hljs.getLanguage(lang)) {
const textOnlyContent = cheerio.load(formattedContent).text()
const highlighted = hljs.highlight(lang, textOnlyContent, true)
return `<pre><code data-lang="${highlighted.language}">${highlighted.value}</code></pre>`
}
return `<pre><code>${formattedContent}</code></pre>`
})

Expand Down Expand Up @@ -231,6 +222,7 @@ function getProcessedHtml(src) {
let html = normalizeHtml(src)
html = convertYoutubeUrl(html)
html = formatCode(html)
transforms.forEach(transform => html = transform(html))
html = pretty(html)
return html
}
Expand Down
30 changes: 30 additions & 0 deletions server/plugins.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const packageJson = require('../package.json')

const transforms = []
const scriptSrcs = []
const styleSrcs = []
const csps = []

Object.keys(packageJson.dependencies).forEach(depName => {
if (depName.includes('library-plugin')) {
console.log(` 🔌 Registering ${depName}`)
const {transform, externalScripts = [], externalStyles = [], csp = {}} = require(depName)
if (transform) {
transforms.push(transform)
console.log(' ↳ Registered transform function')
}
scriptSrcs.push(...externalScripts)
console.log(` ↳ Registered ${externalScripts.length} external scripts`)
styleSrcs.push(...externalStyles)
console.log(` ↳ Registered ${externalStyles.length} external stylesheets`)
csps.push(csp)
console.log(` ↳ Registered ${Object.keys(csp).length} csp header additions`)
}
})

module.exports = {
transforms,
externalScripts: scriptSrcs,
externalStyles: styleSrcs,
csps
}
5 changes: 4 additions & 1 deletion server/routes/categories.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const {getMeta} = require('../list')
const {fetchDoc, cleanName} = require('../docs')
const {getTemplates, sortDocs, stringTemplate} = require('../utils')
const {parseUrl} = require('../urlParser')
const {externalScripts, externalStyles} = require('../plugins')

router.get('*', handleCategory)
module.exports = router
Expand Down Expand Up @@ -43,7 +44,9 @@ async function handleCategory(req, res) {
editLink: meta.mimeType === 'text/html' ? meta.folder.webViewLink : meta.webViewLink,
id,
template: stringTemplate,
duplicates
duplicates,
externalScripts,
externalStyles
})

// if this is a folder, just render from the generic data
Expand Down