Skip to content

Commit

Permalink
feat: add macros and re-organize type imports
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Nov 22, 2020
1 parent 1252f43 commit 0d89211
Show file tree
Hide file tree
Showing 19 changed files with 991 additions and 28 deletions.
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
export * from './src/Contracts'
export { toHtml } from './src/utils'
export { MarkdownFile } from './src/MarkdownFile'
export * as macros from './src/Macros/Collection'
2 changes: 1 addition & 1 deletion npm-audit.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ <h5 class="card-title">
<div class="card">
<div class="card-body">
<h5 class="card-title">
November 22nd 2020, 9:56:16 am
November 22nd 2020, 2:44:43 pm
</h5>
<p class="card-text">Last updated</p>
</div>
Expand Down
20 changes: 11 additions & 9 deletions src/Contracts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
* file that was distributed with this source code.
*/

import type { Content } from 'mdast'
import type * as hastTypes from 'hast'
import type * as mdastTypes from 'mdast'
import { VFileMessage } from 'vfile-message'
import type { Node, Position, Point } from 'unist'
import type { Root, Parent, Element, Text } from 'hast'

export { Node, Position, Point, Root, Parent, Element, Text }
export { Node, Position, Point }
export { hastTypes }
export { mdastTypes }

/**
* Shape of the collected reference
Expand Down Expand Up @@ -44,7 +46,7 @@ export interface TextDirective extends Node {
name: string
type: 'textDirective'
attributes: { [key: string]: string }
children: (Content | Directives)[]
children: (mdastTypes.Content | Directives)[]
}

/**
Expand All @@ -54,7 +56,7 @@ export interface LeafDirective extends Node {
name: string
type: 'leafDirective'
attributes: { [key: string]: string }
children: (Content | Directives)[]
children: (mdastTypes.Content | Directives)[]
}

/**
Expand All @@ -64,7 +66,7 @@ export interface ContainerDirective extends Node {
name: string
type: 'containerDirective'
attributes: { [key: string]: string }
children: (Content | Directives)[]
children: (mdastTypes.Content | Directives)[]
}

/**
Expand All @@ -85,13 +87,13 @@ export interface MarkdownFileOptions {
export interface MarkdownFileJson {
state: 'idle' | 'processing' | 'processed'
stats: StatsNode
ast?: Root
summary?: Root
ast?: hastTypes.Root
summary?: hastTypes.Root
excerpt?: string
frontmatter: { [key: string]: any }
messages: VFileMessage[]
filePath?: string
dirname?: string
basename?: string
toc?: Parent
toc?: hastTypes.Parent
}
107 changes: 107 additions & 0 deletions src/Macros/Collection/codesandbox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* @dimerapp/markdown
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { parse } from 'url'
import { stringify } from 'querystring'
import { MarkdownFile } from '../../MarkdownFile'
import { ensureDomainUrl, ObjectBuilder } from '../../utils'

/**
* Embed codesandbox to your document
*/
export default function (mdFile: MarkdownFile) {
mdFile.macro('codesandbox', (node, file, removeNode) => {
/**
* Ensure macro doesn't have children
*/
if (node.children.length) {
file.report(
'"codesandbox" macro is not a container macro. Use it as "::codesandbox{url=""}"',
node.position
)
removeNode()
return
}

/**
* Validate url and its domain
*/
const errorMessage = ensureDomainUrl(node.attributes.url, 'codesandbox', ['codesandbox.io'])
if (errorMessage) {
file.report(errorMessage, node.position)
removeNode()
return
}

const qs = new ObjectBuilder()

/**
* These are all the possible props accepted by codesandbox.
* Ref: https://codesandbox.io/docs/embedding#embed-options
*/
qs.add('autoresize', node.attributes.autoresize)
qs.add('codemirror', node.attributes.codemirror)
qs.add('editorsize', node.attributes.editorsize)
qs.add('eslint', node.attributes.eslint)
qs.add('expanddevtools', node.attributes.expanddevtools)
qs.add('hidedevtools', node.attributes.hidedevtools)
qs.add('fontsize', node.attributes.fontsize)
qs.add('forcerefresh', node.attributes.forcerefresh)
qs.add('hidenavigation', node.attributes.hidenavigation)
qs.add('highlights', node.attributes.highlights)
qs.add('initialpath', node.attributes.initialpath)
qs.add('module', node.attributes.module)
qs.add('moduleview', node.attributes.moduleview)
qs.add('previewwindow', node.attributes.previewwindow)
qs.add('runonclick', node.attributes.runonclick)
qs.add('view', node.attributes.view)
qs.add('theme', node.attributes.theme)

/**
* Build the final embed url
*/
const parsedUrl = parse(node.attributes.url, false)
const query = stringify(qs.toJSON())
const embedUrl = `${parsedUrl.protocol}//${parsedUrl.hostname}${parsedUrl.pathname?.replace(
'/s/',
'/embed/'
)}${query ? `?${query}` : ''}`

/**
* Mutate the node
*/
node.data = node.data || {}
node.data.hname = 'div'
node.data.hProperties = {
className: ['embed', 'embed-codesandbox'],
}

/**
* Add children. The node name and the attributes will be converted
* to hast automatically. So no need to define them here
*/
node.children = [
{
type: 'containerDirective',
name: 'iframe',
attributes: {
src: embedUrl,
style: `width:${node.attributes.width || '100%'}; height:${
node.attributes.height || '500px'
}; border:0; border-radius: 4px; overflow:hidden;`,
allow:
'accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking',
sandbox:
'allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts',
},
children: [],
},
]
})
}
15 changes: 15 additions & 0 deletions src/Macros/Collection/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* @dimerapp/markdown
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

