diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5d12634 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..773205f --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +node_modules/ +lib/plugins/nuxtentBodyComponent.template.js +dist/ +nuxt/ diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..a661af0 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,28 @@ +{ + "root": true, + "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 8, + "sourceType": "module" + }, + "env": { + "node": true, + "es6": true + }, + "plugins": [ + "babel", + "ava" + ], + "extends": [ + "eslint-config-standard", + "eslint-config-i-am-meticulous", + "plugin:ava/recommended", + "eslint-config-prettier" + ], + "rules": { + "curly": [ + "error", + "all" + ] + } +} diff --git a/README.md b/README.md index dc83e19..657d62a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Nuxtent +[![js-standard-style](https://cdn.rawgit.com/standard/standard/master/badge.svg)](http://standardjs.com) + The goal of Nuxtent is to make using Nuxt for content heavy sites as easy as using Jekyll, Hugo, or any other static site generator. It does in two main ways: diff --git a/docs/nuxt.config.js b/docs/nuxt.config.js index f016b60..198663e 100644 --- a/docs/nuxt.config.js +++ b/docs/nuxt.config.js @@ -4,15 +4,15 @@ module.exports = { meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, - { hid: 'description', name: 'description', content: 'Nuxtent Documentation' } + { + hid: 'description', + name: 'description', + content: 'Nuxtent Documentation' + } ], - link: [ - { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } - ] + link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }] }, - modules: [ - 'nuxtent' - ], + modules: ['nuxtent'], css: [ 'prismjs/themes/prism-coy.css', { src: '~/assets/sass/base.sass', lang: 'sass' } diff --git a/docs/nuxtent.config.js b/docs/nuxtent.config.js index c5be098..c11fd68 100644 --- a/docs/nuxtent.config.js +++ b/docs/nuxtent.config.js @@ -6,29 +6,33 @@ module.exports = { page: 'guide/_slug', permalink: ':slug', isPost: false, - generate: [ - 'get', - 'getAll' - ] + generate: ['get', 'getAll'] }, parsers: { md: { highlight: (code, lang) => { - return Prism.highlight(code, Prism.languages[lang] || Prism.languages.markup) + return Prism.highlight( + code, + Prism.languages[lang] || Prism.languages.markup + ) }, use: [ - [externalLinks, { - target: '_blank', - rel: 'noopener' - }] + [ + externalLinks, + { + target: '_blank', + rel: 'noopener' + } + ] ] } }, api: { - baseURL: process.env.NODE_ENV === 'production' - ? 'https://nuxtent.now.sh' - : 'http://localhost:3000' + baseURL: + process.env.NODE_ENV === 'production' + ? 'https://nuxtent.now.sh' + : 'http://localhost:3000' } } diff --git a/docs/package.json b/docs/package.json index bbcce2d..59e13b1 100644 --- a/docs/package.json +++ b/docs/package.json @@ -9,7 +9,7 @@ "markdown-it-link-attributes": "^1.0.0", "nuxt": "1.0.0-alpha.3", "nuxtent": "0.2.59", - "prismjs": "^1.6.0" + "prismjs": "^1.8.1" }, "scripts": { "dev": "nuxt", diff --git a/examples/.eslintrc b/examples/.eslintrc new file mode 100644 index 0000000..8f2e1a6 --- /dev/null +++ b/examples/.eslintrc @@ -0,0 +1,5 @@ +{ + rules: { + "import/no-unresolved": 0 + } +} diff --git a/examples/content-navigation/nuxt.config.js b/examples/content-navigation/nuxt.config.js index a6df76c..f4e0404 100644 --- a/examples/content-navigation/nuxt.config.js +++ b/examples/content-navigation/nuxt.config.js @@ -5,9 +5,7 @@ module.exports = { { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: 'Nuxt.js project' } - ], + ] }, - modules: [ - 'nuxtent' - ] + modules: ['nuxtent'] } diff --git a/examples/content-navigation/nuxtent.config.js b/examples/content-navigation/nuxtent.config.js index a951e41..b298eeb 100644 --- a/examples/content-navigation/nuxtent.config.js +++ b/examples/content-navigation/nuxtent.config.js @@ -1,7 +1,7 @@ module.exports = { content: { page: '/guide/_slug', - permalink: ":slug", + permalink: ':slug', isPost: false } } diff --git a/examples/content-navigation/package.json b/examples/content-navigation/package.json index 2a9bf66..8a43419 100644 --- a/examples/content-navigation/package.json +++ b/examples/content-navigation/package.json @@ -6,7 +6,7 @@ "private": true, "dependencies": { "@nuxtjs/axios": "^2.2.1", - "nuxt": "^1.0.0-alpha.4", + "nuxt": "latest", "nuxtent": "latest" }, "scripts": { diff --git a/examples/custom-build/nuxt.config.js b/examples/custom-build/nuxt.config.js index a6df76c..f4e0404 100644 --- a/examples/custom-build/nuxt.config.js +++ b/examples/custom-build/nuxt.config.js @@ -5,9 +5,7 @@ module.exports = { { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: 'Nuxt.js project' } - ], + ] }, - modules: [ - 'nuxtent' - ] + modules: ['nuxtent'] } diff --git a/examples/custom-build/nuxtent.config.js b/examples/custom-build/nuxtent.config.js index b601c20..ea06a04 100644 --- a/examples/custom-build/nuxtent.config.js +++ b/examples/custom-build/nuxtent.config.js @@ -1,22 +1,28 @@ const Prism = require('prismjs') module.exports = { - content: { // basic content configuration + content: { + // basic content configuration permalink: ':slug', isPost: false }, - parser: { // custom parser options + parser: { + // custom parser options md: { highlight: (code, lang) => { - return Prism.highlight(code, Prism.languages[lang] || Prism.languages.markup) + return Prism.highlight( + code, + Prism.languages[lang] || Prism.languages.markup + ) } } }, - api: { // custom url for development and production builds - baseURL: process.env.NODE_ENV ? - 'https://production-url.now.sh' : - 'http://localhost:3000' + api: { + // custom url for development and production builds + baseURL: process.env.NODE_ENV + ? 'https://production-url.now.sh' + : 'http://localhost:3000' } } diff --git a/examples/custom-build/package.json b/examples/custom-build/package.json new file mode 100644 index 0000000..52aeb0f --- /dev/null +++ b/examples/custom-build/package.json @@ -0,0 +1,18 @@ +{ + "name": "nuxtent-example", + "version": "1.0.0", + "description": "nuxtent custom-build example", + "author": "Alid Castano ", + "dependencies": { + "@nuxtjs/axios": "^2.2.1", + "nuxt": "latest", + "nuxtent": "latest", + "prismjs": "^1.8.1" + }, + "scripts": { + "dev": "nuxt", + "build": "nuxt build", + "start": "nuxt start", + "generate": "nuxtent generate" + } +} diff --git a/examples/i18n/nuxt.config.js b/examples/i18n/nuxt.config.js index c70fe7f..72f3412 100755 --- a/examples/i18n/nuxt.config.js +++ b/examples/i18n/nuxt.config.js @@ -1,6 +1,4 @@ module.exports = { loading: { color: 'cyan' }, - modules: [ - 'nuxtent' - ] + modules: ['nuxtent'] } diff --git a/examples/i18n/nuxtent.config.js b/examples/i18n/nuxtent.config.js index 9ece0f1..bce45c2 100644 --- a/examples/i18n/nuxtent.config.js +++ b/examples/i18n/nuxtent.config.js @@ -3,8 +3,5 @@ const contentOptions = { } module.exports = { - content: [ - ['en', contentOptions], - ['fe', contentOptions] - ] + content: [['en', contentOptions], ['fe', contentOptions]] } diff --git a/examples/i18n/package.json b/examples/i18n/package.json index 31b43c6..0147041 100755 --- a/examples/i18n/package.json +++ b/examples/i18n/package.json @@ -3,7 +3,7 @@ "dependencies": { "@nuxtjs/axios": "^3.1.4", "nuxt": "latest", - "nuxtent": "file:///Users/acastano/Sites/nuxt/nuxtent" + "nuxtent": "latest" }, "scripts": { "dev": "nuxt", diff --git a/examples/markdown-components/content/HelloWorld.comp.md b/examples/markdown-components/content/HelloWorld.comp.md index f382880..8c74f18 100644 --- a/examples/markdown-components/content/HelloWorld.comp.md +++ b/examples/markdown-components/content/HelloWorld.comp.md @@ -1,5 +1,5 @@ --- -title: Hello World! +title: Markdown Component Demo! --- ### Here's my demo: @@ -10,24 +10,15 @@ title: Hello World! Template: -So it works on client side renderning but not on refresh... - -```html -
-

{{ name }}

-
``` + -Script: -```js + ``` diff --git a/examples/markdown-components/nuxt.config.js b/examples/markdown-components/nuxt.config.js index 36fc9c0..72dbf09 100644 --- a/examples/markdown-components/nuxt.config.js +++ b/examples/markdown-components/nuxt.config.js @@ -1,5 +1,3 @@ module.exports = { - modules: [ - 'nuxtent' - ] + modules: ['nuxtent'] } diff --git a/examples/markdown-components/nuxtent.config.js b/examples/markdown-components/nuxtent.config.js index dee73a6..43e8eea 100644 --- a/examples/markdown-components/nuxtent.config.js +++ b/examples/markdown-components/nuxtent.config.js @@ -1,8 +1,8 @@ module.exports = { content: { page: '/_slug', - permalink: "/:slug", + permalink: '/:slug', isPost: false, - generate: ['get'] + generate: ['get', 'getAll'] } } diff --git a/examples/markdown-components/package.json b/examples/markdown-components/package.json index b6d4cbf..c930ea4 100644 --- a/examples/markdown-components/package.json +++ b/examples/markdown-components/package.json @@ -6,13 +6,13 @@ "private": true, "dependencies": { "@nuxtjs/axios": "^2.2.1", - "nuxt": "^1.0.0-alpha.3", - "nuxtent": "file:///Users/acastano/Sites/nuxt/nuxtent" + "nuxt": "1.0.0-rc11", + "nuxtent": "latest" }, "scripts": { "dev": "nuxt", "build": "nuxt build", "start": "nuxt start", - "generate": "nuxt generate" + "generate": "nuxtent generate" } } diff --git a/examples/markdown-components/pages/_slug.vue b/examples/markdown-components/pages/_slug.vue index 3358018..5eaa571 100644 --- a/examples/markdown-components/pages/_slug.vue +++ b/examples/markdown-components/pages/_slug.vue @@ -1,11 +1,8 @@ @@ -13,19 +10,10 @@ diff --git a/examples/multiple-content-types/nuxt.config.js b/examples/multiple-content-types/nuxt.config.js index 36fc9c0..72dbf09 100644 --- a/examples/multiple-content-types/nuxt.config.js +++ b/examples/multiple-content-types/nuxt.config.js @@ -1,5 +1,3 @@ module.exports = { - modules: [ - 'nuxtent' - ] + modules: ['nuxtent'] } diff --git a/examples/multiple-content-types/nuxtent.config.js b/examples/multiple-content-types/nuxtent.config.js index 58c6a17..1850a78 100644 --- a/examples/multiple-content-types/nuxtent.config.js +++ b/examples/multiple-content-types/nuxtent.config.js @@ -1,15 +1,21 @@ module.exports = { content: [ - ['posts', { - page: '/_post', - permalink: ":year/:slug", - generate: ['get', 'getAll'] - }], - ['projects', { - page: '/projects/slug', - permalink: "/:slug", - isPost: false, - generate: ['get', 'getAll'] - }] + [ + 'posts', + { + page: '/_post', + permalink: ':year/:slug', + generate: ['get', 'getAll'] + } + ], + [ + 'projects', + { + page: '/projects/slug', + permalink: '/:slug', + isPost: false, + generate: ['get', 'getAll'] + } + ] ] } diff --git a/examples/multiple-content-types/package.json b/examples/multiple-content-types/package.json index f2158d9..8075977 100644 --- a/examples/multiple-content-types/package.json +++ b/examples/multiple-content-types/package.json @@ -5,7 +5,7 @@ "author": "Alid Castano ", "dependencies": { "@nuxtjs/axios": "^2.2.1", - "nuxt": "^1.0.0-rc3", + "nuxt": "latest", "nuxtent": "latest" }, "scripts": { diff --git a/examples/single-content-type/nuxt.config.js b/examples/single-content-type/nuxt.config.js index 066f286..1ca0e52 100644 --- a/examples/single-content-type/nuxt.config.js +++ b/examples/single-content-type/nuxt.config.js @@ -1,13 +1,13 @@ module.exports = { - modules: [ - 'nuxtent' - ], + modules: ['nuxtent'], nuxtent: { content: { page: '/_post', permalink: ':year/:slug', - generate: [ // assets to generate static build - 'get', 'getAll' + generate: [ + // assets to generate static build + 'get', + 'getAll' ] } } diff --git a/examples/single-content-type/package.json b/examples/single-content-type/package.json index be3ebee..9bdee31 100644 --- a/examples/single-content-type/package.json +++ b/examples/single-content-type/package.json @@ -5,7 +5,8 @@ "author": "Alid Castano ", "dependencies": { "@nuxtjs/axios": "^2.2.1", - "nuxt": "^1.0.0-rc11" + "nuxt": "latest", + "nuxtent": "latest" }, "scripts": { "dev": "nuxt", diff --git a/examples/sitemap/nuxt.config.js b/examples/sitemap/nuxt.config.js index ab37212..0000e48 100644 --- a/examples/sitemap/nuxt.config.js +++ b/examples/sitemap/nuxt.config.js @@ -1,25 +1,23 @@ const axios = require('axios') module.exports = { - modules: [ - 'nuxtent', - '@nuxtjs/sitemap' - ], + modules: ['nuxtent', '@nuxtjs/sitemap'], nuxtent: { content: { page: '/_post', permalink: ':year/:slug', - generate: [ // assets to generate static build - 'get', 'getAll' + generate: [ + // assets to generate static build + 'get', + 'getAll' ] } }, sitemap: { generate: true, routes: function () { - return axios.get('http://localhost:3000/content-api') - .then((res) => { - return res.data.map((page) => page.path ) + return axios.get('http://localhost:3000/content-api').then(res => { + return res.data.map(page => page.path) }) } } diff --git a/examples/sitemap/package.json b/examples/sitemap/package.json index 0b0f0bb..ec6d272 100644 --- a/examples/sitemap/package.json +++ b/examples/sitemap/package.json @@ -7,7 +7,7 @@ "@nuxtjs/axios": "^2.2.1", "@nuxtjs/sitemap": "0.0.3", "axios": "^0.16.2", - "nuxt": "^1.0.0-rc3", + "nuxt": "latest", "nuxtent": "latest" }, "scripts": { diff --git a/index.js b/index.js index 7f19959..c734eba 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -const nuxtentModule = require("./dist/module.js"); +const nuxtentModule = require('./dist/module.js') -module.exports = nuxtentModule.default; -module.exports.meta = nuxtentModule.meta; +module.exports = nuxtentModule.default +module.exports.meta = nuxtentModule.meta diff --git a/lib/content/api.js b/lib/content/api.js index 2b94e73..3bc7ceb 100644 --- a/lib/content/api.js +++ b/lib/content/api.js @@ -1,21 +1,24 @@ +import { join } from 'path' +import { parse } from 'querystring' + import chalk from 'chalk' -import createDatabase from './database' import { Router } from 'express' -const fs = require('fs') -const { join } = require('path') -const { parse } = require('querystring') +import createDatabase from './database' export default function createRouter (options) { const router = Router() // for multiple content types, show the content configuration in the root request if (!options.content['/']) { - router.use("/", new Router().get('/', (req, res) => { - response(res).json({ - 'content-endpoints': Object.keys(options.content) + router.use( + '/', + new Router().get('/', (req, res) => { + response(res).json({ + 'content-endpoints': Object.keys(options.content) + }) }) - })) + ) } Object.keys(options.content).forEach(dirName => { @@ -27,7 +30,7 @@ export default function createRouter (options) { } function curryResponseHandler (endpoint, options) { - const { sitePath, srcDir, api, content } = options + const { sitePath, srcDir, api } = options const contentPath = join(sitePath, srcDir) @@ -36,35 +39,38 @@ function curryResponseHandler (endpoint, options) { return function sendContent (req, res) { const send = response(res) const permalink = req.params['0'] + // eslint-disable-next-line no-unused-vars const [_, queryStr] = req.url.match(/\?(.*)/) || [] const { only, between, ...query } = parse(queryStr) logRequest(permalink, api.serverPrefix, api.baseURL) - if (permalink === '/') { // request multiple pages from directory - if (between) send.json(db.findBetween(between, query)) - else if (only) send.json(db.findOnly(only, query)) - else send.json(db.findAll(query)) - } else { // request single page - if (db.exists(permalink)) send.json(db.find(permalink, query)) - else send.notFound() + if (permalink === '/') { + // request multiple pages from directory + if (between) {send.json(db.findBetween(between, query))} + else if (only) {send.json(db.findOnly(only, query))} + else {send.json(db.findAll(query))} + } else { + // request single page + if (db.exists(permalink)) {send.json(db.find(permalink, query))} + else {send.notFound()} } } } -export const response = (res) => ({ - json(data) { +export const response = res => ({ + json (data) { res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify(data), 'utf-8') console.log(` Response sent successfully.`) }, - error(err) { - console.log(` Failed to send response.`, error) + error (err) { + console.log(` Failed to send response.`, err) res.statusCode = 500 res.statusMessage = 'Internal Server Error' res.end(err.stack || String(err)) }, - notFound() { + notFound () { console.log(` Page not found.`) res.statusCode = 404 res.statusMessage = 'Not Found' @@ -73,6 +79,8 @@ export const response = (res) => ({ }) function logRequest (permalink, apiPrefix, baseURL) { - console.log(`${chalk.blue(apiPrefix)} ${chalk.green('GET')} ${baseURL + permalink}`) + console.log( + `${chalk.blue(apiPrefix)} ${chalk.green('GET')} ${baseURL + permalink}` + ) return permalink } diff --git a/lib/content/build.js b/lib/content/build.js index 31a8e30..a6f75aa 100644 --- a/lib/content/build.js +++ b/lib/content/build.js @@ -1,9 +1,9 @@ -import createDatabase from './database' +import { join } from 'path' -const { isArray, concat } = Array -const { join } = require('path') +import createDatabase from './database' -const buildPath = (permalink, section, { buildDir }) => { // browser build path +const buildPath = (permalink, section, { buildDir }) => { + // browser build path // convert the permalink's slashes to periods so that // generated content is not overly nested const allButFirstSlash = /(?!^\/)\// @@ -11,13 +11,21 @@ const buildPath = (permalink, section, { buildDir }) => { // browser build path return join(buildDir, section, filePath) + '.json' } -const routeName = (routePath) => { +const routeName = routePath => { const firstSlash = /^\// - return routePath.replace(firstSlash, '').replace('/', '-').replace('_', '') + return routePath + .replace(firstSlash, '') + .replace('/', '-') + .replace('_', '') } -const asset = (object) => { // webpack asset - const content = JSON.stringify(object, null, process.env.NODE_ENV === 'production' ? 0 : 2) +const asset = object => { + // webpack asset + const content = JSON.stringify( + object, + null, + process.env.NODE_ENV === 'production' ? 0 : 2 + ) return { source: () => content, size: () => content.length } } @@ -28,9 +36,9 @@ const asset = (object) => { // webpack asset export default function buildContent ({ nuxt, options }) { const { sitePath, srcDir, content } = options - let routePages = [] // dynamic pages to create - let routePaths = new Map() // paths to reconfigure - let assetMap = new Map() // browser assets to generate + const routePages = [] // dynamic pages to create + const routePaths = new Map() // paths to reconfigure + const assetMap = new Map() // browser assets to generate Object.keys(content).forEach(dirName => { const { page, generate, permalink } = content[dirName] @@ -48,7 +56,7 @@ export default function buildContent ({ nuxt, options }) { generate.forEach(reqType => { const req = {} if (typeof reqType === 'string') { - req['method'] = reqType + req['method'] = reqType } else if (Array.isArray(reqType)) { const [reqMethod, reqOptions] = reqType req['method'] = reqMethod @@ -57,14 +65,17 @@ export default function buildContent ({ nuxt, options }) { } switch (req['method']) { - case 'get': - if (!page) throw new Error('You must specify a page path') + case 'get': { + if (!page) { + throw new Error('You must specify a page path') + } const pathPrefix = getPrefix(name) - db.findAll(req['query']).forEach((page) => { + db.findAll(req['query']).forEach(page => { routePages.push(join(pathPrefix, page.permalink)) assetMap.set(buildPath(page.permalink, dirName, options), page) }) break + } case 'getAll': assetMap.set( buildPath('_all', dirName, options), @@ -78,7 +89,9 @@ export default function buildContent ({ nuxt, options }) { ) break default: - throw new Error(`The ${req['method']} is not supported for static builds.`) + throw new Error( + `The ${req['method']} is not supported for static builds.` + ) } }) } @@ -98,8 +111,7 @@ function interceptRoutes (nuxt, routePaths) { route.children.forEach(nestedRoute => { if (routePaths.has(nestedRoute.name)) { const isOptional = nestedRoute.path.match(/\?$/) - if (isOptional) nestedRoute.path = routePaths.get(nestedRoute.name) + '?' - else nestedRoute.path = routePaths.get(nestedRoute.name) + if (isOptional) { nestedRoute.path = routePaths.get(nestedRoute.name) + '?' } else {nestedRoute.path = routePaths.get(nestedRoute.name)} } }) } @@ -108,16 +120,16 @@ function interceptRoutes (nuxt, routePaths) { } function addRoutes (nuxtOpts, routeData) { - if (!('generate' in nuxtOpts)) nuxtOpts.generate = {} - if (!('routes' in nuxtOpts.generate)) nuxtOpts.generate.routes = [] + if (!('generate' in nuxtOpts)) {nuxtOpts.generate = {}} + if (!('routes' in nuxtOpts.generate)) {nuxtOpts.generate.routes = []} const { routes } = nuxtOpts.generate - if (isArray(routes)) nuxtOpts.generate.routes = routes.concat(routeData) - else throw new Error(`"generate.routes" must be an array`) + if (Array.isArray(routes)) {nuxtOpts.generate.routes = routes.concat(routeData)} + else {throw new Error(`"generate.routes" must be an array`)} } function addAssets (nuxtOpts, assetMap) { nuxtOpts.build.plugins.push({ - apply(compiler) { + apply (compiler) { compiler.plugin('emit', (compilation, cb) => { assetMap.forEach((page, buildPath) => { compilation.assets[buildPath] = asset(page) @@ -131,8 +143,9 @@ function addAssets (nuxtOpts, assetMap) { function getPrefix (routeName, topLevelPrefix = '/') { const result = routeName.match(/(^[a-zA-Z]*)(-)/) // matches `prefix-` if (result) { + // eslint-disable-next-line no-unused-vars const [_, prefix] = result - if (prefix !== 'index') return join('/', prefix) + if (prefix !== 'index') {return join('/', prefix)} } return topLevelPrefix } diff --git a/lib/content/database.js b/lib/content/database.js index 1f6fca3..164ad5a 100644 --- a/lib/content/database.js +++ b/lib/content/database.js @@ -1,7 +1,8 @@ +import { join } from 'path' +import { readdirSync, statSync } from 'fs' + import prepPage from './page' -const { readdirSync, statSync } = require('fs') -const { join } = require('path') const { max, min } = Math export default function createDatabase (contentPath, dirName, options) { @@ -9,15 +10,18 @@ export default function createDatabase (contentPath, dirName, options) { const dirPath = join(contentPath, dirName) const dirOpts = { ...content[dirName], parsers } - const pagesMap = globAndApply(dirPath, new Map(), - ({ index, fileName, section }, store ) => { + const pagesMap = globAndApply( + dirPath, + new Map(), + ({ index, fileName, section }, store) => { const filePath = join(contentPath, dirName, section, fileName) const meta = { index, fileName, section, dirName, filePath } - const lazyPage = prepPage(meta, dirOpts,isDev) + const lazyPage = prepPage(meta, dirOpts, isDev) store.set(lazyPage.permalink, lazyPage) - }) + } + ) - const pagesArr = [ ...pagesMap.values() ] + const pagesArr = [...pagesMap.values()] return { exists (permalink) { @@ -28,18 +32,20 @@ export default function createDatabase (contentPath, dirName, options) { return pagesMap.get(permalink).create(query) }, - findOnly(onlyArg, query) { - if (typeof onlyArg === 'string') onlyArg = onlyArg.split(',') + findOnly (onlyArg, query) { + if (typeof onlyArg === 'string') {onlyArg = onlyArg.split(',')} const [startIndex, endIndex] = onlyArg let currIndex = max(0, parseInt(startIndex)) - let finalIndex = endIndex !== undefined - ? min(parseInt(endIndex), pagesArr.length - 1) : null + const finalIndex = + endIndex !== undefined + ? min(parseInt(endIndex), pagesArr.length - 1) + : null - if (!finalIndex) return pagesArr[currIndex].create(query) + if (!finalIndex) {return pagesArr[currIndex].create(query)} const pages = [] - while(currIndex <= finalIndex && finalIndex !== 0) { + while (currIndex <= finalIndex && finalIndex !== 0) { pages.push(pagesArr[currIndex]) currIndex++ } @@ -47,28 +53,28 @@ export default function createDatabase (contentPath, dirName, options) { return pages.map(page => page.create(query)) }, - findBetween(betweenStr, query) { + findBetween (betweenStr, query) { const { findOnly } = this const [currPermalink, numStr1, numStr2] = betweenStr.split(',') - if (!pagesMap.has(currPermalink)) return [] + if (!pagesMap.has(currPermalink)) {return []} const currPage = pagesMap.get(currPermalink).create(query) const { index } = currPage.meta - const total = pagesArr.length -1 + const total = pagesArr.length - 1 const num1 = parseInt(numStr1 || 0) const num2 = numStr2 !== undefined ? parseInt(numStr2) : null - if (num1 === 0 && num2 === 0) return [currPage] + if (num1 === 0 && num2 === 0) {return [currPage]} let beforeRange - if (num1 === 0) beforeRange = [] - else beforeRange = [max(0, index - num1), max(min(index - 1, total), 0)] + if (num1 === 0) {beforeRange = []} + else {beforeRange = [max(0, index - num1), max(min(index - 1, total), 0)]} let afterRange - if (num2 === 0 || (!num2 && num1 === 0)) afterRange = [] - else afterRange = [min(index + 1, total), min(index + (num2 || num1), total)] + if (num2 === 0 || (!num2 && num1 === 0)) {afterRange = []} + else { afterRange = [min(index + 1, total), min(index + (num2 || num1), total)] } const beforePages = findOnly(beforeRange, query) const afterPages = findOnly(afterRange, query) @@ -86,10 +92,10 @@ function globAndApply (dirPath, fileStore, applyFn, nestedPath = '/') { const stats = readdirSync(dirPath).reverse() // posts more useful in reverse order stats.forEach((stat, index) => { const statPath = join(dirPath, stat) - if(statSync(statPath).isFile()) { + if (statSync(statPath).isFile()) { const fileData = { index, fileName: stat, section: nestedPath } applyFn(fileData, fileStore) - } else globAndApply(statPath, fileStore, applyFn, join(nestedPath, stat)) + } else {globAndApply(statPath, fileStore, applyFn, join(nestedPath, stat))} }) return fileStore } diff --git a/lib/content/page.js b/lib/content/page.js index dd77120..d68f803 100644 --- a/lib/content/page.js +++ b/lib/content/page.js @@ -1,28 +1,37 @@ -const { existsSync, readFileSync, statSync } = require('fs') -const { join } = require('path') -const fm = require('front-matter') -const moment = require('moment') -const paramCase = require('param-case') -const permalinkCompiler = require('path-to-regexp').compile +import { join } from 'path' +import { readFileSync, statSync } from 'fs' + +import fm from 'front-matter' +import moment from 'moment' +import paramCase from 'param-case' +import pathToRegexp from 'path-to-regexp' + +const permalinkCompiler = pathToRegexp.compile export default function prepPage (meta, options, isDev) { const cached = {} return { create (params = {}) { - const props = new Set( - ['meta', 'date', 'path', 'permalink', 'anchors', 'attributes', 'body'] - ) + const props = new Set([ + 'meta', + 'date', + 'path', + 'permalink', + 'anchors', + 'attributes', + 'body' + ]) if (params.exclude) { params.exclude.split(',').forEach(prop => { - if (props.has(prop)) props.delete(prop) + if (props.has(prop)) {props.delete(prop)} }) } let data = {} props.forEach(prop => { - if (prop === 'attributes') data = { ...this[prop], ...data } - else data[prop] = this[prop] + if (prop === 'attributes') {data = { ...this[prop], ...data }} + else {data[prop] = this[prop]} }) return data @@ -34,9 +43,9 @@ export default function prepPage (meta, options, isDev) { get path () { const { permalink } = this - if (isDev || !options.routes) return permalink + if (isDev || !options.routes) {return permalink} const dynamicRoute = options.routes.find(route => route.method === 'get') - const nestedPath = /([^_][a-zA-z]*?)\/[^a-z\_]*/ + const nestedPath = /([^_][a-zA-z]*?)\/[^a-z_]*/ const matchedPath = dynamicRoute.path.match(nestedPath) if (matchedPath && matchedPath[1] !== 'index') { return join(matchedPath[1] + permalink) @@ -53,8 +62,10 @@ export default function prepPage (meta, options, isDev) { const { year, month, day } = splitDate(date) const params = { section, slug, date, year, month, day } const toPermalink = permalinkCompiler(options.permalink) - cached.permalink = join('/', toPermalink(params, { pretty: true }) - .replace(/%2F/gi, "/")) // make url encoded slash pretty + cached.permalink = join( + '/', + toPermalink(params, { pretty: true }).replace(/%2F/gi, '/') + ) // make url encoded slash pretty } return cached.permalink }, @@ -65,23 +76,28 @@ export default function prepPage (meta, options, isDev) { const { _rawData } = this const level = options.anchorsLevel - const anchorsExp = new RegExp([ - '(`{3}[\\s\\S]*?`{3}|`{1}[^`].*?`{1}[^`]*?)', // code snippet - `(#{${level + 1},})`, // other heading - `(?:^|\\s)#{${level}}[^#](.*)`, // heading text - ].join('|'), 'g') + const anchorsExp = new RegExp( + [ + '(`{3}[\\s\\S]*?`{3}|`{1}[^`].*?`{1}[^`]*?)', // code snippet + `(#{${level + 1},})`, // other heading + `(?:^|\\s)#{${level}}[^#](.*)` // heading text + ].join('|'), + 'g' + ) let result - let anchors = [] - while (result = anchorsExp.exec(_rawData)) { - let [match, codeSnippet, otherHeading, headingText] = result + const anchors = [] + while ((result = anchorsExp.exec(_rawData))) { + // eslint-disable-next-line no-unused-vars + const [match, codeSnippet, otherHeading, headingText] = result if (!(codeSnippet || otherHeading) && headingText) { const anchor = `#${paramCase(headingText)}` anchors.push([anchor, headingText]) } } cached.anchors = anchors - } else { // yaml file + } else { + // yaml file cached.anchors = [] } } @@ -98,16 +114,16 @@ export default function prepPage (meta, options, isDev) { const { parsers } = options const { dirName, section, fileName } = meta if (fileName.search(/\.comp\.md$/) > -1) { - const relativePath = '.' + join(dirName, section, fileName) + const relativePath = '.' + join(dirName, section, fileName) cached.body = { relativePath // component body compiled by loader and imported separately } } else if (fileName.search(/\.md$/) > -1) { - cached.body = parsers.mdParser(parsers.md, options) + cached.body = parsers + .mdParser(parsers.md, options) .render(_rawData.body) // markdown to html } else if (fileName.search(/\.yaml$/) > -1) { - cached.body = parsers.yamlParser() - .render(_rawData.body) // yaml to json + cached.body = parsers.yamlParser().render(_rawData.body) // yaml to json } } return cached.body @@ -118,7 +134,7 @@ export default function prepPage (meta, options, isDev) { const { filePath, fileName, section } = meta if (options.isPost) { const fileDate = fileName.match(/!?(\d{4}-\d{2}-\d{2})/) // YYYY-MM-DD - if (!fileDate) throw Error(`Post in "${section}" does not have a date!`) + if (!fileDate) { throw Error(`Post in "${section}" does not have a date!`) } cached.date = fileDate[0] } else { const stats = statSync(filePath) @@ -128,7 +144,6 @@ export default function prepPage (meta, options, isDev) { return cached.date }, - get _rawData () { if (isDev || !cached.data) { const source = readFileSync(meta.filePath).toString() @@ -147,13 +162,13 @@ export default function prepPage (meta, options, isDev) { function getSlug (fileName) { const onlyName = fileName .replace(/(\.comp)?(\.[0-9a-z]+$)/, '') // remove any ext - .replace(/!?(\d{4}-\d{2}-\d{2}-)/, '') // remove date and hypen + .replace(/!?(\d{4}-\d{2}-\d{2}-)/, '') // remove date and hypen return paramCase(onlyName) } function splitDate (date) { const dateData = date.split('-') - return { + return { year: dateData[0], month: dateData[1], day: dateData[2] diff --git a/lib/loader.js b/lib/loader.js index cfd2573..b7be998 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -1,17 +1,17 @@ -const fs = require('fs') -const loaderUtils = require('loader-utils') -const { existsSync, readFileSync } = require('fs') +const { existsSync } = require('fs') const { join } = require('path') + +const loaderUtils = require('loader-utils') const uppercamelcase = require('uppercamelcase') const paramCase = require('param-case') const fm = require('front-matter') -const mdCompParser = (mdParser) => { +const mdCompParser = mdParser => { // we need to add the `v-pre` snippet to code snippets so // that mustage tags (`{{ }}`) are interpreted as raw text - const codeRules = ['code_inline', 'code_block', 'fence' ] - const parser = mergeParserRules(mdParser, codeRules, (str) => { - return str.replace(/( { + return str.replace(/( { const mdComponent = (source, moduleOpts, dirOpts) => { const { sitePath, componentsDir, parsers } = moduleOpts - const compExp = new RegExp([ - '(`{3}[\\s\\S]*?`{3}|`{1}[^`].*?`{1}[^`])', // code snippet - '@\\[(.*?)\\](?:\\((.*?)\\))?', // markdown component - '@[]' or '@[]()' - ].join('|'), 'g') + const compExp = new RegExp( + [ + '(`{3}[\\s\\S]*?`{3}|`{1}[^`].*?`{1}[^`])', // code snippet + '@\\[(.*?)\\](?:\\((.*?)\\))?' // markdown component - '@[]' or '@[]()' + ].join('|'), + 'g' + ) let result const comps = {} - while (result = compExp.exec(source)) { - let [match, codeSnippet, name, props] = result + while ((result = compExp.exec(source))) { + const [match, codeSnippet, name, props] = result if (!codeSnippet) { const compName = uppercamelcase(paramCase(name)) if (!comps[compName]) { @@ -42,7 +45,7 @@ const mdComponent = (source, moduleOpts, dirOpts) => { const { mdParser, md } = parsers return { - template: mdCompParser(parsers.mdParser(md, dirOpts)).render(source), + template: mdCompParser(mdParser(md, dirOpts)).render(source), components: comps } } @@ -58,7 +61,8 @@ module.exports = function (source) { const { template, components } = mdComponent(body, moduleOpts, dirOpts) const allImports = Object.keys(components) - .map(key => `import ${key} from '~/components/${components[key]}'`).join('\n') + .map(key => `import ${key} from '~/components/${components[key]}'`) + .join('\n') const allComponents = Object.keys(components).join(', ') @@ -84,7 +88,7 @@ function mergeParserRules (parser, rules, fn) { if (parser.renderer && parser.renderer.rules) { const parserRules = parser.renderer.rules rules.forEach(function (rule) { - if (!parserRules[rule]) return + if (!parserRules[rule]) {return} const defaultRule = parserRules[rule] parserRules[rule] = function () { return fn(defaultRule.apply(this, arguments)) @@ -98,18 +102,19 @@ function getDirOpts (moduleOpts, section) { // configuration options can be for root files ('/') but regex for section also // captures closest subsection, so we first check that since you can't configure // both root files and nested sections - if (moduleOpts.content['/']) return moduleOpts.content['/'] - else return moduleOpts.content[section] + if (moduleOpts.content['/']) {return moduleOpts.content['/']} + else {return moduleOpts.content[section]} } function getSection (path) { // capture '/content/closestSubsection' or '/content' - const [match, section] = path.match(/\/content([\/][a-zA-Z\-_]*|$)/) + // eslint-disable-next-line no-unused-vars + const [match, section] = path.match(/\/content([/][a-zA-Z\-_]*|$)/) return section === '' ? '/' : section } -function getExt(basePath, name) { - if (existsSync(basePath + name + '.vue')) return '.vue' - else if (existsSync(basePath + name + '.js')) return '.js' - else throw new Error(`"${name}" does not exist at ${basePath}`) +function getExt (basePath, name) { + if (existsSync(basePath + name + '.vue')) {return '.vue'} + else if (existsSync(basePath + name + '.js')) {return '.js'} + else {throw new Error(`"${name}" does not exist at ${basePath}`)} } diff --git a/lib/module.js b/lib/module.js index 271a369..d0a7d30 100644 --- a/lib/module.js +++ b/lib/module.js @@ -1,11 +1,11 @@ import { resolve, join } from 'path' +import pkg from '../package.json' + import createRouter from './content/api' import buildContent from './content/build' import { mdParser, yamlParser } from './util/parsers' -import pkg from '../package.json' - const nuxtentConfig = (nuxtOpts) => { const rootConfig = resolve(nuxtOpts.rootDir, 'nuxtent.config.js') try { @@ -19,100 +19,115 @@ const nuxtentConfig = (nuxtOpts) => { } const contentOptions = (content, defaults) => { - const opts = {} - if (!Array.isArray(content)) opts['/'] = { ...defaults, ...content } - else { - content.forEach(strOrArr => { - const dirName = Array.isArray(strOrArr) ? strOrArr[0] : strOrArr - const dirOpts = Array.isArray(strOrArr) ? strOrArr[1] : {} - if (dirName === '/' && registered.length > 1) { // prevent endpoint conflict - throw new Error('Top level files not allowed with nested registered directories') - } - opts[join('/', dirName)] = { ...defaults, ...dirOpts } - }) - } - return opts + const opts = {} + if (!Array.isArray(content)) { + opts['/'] = { ...defaults, ...content } + } else { + content.forEach(strOrArr => { + const dirName = Array.isArray(strOrArr) ? strOrArr[0] : strOrArr + const dirOpts = Array.isArray(strOrArr) ? strOrArr[1] : {} + if (dirName === '/' && content.length > 1) { + // prevent endpoint conflict + throw new Error( + 'Top level files not allowed with nested registered directories' + ) + } + opts[join('/', dirName)] = { ...defaults, ...dirOpts } + }) + } + return opts } -export default function ContentModule(moduleOpts) { - const userOptions = nuxtentConfig(this.options) - - const options = { - isDev: this.nuxt.options.dev, - srcPath: this.options.rootDir, - sitePath: this.options.srcDir, - srcDir: '/content', - componentsDir: '/components', - buildDir: `/content`, - isStatic: userOptions.isStatic || process.env.STATIC || false, - - content: contentOptions(userOptions.content, { - page: null, - permalink: ':slug', - anchorsLevel: 1, - isPost: true, - generate: [] - }), - - parsers: { - md: Object.assign({}, { - highlight: null, - use: [] - }, userOptions.parsers && userOptions.parsers.md ? userOptions.parsers.md : {}), - mdParser, - yamlParser - }, - - api: { - baseURL: '', - ...userOptions.api, - serverPrefix: `/content-api`, - browserPrefix: `/_nuxt/content` - } - } - - const { srcDir, content, api } = options - - // 1. Configure and build dynamic content pages - - this.extendBuild(config => { - config.module.rules.push({ - test: /\.comp\.md$/, - use: [ - 'vue-loader', - { loader: 'nuxtent/dist/loader.js', options } - ] - }) - }) - - buildContent({ - nuxt: this, - options - }) - - // 2. Add content API - - this.addServerMiddleware({ - path: api.serverPrefix, - handler: createRouter(options) - }) - - // 3. Add request helpers - - this.requireModule([ - '@nuxtjs/axios', { - baseURL: api.baseURL + api.serverPrefix, - browserBaseURL: api.baseURL + (process.env.STATIC ? api.browserPrefix : api.serverPrefix) - } - ]) - - this.addPlugin({ - src: resolve(__dirname, 'plugin.js'), - options: { - ...options, - srcDirFromPlugin: join('~/', srcDir) - } - }) +export default function ContentModule (moduleOpts) { + const userOptions = nuxtentConfig(this.options) + + const options = { + isDev: this.nuxt.options.dev, + srcPath: this.options.rootDir, + sitePath: this.options.srcDir, + srcDir: '/content', + componentsDir: '/components', + buildDir: `/content`, + isStatic: userOptions.isStatic || process.env.STATIC || false, + + content: contentOptions(userOptions.content, { + page: null, + permalink: ':slug', + anchorsLevel: 1, + isPost: true, + generate: [] + }), + + parsers: { + md: Object.assign( + {}, + { + highlight: null, + use: [] + }, + userOptions.parsers && userOptions.parsers.md + ? userOptions.parsers.md + : {} + ), + mdParser, + yamlParser + }, + + api: { + baseURL: '', + ...userOptions.api, + serverPrefix: `/content-api`, + browserPrefix: `/_nuxt/content` + } + } + + const { srcDir, api } = options + + // 1. Configure and build dynamic content pages + + this.extendBuild(config => { + config.module.rules.push({ + test: /\.comp\.md$/, + use: ['vue-loader', { loader: 'nuxtent/dist/loader.js', options }] + }) + }) + + buildContent({ + nuxt: this, + options + }) + + // 2. Add content API + + this.addServerMiddleware({ + path: api.serverPrefix, + handler: createRouter(options) + }) + + // 3. Add request helpers + + this.requireModule([ + '@nuxtjs/axios', + { + baseURL: api.baseURL + api.serverPrefix, + browserBaseURL: + api.baseURL + + (process.env.STATIC ? api.browserPrefix : api.serverPrefix) + } + ]) + + this.addPlugin({ + src: resolve(__dirname, 'plugins/requestContent.js') + }) + + // 4. Add Markdown Components + + this.addPlugin({ + src: resolve(__dirname, 'plugins/markdownComponents.js'), + options: { + srcDirFromPlugin: join('~/', srcDir) + } + }) } export { pkg as meta } diff --git a/lib/plugins/markdownComponents.js b/lib/plugins/markdownComponents.js new file mode 100644 index 0000000..7029d90 --- /dev/null +++ b/lib/plugins/markdownComponents.js @@ -0,0 +1,27 @@ +import Vue from 'vue' + +const mdComps = {} + +function importAllMdComps (r) { + r.keys().forEach(key => (mdComps[key] = r(key).default)) +} + +importAllMdComps( + require.context(<%= JSON.stringify(options.srcDirFromPlugin) %>, true, /\.comp\.md$/) +) + +Vue.component('nuxtent-body', { + render (h) { + if (typeof this.body === 'object' && this.body.relativePath) { + const MarkdownComponent = mdComps[this.body.relativePath] + return + } else { + return
+ } + }, + props: { + body: { + type: [Object, String] + } + } +}); diff --git a/lib/plugin.js b/lib/plugins/requestContent.js similarity index 55% rename from lib/plugin.js rename to lib/plugins/requestContent.js index 7e7bd55..d22f696 100644 --- a/lib/plugin.js +++ b/lib/plugins/requestContent.js @@ -1,46 +1,29 @@ -import Vue from 'vue' +import { join } from 'path' -const { join } = require('path') +function toQuery (options = {}) { + const exclude = options.exclude + if (!exclude) {return ''} -const options = <%= JSON.stringify(options) %> -const mdComps = {} + if (Array.isArray(exclude)) {return 'exclude=' + exclude.join(',')} -function importAllMdComps (r) { - r.keys().forEach(key => mdComps[key] = r(key)) + return 'exclude=' + exclude } -importAllMdComps(require.context( - <%= JSON.stringify(options.srcDirFromPlugin) %>, true, /\.comp\.md$/ -)) - -Vue.component('nuxtent-body', { - functional: true, - props: { - body: { required: true } - }, - render (h, ctx) { - const { body } = ctx.props - if (typeof body === 'object') { - const MarkdownComponent = mdComps[body.relativePath] - return ( ) - } else { - return (
) - } - } -}) - -export default ({ app, isServer, isClient, hotReload, route }) => { - const isNotContentReq = hotReload || route.fullPath.includes('__webpack_hmr?') || route.fullPath.includes('.hot-update.') - if (isNotContentReq) return +export default ({ app, isServer, isClient, isStatic, hotReload, route }) => { + const isNotContentReq = + hotReload || + route.fullPath.includes('__webpack_hmr?') || + route.fullPath.includes('.hot-update.') + if (isNotContentReq) {return} - const isAPI = isServer || !options.isStatic + const isAPI = isServer || !isStatic const cache = {} async function fetchContent (path, permalink, query = '') { if (isAPI) { const apiEndpoint = join(path, permalink + query) - if (options.isDev || !cache[apiEndpoint]) { - cache[apiEndpoint] = (await app.$axios.get(apiEndpoint)).data + if (!isStatic || !cache[apiEndpoint]) { + cache[apiEndpoint] = (await app.$axios.get(apiEndpoint)).data } return cache[apiEndpoint] } else if (isClient) { @@ -51,21 +34,23 @@ export default ({ app, isServer, isClient, hotReload, route }) => { cache[browserPath] = (await app.$axios.get(browserPath)).data } return cache[browserPath] - } - else { - return // static server build + } else { + // static server build } } app.$content = function requestMethod (contentDir) { let query = '' return { - query (options) { // per page query + query (options = {}) { + // per page query query = toQuery(options) return this }, async get (permalink) { - if (typeof permalink !== 'string') throw Error(`Permalink must be a string.`) + if (typeof permalink !== 'string') { + throw Error(`Permalink must be a string.`) + } return await fetchContent(contentDir, permalink, '?' + query) }, async getBetween (permalink, num1or2, num2 = '') { @@ -87,12 +72,3 @@ export default ({ app, isServer, isClient, hotReload, route }) => { } } } - -function toQuery (options = {}) { - let exclude = options.exclude - if (!exclude) return '' - - if (Array.isArray(exclude)) return 'exclude=' + exclude.join(',') - - return 'exclude=' + exclude -} diff --git a/lib/util/parsers.js b/lib/util/parsers.js index 94da231..d49a834 100644 --- a/lib/util/parsers.js +++ b/lib/util/parsers.js @@ -1,6 +1,6 @@ -const yamlit = require('js-yaml') -const markdownit = require('markdown-it') -const markdownAnchors = require('markdown-it-anchor') +import yamlit from 'js-yaml' +import markdownit from 'markdown-it' +import markdownAnchors from 'markdown-it-anchor' export const mdParser = ({ highlight, use }, { anchorsLevel }) => { const parser = markdownit({ @@ -12,13 +12,18 @@ export const mdParser = ({ highlight, use }, { anchorsLevel }) => { }) const plugins = [ - [markdownAnchors, { - level: [anchorsLevel] - }] + [ + markdownAnchors, + { + level: [anchorsLevel] + } + ] ].concat(use) plugins.forEach(plugin => { - Array.isArray(plugin) ? parser.use.apply(parser, plugin) : parser.use(plugin) + Array.isArray(plugin) + ? parser.use.apply(parser, plugin) + : parser.use(plugin) }) return parser @@ -26,6 +31,6 @@ export const mdParser = ({ highlight, use }, { anchorsLevel }) => { export const yamlParser = () => { return { - render: yamlit.safeLoad + render: yamlit.safeLoad } } diff --git a/package.json b/package.json index 4ad0c03..9e00455 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,11 @@ "nuxtent": "bin/nuxtent" }, "scripts": { + "#": "handled by husky", + "precommit": "lint-staged", + "#": "handled by husky", + "lint": "eslint --fix \"**/*.js\"", + "pretest": "npm run lint", "unit": "cross-env NODE_ENV=development karma start test/unit/karma.conf.js", "e2e": "cross-env NODE_ENV=test ava --verbose --serial test/e2e", "test": "npm run unit --single-run && npm run e2e", @@ -52,6 +57,7 @@ "@nuxtjs/axios": "^3.0.1", "ava": "^0.22.0", "babel-cli": "^6.26.0", + "babel-eslint": "^8.0.0", "babel-plugin-external-helpers": "^6.22.0", "babel-plugin-istanbul": "^4.1.5", "babel-plugin-transform-async-to-generator": "^6.24.1", @@ -62,14 +68,27 @@ "babel-register": "^6.26.0", "chai": "^4.1.0", "cross-env": "^5.0.1", + "eslint": "^4.7.2", + "eslint-config-i-am-meticulous": "^7.0.1", + "eslint-config-prettier": "^2.5.0", + "eslint-config-standard": "^10.2.1", + "eslint-plugin-ava": "^4.2.2", + "eslint-plugin-babel": "^4.1.2", + "eslint-plugin-node": "^5.1.1", + "eslint-plugin-promise": "^3.5.0", + "eslint-plugin-standard": "^3.0.1", "express": "^4.15.3", + "git-exec-and-restage": "^1.0.1", + "husky": "^0.14.3", "jsdom": "^11.1.0", "karma": "^1.7.0", "karma-mocha": "^1.3.0", "karma-rollup-preprocessor": "^4.0.2", "karma-sinon-chai": "^1.3.1", + "lint-staged": "^4.2.1", "mocha": "^3.5.0", "nuxt": "^1.0.0-rc11", + "prettier-standard": "^6.0.0", "request-promise-native": "^1.0.4", "rollup": "^0.50.0", "rollup-plugin-babel": "^3.0.2", @@ -77,13 +96,17 @@ "rollup-plugin-copy": "^0.2.3", "rollup-plugin-filesize": "^1.2.1", "rollup-plugin-json": "^2.3.0", - "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-resolve": "^3.0.0", "rollup-plugin-uglify-es": "0.0.1", "rollup-watch": "^4.0.0", "sinon": "^3.0.0", "sinon-chai": "^2.12.0" }, + "lint-staged": { + "[!template].js": [ + "git-exec-and-restage prettier-standard" + ] + }, "ava": { "require": [ "babel-register" @@ -98,7 +121,7 @@ "doc": "docs", "example": "examples", "lib": "lib", - "test": "tests" + "test": "test" }, "author": "Alid Castano" } diff --git a/rollup.config.js b/rollup.config.js index 74402e7..67edb5c 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,23 +1,26 @@ import resolve from 'rollup-plugin-node-resolve' import json from 'rollup-plugin-json' -import builtins from 'rollup-plugin-node-builtins' import babel from 'rollup-plugin-babel' import commonjs from 'rollup-plugin-commonjs' import uglify from 'rollup-plugin-uglify-es' import filesize from 'rollup-plugin-filesize' import copy from 'rollup-plugin-copy' -const version = process.env.VERSION || require('./package.json').version +import pkg from './package.json' -const corePlugins = () => [ - resolve(), +const version = process.env.VERSION || pkg.version +const external = Object.keys(pkg.dependencies || {}) + +const corePlugins = [ + resolve({ + preferBuiltins: false + }), commonjs({ include: 'node_modules/**' }), babel({ plugins: ['external-helpers'] }), - builtins(), uglify(), filesize() ] @@ -47,14 +50,18 @@ export default [ plugins: [ json(), copy({ - 'lib/plugin.js': 'dist/plugin.js', + 'lib/plugins': 'dist/plugins', 'lib/loader.js': 'dist/loader.js' }), - ...corePlugins() + ...corePlugins ], external: [ + 'path', + 'fs', + 'querystring', 'express', - 'axios' + 'axios', + ...external ], globals: { express: 'express' diff --git a/test/e2e/complex.test.js b/test/e2e/complex.test.js index e6e4cc7..78b2a9f 100644 --- a/test/e2e/complex.test.js +++ b/test/e2e/complex.test.js @@ -2,7 +2,7 @@ import { resolve } from 'path' import test from 'ava' -import { get, commonBefore, commonAfter } from "../fixtures/nuxt"; +import { get, commonBefore, commonAfter } from '../fixtures/nuxt' test.before('Init Nuxt and Nuxtent', async () => { await commonBefore( @@ -12,14 +12,14 @@ test.before('Init Nuxt and Nuxtent', async () => { 'posts', { page: '/posts/_slug', - permalink: '/:year/:slug', + permalink: '/:year/:slug' } ], [ 'projects', { page: '/projects/_slug', - permalink: "/projects/:slug", + permalink: '/projects/:slug', isPost: false } ] @@ -33,30 +33,46 @@ test.before('Init Nuxt and Nuxtent', async () => { test('index', async t => { const html = await get('/') - t.true(html.includes('

Nuxtent

See my first postSee all my postsSee my first projectSee all my projects
')) + t.true( + html.includes( + '

Nuxtent

See my first postSee all my postsSee my first projectSee all my projects
' + ) + ) }) test('posts content - get', async t => { const html = await get('/2016/first-post') - t.true(html.includes('

My First Post

This is my first post!

')) + t.true( + html.includes('

My First Post

This is my first post!

') + ) }) test('posts content - getAll', async t => { const html = await get('/archives') - t.true(html.includes('

Posts

')) + t.true( + html.includes( + '

Posts

' + ) + ) }) test('projects content - get', async t => { const html = await get('/projects/ency') - t.true(html.includes( -`

Project: Ency.js

Pretty cool plugin!

+ t.true( + html.includes( + `

Project: Ency.js

Pretty cool plugin!

` - )) + ) + ) }) test('projects content - getAll', async t => { const html = await get('/projects/') - t.true(html.includes('

Projects

')) + t.true( + html.includes( + '

Projects

' + ) + ) }) test.after('Closing server and nuxt.js', async () => { diff --git a/test/e2e/simple.test.js b/test/e2e/simple.test.js index 71c94d7..1d87bc3 100644 --- a/test/e2e/simple.test.js +++ b/test/e2e/simple.test.js @@ -2,14 +2,14 @@ import { resolve } from 'path' import test from 'ava' -import { get, commonBefore, commonAfter } from "../fixtures/nuxt"; +import { get, commonBefore, commonAfter } from '../fixtures/nuxt' test.before('Init Nuxt and Nuxtent', async () => { await commonBefore( { content: { page: '/_slug', - permalink: '/:year/:slug', + permalink: '/:year/:slug' } }, { @@ -25,12 +25,18 @@ test('index', async t => { test('content - get', async t => { const html = await get('/2016/first-post') - t.true(html.includes('

My First Post

This is my first post!

')) + t.true( + html.includes('

My First Post

This is my first post!

') + ) }) test('content - getAll', async t => { const html = await get('/archives') - t.true(html.includes('

All Posts

')) + t.true( + html.includes( + '

All Posts

' + ) + ) }) test.after('Closing server and nuxt.js', async () => { diff --git a/test/fixtures/nuxt.config.js b/test/fixtures/nuxt.config.js index 5338741..25d5dc1 100644 --- a/test/fixtures/nuxt.config.js +++ b/test/fixtures/nuxt.config.js @@ -1,12 +1,10 @@ import nuxtent from '../../lib/module' -export default (nuxtentConfig) => ({ +export default nuxtentConfig => ({ dev: false, render: { resourceHints: false }, - modules: [ - nuxtent - ], + modules: [nuxtent], nuxtent: nuxtentConfig }) diff --git a/test/fixtures/nuxt.js b/test/fixtures/nuxt.js index c232e42..c959c85 100644 --- a/test/fixtures/nuxt.js +++ b/test/fixtures/nuxt.js @@ -14,21 +14,19 @@ let nuxt const commonBefore = (nuxtentConfig, config = {}) => async () => { const mergedConfig = { - ...baseConfig( - { - ...nuxtentConfig, - api: { - baseURL: `http://localhost:${process.env.PORT}` - }, + ...baseConfig({ + ...nuxtentConfig, + api: { + baseURL: `http://localhost:${process.env.PORT}` } - ), + }), ...config } // Build a fresh nuxt - nuxt = new Nuxt(mergedConfig); - await new Builder(nuxt).build(); - await nuxt.listen(process.env.PORT); + nuxt = new Nuxt(mergedConfig) + await new Builder(nuxt).build() + await nuxt.listen(process.env.PORT) } const commonAfter = async () => { diff --git a/test/unit/karma.conf.js b/test/unit/karma.conf.js index 79455c9..b502d64 100644 --- a/test/unit/karma.conf.js +++ b/test/unit/karma.conf.js @@ -1,27 +1,24 @@ module.exports = function (config) { - config.set({ - frameworks: ['mocha', 'sinon-chai'], + config.set({ + frameworks: ['mocha', 'sinon-chai'], - files: [ - './specs/**.spec.js', - ], + files: ['./specs/**.spec.js'], - preprocessors: { - '../../lib/module.js': ['rollup'], - '../../lib/content/**.js': ['rollup'], - './specs/**.spec.js': ['rollup'], - }, + preprocessors: { + '../../lib/module.js': ['rollup'], + '../../lib/content/**.js': ['rollup'], + './specs/**.spec.js': ['rollup'] + }, - rollupPreprocessor: { - plugins: [ - require('rollup-plugin-node-resolve')(), - require('rollup-plugin-node-builtins')(), - require('rollup-plugin-babel')(), - require('rollup-plugin-commonjs')() - ], + rollupPreprocessor: { + plugins: [ + require('rollup-plugin-node-resolve')(), + require('rollup-plugin-babel')(), + require('rollup-plugin-commonjs')() + ], format: 'umd', moduleName: `nuxtContent`, - sourceMap: 'inline' - } - }) + sourceMap: 'inline' + } + }) } diff --git a/test/unit/specs/database.spec.js b/test/unit/specs/database.spec.js index 2ebea28..e380e1a 100644 --- a/test/unit/specs/database.spec.js +++ b/test/unit/specs/database.spec.js @@ -1,3 +1,4 @@ +/* eslint-disable */ /* global describe, it, expect, beforeEach, sinon */ import createDatabase from '../../../lib/content/database' @@ -5,7 +6,6 @@ import createDatabase from '../../../lib/content/database' import { resolve } from 'path' describe('database API', function () { - it('loads single content type', () => { const contentPath = '../../fixtures/single-content-type/content' const dirName = '/'