Compare commits

...

9 Commits
v0.3.1 ... main

@ -13,7 +13,6 @@ finished, it was only a proof of concept. But now it works for created a entire
Next will be, Next will be,
* Some more Tests * Some more Tests
* Image Handling in Markdown
Maybe later, Maybe later,
@ -200,6 +199,30 @@ media:
--- ---
``` ```
Options from Sharp can be add on two different ways. As "options" for all Sizes or
you can simply add options to a sizes, that means the main options will be ignored.
```
---
title: "health goth DIY tattooed"
view: "home.njk"
meta:
description: "La"
media:
teaser:
src:
src: '_images/dog.jpg'
sizes:
- width: 300
- width: 500
height: 100
position: 'left'
alt: "cold-pressed"
options:
position: 'right'
---
```
## Queries ## Queries
Queries can be used in Templates to get Pages. Queries can be used in Templates to get Pages.

@ -1,6 +1,6 @@
{ {
"name": "@site-o-mat/core", "name": "@site-o-mat/core",
"version": "0.3.1", "version": "0.5.0",
"build": "webpack", "build": "webpack",
"author": "Björn Hase <me@herr-hase.wtf>", "author": "Björn Hase <me@herr-hase.wtf>",
"main": "index.js", "main": "index.js",

@ -3,6 +3,7 @@ title: "health goth DIY tattooed"
view: "page.njk" view: "page.njk"
meta: meta:
description: "DSA yes plz hot chicken green juice" description: "DSA yes plz hot chicken green juice"
robots: "noindex"
media: media:
src: src:
src: '_images/dog.jpg' src: '_images/dog.jpg'
@ -21,4 +22,6 @@ bicycle rights sartorial godard slow-carb thundercats art party cray JOMO. Truff
## Bitters kale chips chambray activated charcoal ## Bitters kale chips chambray activated charcoal
wolf keffiyeh hell of selfies. Wolf readymade shoreditch flexitarian venmo single-origin coffee, knausgaard fit actually street art cold-pressed iPhone gatekeep. Migas bruh adaptogen semiotics marfa pickled yuccie. Locavore normcore lomo, shoreditch fashion axe actually glossier iPhone photo booth blue bottle DIY XOXO williamsburg. Pinterest whatever taxidermy, kale chips prism XOXO schlitz twee tote bag woke swag. Wayfarers fashion axe heirloom humblebrag synth. Whatever succulents PBR&B, pop-up enamel pin echo park tonx stumptown taiyaki. wolf keffiyeh hell of selfies. Wolf readymade shoreditch flexitarian venmo single-origin coffee, knausgaard fit actually street art cold-pressed iPhone gatekeep. Migas bruh adaptogen semiotics marfa pickled yuccie. Locavore normcore lomo, shoreditch fashion axe actually glossier iPhone photo booth blue bottle DIY XOXO williamsburg. Pinterest whatever taxidermy, kale chips prism XOXO schlitz twee tote bag woke swag. Wayfarers fashion axe heirloom humblebrag synth. Whatever succulents PBR&B, pop-up enamel pin echo park tonx stumptown taiyaki.
![_images/dog.jpg](_images/dog.jpg)

@ -37,11 +37,6 @@ class ConfigStore {
* @return {String|Object} * @return {String|Object}
*/ */
get(key) { get(key) {
if (!this._data?.[key]) {
throw new Error(key + ' not found in ConfigStore!')
}
return this._data[key] return this._data[key]
} }
} }
@ -49,4 +44,4 @@ class ConfigStore {
// create instance // create instance
const instance = new ConfigStore(); const instance = new ConfigStore();
module.exports = instance module.exports = instance

@ -1,5 +1,6 @@
const path = require('path') const path = require('path')
const fs = require('fs') const fs = require('fs')
const configStore = require('./../config.js')
/** /**
* asset - checks manifest.json for given path and return * asset - checks manifest.json for given path and return
@ -16,7 +17,7 @@ function asset(staticPath) {
let result = staticPath let result = staticPath
// path to mix-manifest // path to mix-manifest
const file = path.join(path.resolve()) + 'mix-manifest.json' const file = path.join(configStore.get('destination')) + '/mix-manifest.json'
if (fs.existsSync(file)) { if (fs.existsSync(file)) {

@ -25,7 +25,7 @@ class Block {
constructor(fileString, dirPath) { constructor(fileString, dirPath) {
// parse string of file // parse string of file
const parsedFile = parseMarkdownFile(fileString) const parsedFile = parseMarkdownFile(fileString, dirPath)
this._dirPath = dirPath this._dirPath = dirPath

@ -4,6 +4,7 @@ const sharp = require('sharp')
const mkdirp = require('mkdirp') const mkdirp = require('mkdirp')
const crypto = require('crypto') const crypto = require('crypto')
const slugify = require('slugify') const slugify = require('slugify')
const assign = require('assign-deep')
const configStore = require('./../config.js') const configStore = require('./../config.js')
@ -20,8 +21,8 @@ const configStore = require('./../config.js')
class Media { class Media {
constructor(path = NULL) { constructor(dirPath = NULL) {
this._path = path this._path = dirPath
this._DIR_ASSETS = '/assets/' this._DIR_ASSETS = '/assets/'
} }
@ -42,11 +43,7 @@ class Media {
const filename = slugify(path.basename(src, extension)) const filename = slugify(path.basename(src, extension))
// check for images in path // check for images in path
if (this._path && fs.existsSync(configStore.get('source') + this._path + '/' + src)) { sourcePath = this._getSourcePath(src)
sourcePath = configStore.get('source') + this._path + '/' + src
} else {
sourcePath = configStore.get('source') + '/' + src
}
// getting sharp // getting sharp
const process = sharp(sourcePath) const process = sharp(sourcePath)
@ -91,6 +88,30 @@ class Media {
return this._reduce(results) return this._reduce(results)
} }
/**
* get source path
*
* @param {String} src
* @return {String}
*
*/
_getSourcePath(src) {
let sourcePath = configStore.get('source') + '/' + src
if (Array.isArray(this._path)) {
if (fs.existsSync(configStore.get('source') + this._path[0] + '/' + src)) {
sourcePath = configStore.get('source') + this._path[0] + '/' + src
} else if (fs.existsSync(configStore.get('source') + this._path[1] + '/' + src)) {
sourcePath = configStore.get('source') + this._path[1] + '/' + src
}
} else if (this._path && fs.existsSync(configStore.get('source') + this._path + '/' + src)) {
sourcePath = configStore.get('source') + this._path + '/' + src
}
return sourcePath
}
/** /**
* if only full is in results, reduce object to string * if only full is in results, reduce object to string
* *
@ -142,16 +163,34 @@ class Media {
*/ */
_writeFile(file, process, options) { _writeFile(file, process, options) {
// resize without options and with options // if sizes have height or width with no optional parameters then check for merge of options
if (file.sizes && Object.getOwnPropertyNames(options).length === 0 && Object.getOwnPropertyNames(file.sizes).length > 0) { if (file.sizes &&
(((!file.sizes.height || !file.sizes.width) && Object.getOwnPropertyNames(file.sizes).length === 1) ||
(file.sizes.height && file.sizes.width && Object.getOwnPropertyNames(file.sizes).length === 2))) {
process.resize(this._mergeOptions(file.sizes, options))
// if already options in sizes ignore options
} else if (file.sizes) {
process.resize(file.sizes) process.resize(file.sizes)
} else if (file.sizes && Object.getOwnPropertyNames(options).length > 0 && Object.getOwnPropertyNames(file.sizes).length > 0) {
process.resize(file.sizes, options)
} }
process.toFile(configStore.get('destination') + file.path) process.toFile(configStore.get('destination') + file.path)
} }
/**
* if options are exists merge them with sizes
*
* @param {object} sizes
* @param {Object} options
*/
_mergeOptions(sizes, options) {
if (Object.getOwnPropertyNames(options).length > 0) {
sizes = assign(options, sizes)
}
return sizes
}
/** /**
* generate destination path from hash of file * generate destination path from hash of file
* *

@ -3,9 +3,11 @@ const slugify = require('slugify')
const merge = require('lodash.merge') const merge = require('lodash.merge')
const nunjucks = require('nunjucks') const nunjucks = require('nunjucks')
const assign = require('assign-deep') const assign = require('assign-deep')
const fs = require('fs')
const Media = require('./../factories/media.js') const Media = require('./../factories/media.js')
const parseMarkdownFile = require('./../parsers/markdown.js') const parseMarkdownFile = require('./../parsers/markdown.js')
const configStore = require('./../config.js')
/** /**
* Page - building from markdown file * Page - building from markdown file
@ -30,8 +32,11 @@ class Page {
*/ */
constructor(file, parent, fileString, blocks = {}) { constructor(file, parent, fileString, blocks = {}) {
// getting dirPath for files for page
this._dirPath = this._resolvePath(parent)
// parse file // parse file
const result = parseMarkdownFile(fileString) const result = parseMarkdownFile(fileString, this._dirPath)
// fields merge by default values // fields merge by default values
this._fields = merge({ this._fields = merge({
@ -46,13 +51,18 @@ class Page {
// adding filename for html as pathname and relative path in structure // adding filename for html as pathname and relative path in structure
this._filename = this._resolveFilename(file) this._filename = this._resolveFilename(file)
this._slug = this._resolveSlug(this._filename) this._slug = this._resolveSlug(this._filename)
this._dirPath = this._resolvePath(parent)
this._permalink = this._dirPath this._permalink = this._dirPath
if (this._slug) { if (this._slug) {
this._permalink = this._dirPath + '/' + this._slug this._permalink = this._dirPath + '/' + this._slug
} }
// check if page is in subdirectory
if (fs.existsSync(configStore.get('source') + this._permalink) && this._slug) {
this._dirPath += '/' + this._slug
this._filename = 'index'
}
this._filename += '.' + this._fields.extensions this._filename += '.' + this._fields.extensions
this._content = result.content this._content = result.content
@ -113,7 +123,12 @@ class Page {
return fields return fields
} }
/**
*
*
*/
_resolveMediaSrc(field, dirPath) { _resolveMediaSrc(field, dirPath) {
const media = new Media(dirPath) const media = new Media(dirPath)
if (typeof field === 'string' || field instanceof String) { if (typeof field === 'string' || field instanceof String) {
@ -121,7 +136,11 @@ class Page {
} }
if (typeof field === 'object' || field instanceof Object) { if (typeof field === 'object' || field instanceof Object) {
field = media.resolve(field.src, field.sizes) if (field.options) {
field = media.resolve(field.src, field.sizes, field.options)
} else {
field = media.resolve(field.src, field.sizes)
}
} }
return field return field

@ -1,5 +1,6 @@
const { XMLParser, XMLBuilder, XMLValidator} = require('fast-xml-parser') const { XMLParser, XMLBuilder, XMLValidator} = require('fast-xml-parser')
const dayjs = require('dayjs') const dayjs = require('dayjs')
const assign = require('assign-deep')
/** /**
* *
@ -19,7 +20,11 @@ class Sitemap {
* *
*/ */
constructor(site) { constructor(site) {
this._site = site this._site = assign({
'sitemap': {
'use_permalinks': true
}
}, site)
this._urls = [] this._urls = []
} }
@ -31,8 +36,15 @@ class Sitemap {
*/ */
addPage(page) { addPage(page) {
if (this._isValid(page)) { if (this._isValid(page)) {
let path = page.permalink
if (this._site.sitemap.use_permalinks === false) {
path = page.path
}
this._urls.push({ this._urls.push({
loc: 'https://' + this._site.domain + page.path, loc: 'https://' + this._site.domain + path,
lastmod: dayjs().format() lastmod: dayjs().format()
}) })
} }
@ -59,14 +71,8 @@ class Sitemap {
let result = true let result = true
if (page.meta) { if (page.meta && page.meta.robots && page.meta.robots.includes('noindex')) {
page.meta = Object.entries(page.meta) result = false
page.meta.forEach((meta) => {
if (meta['name'] === 'robots' && meta['content'].includes('noindex')) {
result = false
return;
}
})
} }
if (page.extensions !== 'html') { if (page.extensions !== 'html') {

@ -0,0 +1,112 @@
const { marked } = require('marked')
const configStore = require('./../config.js')
const Media = require('./../factories/media.js')
/**
*
*
*/
// copy from @marked/src/helpers.js, no export possible
function cleanUrl(sanitize, base, href) {
if (sanitize) {
let prot
try {
prot = decodeURIComponent(unescape(href))
.replace(nonWordAndColonTest, '')
.toLowerCase()
} catch (e) {
return null
}
if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
return null
}
}
if (base && !originIndependentUrl.test(href)) {
href = resolveUrl(base, href)
}
try {
href = encodeURI(href).replace(/%25/g, '%')
} catch (e) {
return null
}
return href
}
const renderer = {
/**
*
* @param {string} href
* @param {string} title
* @param {string} text
*/
link(href, title, text) {
href = cleanUrl(this.options.sanitize, this.options.baseUrl, href)
if (href === null) {
return text
}
let out = '<a href="' + href + '"'
if (title) {
out += ' title="' + title + '"'
}
// check if url is external and add target
if (href.match(/^(http|https):\/\//)) {
out += ' target="_blank" rel="noopener" '
}
out += '>' + text + '</a>'
return out
},
/**
*
* @param {string} href
* @param {string} title
* @param {string} text
*/
image(href, title, text) {
href = cleanUrl(this.options.sanitize, this.options.baseUrl, href)
if (href === null) {
return text
}
// check if href for image is relative
if (!href.match(/^(http|https):\/\//)) {
const markedDirPath = configStore.get('markedDirPath')
// check if dirPath are exists from options
if (markedDirPath || markedDirPath === '') {
const media = new Media(markedDirPath)
href = media.resolve(href)
}
}
let out = `<img src="${href}" alt="${text}"`
if (title) {
out += ` title="${title}"`
}
out += this.options.xhtml ? '/>' : '>'
return out
}
}
module.exports = renderer

@ -1,6 +1,9 @@
const yaml = require('js-yaml') const yaml = require('js-yaml')
const { marked } = require('marked') const { marked } = require('marked')
const configStore = require('./../config.js')
const renderer = require('./../marked/renderer.js')
/** /**
* parse string of file, parse yaml and parse markdown * parse string of file, parse yaml and parse markdown
* *
@ -10,7 +13,7 @@ const { marked } = require('marked')
* *
*/ */
function parseMarkdownFile(fileString) { function parseMarkdownFile(fileString, dirPath = '') {
// regex get yaml section and markdown // regex get yaml section and markdown
// thanks to, https://github.com/getgrav/grav // thanks to, https://github.com/getgrav/grav
@ -33,10 +36,20 @@ function parseMarkdownFile(fileString) {
// if markdown section exits parse it to html 6565 // if markdown section exits parse it to html 6565
if (matches?.[3]) { if (matches?.[3]) {
// reset configStore
configStore.set('markedDirPath', false)
// check for dirPath and set it to configStore for marked/renderer.js
if (dirPath || dirPath === '') {
configStore.set('markedDirPath', dirPath)
}
marked.use({ renderer })
result.content = marked.parse(matches[3]) result.content = marked.parse(matches[3])
} }
return result return result
} }
module.exports = parseMarkdownFile module.exports = parseMarkdownFile

@ -29,6 +29,10 @@ describe('Page /index.md', function () {
it('permalink', function() { it('permalink', function() {
assert.equal(page.permalink, '') assert.equal(page.permalink, '')
}) })
it('parsed content contains image', () => {
assert.match(page.content, /<img src="\/assets\/88c010ea\/4ca9b5f5\/6024c57d\/05899fae\/a33d9a45\/dog.webp" alt="_images\/dog.jpg">/)
})
}) })
describe('Page /blog/index.md', function () { describe('Page /blog/index.md', function () {
@ -50,7 +54,7 @@ describe('Page /blog/index.md', function () {
}) })
it('path', function() { it('path', function() {
assert.equal(page.path, '/blog.html') assert.equal(page.path, '/blog/index.html')
}) })
it('permalink', function() { it('permalink', function() {
@ -59,9 +63,9 @@ describe('Page /blog/index.md', function () {
it('fields has media src', function() { it('fields has media src', function() {
assert.deepEqual(page.media.src, { assert.deepEqual(page.media.src, {
"300": "/assets/88c010ea/4ca9b5f5/6024c57d/05899fae/a33d9a45/dog300.webp", "300": "/assets/a6c45d17/11bf0a4e/a2b1d75d/dc85ca56/71c63294/dog300.webp",
"500x100": "/assets/88c010ea/4ca9b5f5/6024c57d/05899fae/a33d9a45/dog500x100.webp", "500x100": "/assets/a6c45d17/11bf0a4e/a2b1d75d/dc85ca56/71c63294/dog500x100.webp",
"full": "/assets/88c010ea/4ca9b5f5/6024c57d/05899fae/a33d9a45/dog.webp" "full": "/assets/a6c45d17/11bf0a4e/a2b1d75d/dc85ca56/71c63294/dog.webp"
}) })
}) })
}) })

@ -39,7 +39,8 @@ describe('Parser Markdown', function () {
title: 'health goth DIY tattooed', title: 'health goth DIY tattooed',
view: 'page.njk', view: 'page.njk',
meta: { meta: {
description: 'DSA yes plz hot chicken green juice' description: 'DSA yes plz hot chicken green juice',
robots: 'noindex'
} }
}) })
}) })

@ -25,6 +25,10 @@ describe('Sitemap', function () {
// check results // check results
it('loc-tag with url', function() { it('loc-tag with url', function() {
assert.match(sitemap.getXmlAsString(), /<loc>https:\/\/test.lan\/blog\/article.html<\/loc>/) assert.match(sitemap.getXmlAsString(), /<loc>https:\/\/test.lan\/blog\/article<\/loc>/)
})
it('loc-tag has robotos:noindex and has missing', function() {
assert.notMatch(sitemap.getXmlAsString(), /<loc>https:\/\/test.lan\/<\/loc>/)
}) })
}) })

Loading…
Cancel
Save