export { default as codesandbox } from './codesandbox'
export { default as note } from './note'
export { default as tip } from './tip'
export { default as video } from './video'
export { default as warning } from './warning'
export { default as youtube } from './youtube'
28 changes: 28 additions & 0 deletions src/Macros/Collection/note.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* @dimerapp/markdown
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { MarkdownFile } from '../../MarkdownFile'

/**
* Wrap markup inside div with class "alert-note"
*/
export default function (mdFile: MarkdownFile) {
mdFile.macro('note', (node) => {
node.data = node.data || {}
node.data.hName = 'div'
node.data.hProperties = {
className: ['alert', 'alert-note'],
/**
* We do not add the `role=alert` inside note, since role=alert is meant
* to inform the user about the things that needs immediate attention
* and "notes" are not one of them
*/
}
})
}
28 changes: 28 additions & 0 deletions src/Macros/Collection/tip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* @dimerapp/markdown
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { MarkdownFile } from '../../MarkdownFile'

/**
* Wrap markup inside div with class "alert-tip"
*/
export default function (mdFile: MarkdownFile) {
mdFile.macro('tip', (node) => {
node.data = node.data || {}
node.data.hName = 'div'
node.data.hProperties = {
className: ['alert', 'alert-tip'],
/**
* We do not add the `role=alert` inside tip, since role=alert is meant
* to inform the user about the things that needs immediate attention
* and "tips" are not one of them
*/
}
})
}
91 changes: 91 additions & 0 deletions src/Macros/Collection/video.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* @dimerapp/markdown
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { MarkdownFile } from '../../MarkdownFile'
import { ObjectBuilder } from '../../utils'

/**
* Allows adding videos to the document
*/
export default function (mdFile: MarkdownFile) {
mdFile.macro('video', (node, file, removeNode) => {
/**
* Ensure macro doesn't have children
*/
if (node.children.length) {
file.report(
'"video" macro is not a container macro. Use it as "::video{url=""}"',
node.position
)
removeNode()
return
}

/**
* Ensure url is defined
*/
if (!node.attributes.url) {
file.report('"video" macro needs a url prop to be functional', node.position)
removeNode()
return
}

/**
* Mutate the node
*/
node.data = node.data || {}
node.data.hname = 'div'
node.data.hProperties = {
className: ['embed', 'embed-video'],
}

/**
* We support only the following props. The actual video
* element accepts a lot more, but we want to keep it
* simple
*/
const props = new ObjectBuilder()
props.add('autoplay', node.attributes.autoplay)
props.add('controls', node.attributes.controls)
props.add('loop', node.attributes.loop)
props.add('preload', node.attributes.preload)
props.add('poster', node.attributes.poster)

/**
* Add children. The node name and the attributes will be converted
* to hast automatically. So no need to define them here
*/
node.children = [
{
type: 'containerDirective',
name: 'video',
attributes: props.toJSON(),
data: {
/**
* Telling the macros engine to self process this node and not again
* forward it to the macro handler, coz the `name = video`, which
* matches the macro name.
*/
isMacro: false,
},
children: [
{
type: 'containerDirective',
name: 'source',
attributes: {
src: node.attributes.url,
type: 'video/mp4',
},
children: [],
},
],
},
]
})
}
24 changes: 24 additions & 0 deletions src/Macros/Collection/warning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* @dimerapp/markdown
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { MarkdownFile } from '../../MarkdownFile'

/**
* Wrap markup inside div with class "alert-warning"
*/
export default function (mdFile: MarkdownFile) {
mdFile.macro('warning', (node) => {
node.data = node.data || {}
node.data.hName = 'div'
node.data.hProperties = {
className: ['alert', 'alert-warning'],
role: 'alert',
}
})
}
Loading

0 comments on commit 0d89211

Please sign in to comment.