markdown-magic 2.6.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +47 -37
  2. package/cli.js +5 -82
  3. package/lib/block-parser-js.test.js +171 -0
  4. package/lib/block-parser.js +382 -0
  5. package/lib/block-parser.test.js +479 -0
  6. package/lib/cli.js +245 -0
  7. package/lib/cli.test.js +409 -0
  8. package/lib/defaults.js +12 -0
  9. package/lib/globals.d.ts +66 -0
  10. package/lib/index.js +353 -184
  11. package/lib/index.test.js +11 -0
  12. package/lib/process-contents.js +371 -0
  13. package/lib/process-file.js +37 -0
  14. package/lib/transforms/code.js +67 -28
  15. package/lib/transforms/file.js +17 -17
  16. package/lib/transforms/index.js +0 -114
  17. package/lib/transforms/remote.js +8 -6
  18. package/lib/transforms/sectionToc.js +18 -0
  19. package/lib/transforms/toc.js +12 -265
  20. package/lib/transforms/wordCount.js +5 -0
  21. package/lib/types.js +11 -0
  22. package/lib/utils/fs.js +342 -0
  23. package/lib/utils/fs.test.js +267 -0
  24. package/lib/utils/index.js +19 -0
  25. package/{cli-utils.js → lib/utils/load-config.js} +2 -6
  26. package/lib/utils/logs.js +94 -0
  27. package/lib/utils/md/filters.js +20 -0
  28. package/lib/utils/md/find-code-blocks.js +88 -0
  29. package/lib/utils/md/find-date.js +32 -0
  30. package/lib/utils/md/find-frontmatter.js +92 -0
  31. package/lib/utils/md/find-frontmatter.test.js +17 -0
  32. package/lib/utils/md/find-html-tags.js +105 -0
  33. package/lib/utils/md/find-images-md.js +27 -0
  34. package/lib/utils/md/find-images.js +107 -0
  35. package/lib/utils/md/find-links.js +220 -0
  36. package/lib/utils/md/find-unmatched-html-tags.js +32 -0
  37. package/lib/utils/md/fixtures/2022-01-22-date-in-filename.md +14 -0
  38. package/lib/utils/md/fixtures/file-with-frontmatter.md +32 -0
  39. package/lib/utils/md/fixtures/file-with-links.md +153 -0
  40. package/lib/utils/md/md.test.js +105 -0
  41. package/lib/utils/md/parse.js +146 -0
  42. package/lib/utils/md/utils.js +19 -0
  43. package/lib/utils/regex-timeout.js +84 -0
  44. package/lib/utils/regex.js +40 -6
  45. package/lib/utils/remoteRequest.js +55 -0
  46. package/lib/utils/syntax.js +82 -0
  47. package/lib/utils/text.js +328 -0
  48. package/lib/utils/text.test.js +305 -0
  49. package/lib/utils/toc.js +315 -0
  50. package/package.json +30 -26
  51. package/index.js +0 -46
  52. package/lib/processFile.js +0 -154
  53. package/lib/updateContents.js +0 -125
  54. package/lib/utils/_md.test.js +0 -63
  55. package/lib/utils/new-parser.js +0 -412
  56. package/lib/utils/new-parser.test.js +0 -324
  57. package/lib/utils/weird-parse.js +0 -230
  58. package/lib/utils/weird-parse.test.js +0 -217
@@ -0,0 +1,105 @@
1
+
2
+ // Might need ([\s\S]*?) instead of '*' in between tags
3
+ const HTML_TAG = /<([a-zA-Z1-6]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)/gim
4
+
5
+ const MATCH_HTML_TAGS_REGEX = /<([a-zA-Z1-6]+)\b([^>]*)>*(?:>([\s\S]*?)<\/\1>|\s?\/?>)/gm
6
+ // old forces closes / - /<([a-zA-Z1-6]+)\b([^>]*)>*(?:>([\s\S]*?)<\/\1>|\s?\/>)/gm
7
+
8
+ function findHtmlTags(mdContents) {
9
+ const parents = mdContents
10
+ /* Fix non terminating <tags> */
11
+ .replace(/(['"`]<(.*)>['"`])/gm, '_$2_')
12
+ .match(MATCH_HTML_TAGS_REGEX)
13
+ // console.log('parents', parents)
14
+
15
+ if (parents) {
16
+ // const children = parents.filter(Boolean).map((p) => {
17
+ // return p.match(HTML_TAG)
18
+ // })
19
+ // console.log('children', children)
20
+ }
21
+
22
+ const htmlTags = mdContents
23
+ /* Fix non terminating <tags> */
24
+ .replace(/(['"`]<(.*)>['"`])/gm, '_$2_')
25
+ .match(MATCH_HTML_TAGS_REGEX)
26
+ // console.log('htmlTags', htmlTags)
27
+
28
+ let tags = []
29
+ if (htmlTags) {
30
+ let propsValues = {}
31
+ // var regexSingleTag = /<([a-zA-Z1-6]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)/
32
+ // var regexSingleTag = /<([a-zA-Z1-6]+)([^<]+)*(?:>([\s\S]*?)<\/\1>|\s*\/>)/
33
+ var regexSingleTag = /<([a-zA-Z1-6]+)\b([^>]*)>*(?:>([\s\S]*?)<\/\1>|\s?\/?>)/
34
+ for (var i = 0; i < htmlTags.length; i++) {
35
+ // console.log('htmlTags[i]', htmlTags[i])
36
+ var tagMatches = regexSingleTag.exec(htmlTags[i]) || []
37
+ // console.log('tagMatches', tagMatches)
38
+ var [ match, tag, props ] = tagMatches
39
+ // console.log(`Tag #${i} ${tag}`)
40
+ if (props) {
41
+ const cleanProps = props
42
+ // Remove new lines and tabs
43
+ .replace(/\n\t/g, '')
44
+ // Remove extra spaces
45
+ .replace(/\s\s+/g, ' ')
46
+ .trim()
47
+
48
+ propsValues = cleanProps.split(" ").reduce((acc, curr) => {
49
+ const hasQuotes = curr.match(/=['"]/)
50
+ // Check key="value" | key='value' | key={value}
51
+ const propWithValue = /([A-Za-z-_$]+)=['{"](.*)['}"]/g.exec(curr)
52
+ if (propWithValue && propWithValue[1]) {
53
+ return {
54
+ ...acc,
55
+ [`${propWithValue[1]}`]: (hasQuotes) ? propWithValue[2] : convert(propWithValue[2])
56
+ }
57
+ }
58
+ // Check isLoading boolean props
59
+ const booleanProp = curr.match(/([A-Za-z]*)/)
60
+ if (booleanProp && booleanProp[1]) {
61
+ return {
62
+ ...acc,
63
+ [`${booleanProp[1]}`]: true
64
+ }
65
+ }
66
+ return acc
67
+ }, {})
68
+ }
69
+
70
+ tags.push({
71
+ tag: tag,
72
+ props: propsValues,
73
+ raw: match
74
+ })
75
+ }
76
+ }
77
+ return tags
78
+ }
79
+
80
+ function convert(value) {
81
+ if (value === 'false') {
82
+ return false
83
+ }
84
+ if (value === 'true') {
85
+ return true
86
+ }
87
+ const isNumber = Number(value)
88
+ if (typeof isNumber === 'number' && !isNaN(isNumber)) {
89
+ return isNumber
90
+ }
91
+
92
+ try {
93
+ const val = JSON.parse(value)
94
+ return val
95
+ } catch (err) {
96
+
97
+ }
98
+
99
+ return value
100
+ }
101
+
102
+ module.exports = {
103
+ findHtmlTags,
104
+ MATCH_HTML_TAGS_REGEX
105
+ }
@@ -0,0 +1,27 @@
1
+ const { onlyUnique } = require('./filters')
2
+
3
+ // https://regex101.com/r/u2DwY2/2/
4
+ const MARKDOWN_IMAGE_REGEX = /!\[[^\]]*\]\((.*?)\s*("(?:.*[^"])")?\s*\)/g
5
+
6
+ /**
7
+ * Get markdown style images from text
8
+ * @param {string} text
9
+ * @returns {string[]}
10
+ */
11
+ function findMarkdownImages(text) {
12
+ let matches
13
+ let imageLinks = []
14
+ while ((matches = MARKDOWN_IMAGE_REGEX.exec(text)) !== null) {
15
+ if (matches.index === MARKDOWN_IMAGE_REGEX.lastIndex) {
16
+ MARKDOWN_IMAGE_REGEX.lastIndex++ // avoid infinite loops with zero-width matches
17
+ }
18
+ const [ match, image, altText ] = matches
19
+ imageLinks.push(image)
20
+ }
21
+ return imageLinks.filter(onlyUnique)
22
+ }
23
+
24
+ module.exports = {
25
+ findMarkdownImages,
26
+ MARKDOWN_IMAGE_REGEX
27
+ }
@@ -0,0 +1,107 @@
1
+ const { onlyUnique, isImage, isRelative } = require('./filters')
2
+ const { findLinks, findAbsoluteLinks } = require('./find-links')
3
+ const { findMarkdownImages, MARKDOWN_IMAGE_REGEX } = require('./find-images-md')
4
+
5
+ // https://regex101.com/r/Uxgu3P/1
6
+ const RELATIVE_IMAGES_REGEX = /(<img.*?src=['"])(?!(?:(?:https?|ftp):\/\/|data:))(\.?\/)?(.*?)(['"].*?\/?>)/gim
7
+
8
+ /**
9
+ * @typedef {object} findImagesOpts
10
+ * @property {string[]} [links] - optional links to use to avoid re-parse
11
+ * @property {boolean} [unique=true] - ensure links unique
12
+ * @property {Record<string,any>} [frontmatter] - Frontmatter data
13
+ */
14
+
15
+ /**
16
+ * @typedef {object} findImagesResult
17
+ * @property {string[]} all - All links
18
+ * @property {string[]} absolute - All absolute links
19
+ * @property {string[]} relative - All relative links
20
+ * @property {string[]} md - All md style links
21
+ */
22
+
23
+ /**
24
+ * Get image links from content
25
+ * @param {string} content
26
+ * @param {findImagesOpts} [opts] - optional links to use to avoid re-parse
27
+ * @returns {findImagesResult}
28
+ */
29
+ function findImages(content = '', opts = {}) {
30
+ const { links, unique = true, frontmatter } = opts
31
+ let foundLinks = []
32
+ if (links && Array.isArray(links)) {
33
+ foundLinks = links
34
+ } else {
35
+ const results = findLinks(content, { frontmatter })
36
+ foundLinks = results.links.concat(results.images)
37
+ }
38
+ const imageLinks = foundLinks.filter(isImage)
39
+ const markdownLinks = findMarkdownImages(content)
40
+ const allImageLinks = imageLinks.concat(markdownLinks)
41
+ const all = (!unique) ? allImageLinks : allImageLinks.filter(onlyUnique)
42
+ return {
43
+ all,
44
+ absolute: all.filter((link) => !isRelative(link)),
45
+ relative: all.filter((link) => isRelative(link)),
46
+ md: markdownLinks
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Get absolute url image links
52
+ * @param {string} content
53
+ * @param {array} [links] - optional links to use to avoid re-parse
54
+ * @returns {array}
55
+ */
56
+ function findAbsoluteImages(content = '', links) {
57
+ const foundLinks = (links && Array.isArray(links)) ? links : findAbsoluteLinks(content)
58
+ const imageLinks = foundLinks.filter(isImage)
59
+ const markdownLinks = findMarkdownImages(content)
60
+ const allImageLinks = imageLinks.concat(markdownLinks)
61
+
62
+ return allImageLinks
63
+ .filter(onlyUnique)
64
+ .filter((link) => !isRelative(link))
65
+ }
66
+
67
+ /**
68
+ * Get relative image links from content
69
+ * @param {string} text
70
+ * @returns {array}
71
+ */
72
+ function findRelativeImages(text) {
73
+ const imgTags = findRelativeImgTags(text) || []
74
+ const mdTags = findMarkdownImages(text).filter(isRelative)
75
+ return imgTags.concat(mdTags)
76
+ }
77
+
78
+ /*
79
+ // https://regex101.com/r/SvMfme/1
80
+ <img src="img/deploy/button.svg" />
81
+ <img src="/img/deploy/button.svg" />
82
+ <img src='/img/deploy/button.svg' />
83
+ <img src='./img/deploy/button.svg' />
84
+ <img src='../img/deploy/button.svg' />
85
+ <img src='../../img/deploy/button.svg' />
86
+ */
87
+ function findRelativeImgTags(block) {
88
+ let matches
89
+ let relLinks = []
90
+ while ((matches = RELATIVE_IMAGES_REGEX.exec(block)) !== null) {
91
+ if (matches.index === RELATIVE_IMAGES_REGEX.lastIndex) {
92
+ RELATIVE_IMAGES_REGEX.lastIndex++ // avoid infinite loops with zero-width matches
93
+ }
94
+ const [ match, _, start, link ] = matches
95
+ relLinks.push(`${start || ''}${link}`)
96
+ }
97
+ return relLinks.filter(onlyUnique)
98
+ }
99
+
100
+ module.exports = {
101
+ findImages,
102
+ findAbsoluteImages,
103
+ findRelativeImages,
104
+ findMarkdownImages,
105
+ MARKDOWN_IMAGE_REGEX,
106
+ RELATIVE_IMAGES_REGEX
107
+ }
@@ -0,0 +1,220 @@
1
+ const { onlyUnique, isImage, isRelative } = require('./filters')
2
+ const { findMarkdownImages } = require('./find-images-md')
3
+ // Alt https://github.com/MikeKovarik/link-extract
4
+
5
+ // https://regex101.com/r/In5HtG/3
6
+ // const LIVE_LINKS_REGEX = /(?:['"(])((?:https?:\/\/)[\w\d\-_,./?=#%:+&]{3,})/gmi
7
+ // https://regex101.com/r/In5HtG/4
8
+ const LIVE_LINKS_REGEX = /['"(]((?:https?:\/\/)[\w\d\-_,./?=#%:+&]{3,})|<(\S*:\/\/\S*)>/gmi
9
+ // https://regex101.com/r/Nywerx/3
10
+ const RELATIVE_LINKS_REGEX = /(src|href|\()=?(['"/])(?!(?:(?:https?|ftp):\/\/|data:))(\.?\/)?([\w\d-_./,?=#%:+&]+)(?:['")])?/gim
11
+ // https://regex101.com/r/u2DwY2/2/
12
+ const MARKDOWN_IMAGE_REGEX = /!\[[^\]]*\]\((.*?)\s*("(?:.*[^"])")?\s*\)/g
13
+ // https://regex101.com/r/UeQ049/2 <https://www.markdownguide.org>
14
+ const ANGLE_LINKS = /(<)(\S*[@:]\S*)(>)/
15
+
16
+ const LINK_PATTERN = /^https?:\/\//
17
+
18
+ function isLocal(link) {
19
+ return isRelative(link)
20
+ }
21
+
22
+ function isRemote(link) {
23
+ return !isRelative(link)
24
+ }
25
+
26
+ /**
27
+ * @typedef {object} findLinksOpts
28
+ * @property {Record<string,any>} [frontmatter] - Frontmatter data
29
+ * @property {boolean} [unique=true] - ensure links unique
30
+ */
31
+
32
+ /**
33
+ * @typedef {object} findLinksResult
34
+ * @property {string[]} links - All images
35
+ * @property {string[]} images - All live image links
36
+ */
37
+
38
+ /**
39
+ * Finds all links in text relative or otherwise
40
+ * @param {string} text
41
+ * @param {findLinksOpts} opts
42
+ * @returns {findLinksResult}
43
+ */
44
+ function findLinks(text, opts = {}) {
45
+ const { unique = true, frontmatter } = opts
46
+
47
+ const absoluteLinks = findAbsoluteLinks(text)
48
+ // console.log('absoluteLinks', absoluteLinks)
49
+ const relativeLinks = findRelativeLinks(text)
50
+ // console.log('relativeLinks', relativeLinks)
51
+ const frontmatterLinks = (frontmatter) ? findLinksInFrontMatter(frontmatter) : []
52
+ // console.log('frontmatterLinks', frontmatterLinks)
53
+ const markdownImages = findMarkdownImages(text)
54
+ // console.log('markdownImages', markdownImages)
55
+ const foundLinks = frontmatterLinks
56
+ .concat(absoluteLinks)
57
+ .concat(relativeLinks)
58
+ .concat(markdownImages)
59
+
60
+ const allLinks = (!unique) ? foundLinks : foundLinks.filter(onlyUnique)
61
+
62
+ let _images = markdownImages
63
+ let _links = []
64
+ for (let i = 0; i < allLinks.length; i++) {
65
+ if (isImage(allLinks[i])) {
66
+ _images.push(allLinks[i])
67
+ } else {
68
+ _links.push(allLinks[i])
69
+ }
70
+ }
71
+ // const allImages = normalLinks.filter((link) => isImage(link)).concat(mdLinks)
72
+ // const links = normalLinks.filter((link) => !isImage(link))
73
+ const images = _images.filter(onlyUnique)
74
+ const links = _links.filter(onlyUnique).filter(function(el) {
75
+ return images.indexOf(el) < 0
76
+ })
77
+
78
+ return {
79
+ links,
80
+ images
81
+ }
82
+ /*
83
+ // Old return https://github.com/DavidWells/markdown-magic/blob/b148b4ad3876c4ea07371451d230a5e9cec57ce5/lib/utils/md/find-links.js#L32-L44
84
+ return {
85
+ // all,
86
+ // live,
87
+ // relative,
88
+ // frontmatter: frontmatterLinks,
89
+ links: {
90
+ all: allLink,
91
+ relative: allLink.filter(isLocal),
92
+ live: allLink.filter(isRemote)
93
+ },
94
+ images: {
95
+ all: allImg,
96
+ relative: allImg.filter(isLocal),
97
+ live: allImg.filter(isRemote)
98
+ },
99
+ }
100
+ */
101
+ }
102
+
103
+ function findMarkdownImageLinks(text) {
104
+ let matches
105
+ let imageLinks = []
106
+ while ((matches = MARKDOWN_IMAGE_REGEX.exec(text)) !== null) {
107
+ if (matches.index === MARKDOWN_IMAGE_REGEX.lastIndex) {
108
+ MARKDOWN_IMAGE_REGEX.lastIndex++ // avoid infinite loops with zero-width matches
109
+ }
110
+ const [ match, image, altText ] = matches
111
+ imageLinks.push(image)
112
+ }
113
+ return imageLinks.filter(onlyUnique)
114
+ }
115
+
116
+ /**
117
+ * Finds all links in markdown <a>, <img> and md link format []()
118
+ * @param {string} text
119
+ * @returns
120
+ */
121
+ function findAbsoluteLinks(text) {
122
+ let matches
123
+ let links = []
124
+ while ((matches = LIVE_LINKS_REGEX.exec(text)) !== null) {
125
+ if (matches.index === LIVE_LINKS_REGEX.lastIndex) {
126
+ LIVE_LINKS_REGEX.lastIndex++ // avoid infinite loops with zero-width matches
127
+ }
128
+ const [ match, url, bracketLink ] = matches
129
+ links.push(url || bracketLink)
130
+ }
131
+ return links.filter(onlyUnique)
132
+ }
133
+
134
+ /*
135
+ Match relative links
136
+ <h1 jdjdjjdjd=lksjskljfsdlk="jdjdj">Netlify + FaunaDB &nbsp;&nbsp;&nbsp;
137
+ <a href="https://app.netlify.com/start/deploy?repository=https://github.com/netlify/netlify-faunadb-example&stack=fauna">
138
+ <img src="../../../../img/deploy/lol.svg">
139
+ </a>
140
+ </h1>
141
+ [link](/my-great-page)
142
+ <a href="img/deploy/one.svg">cool</a>
143
+ <img src="img/deploy/duplicate.svg" />
144
+ <img src="img/deploy/duplicate.svg" >
145
+ <img src="/img/deploy/three.svg" />
146
+ <img src='/img/deploy/four.svg' />
147
+ <img src='./img/deploy/five.svg' />
148
+ <img src='../img/deploy/button.svg' />
149
+ <img src='../../img/deploy/button.svg' />
150
+ <img src="https://www.netlify.com/img/deploy/button.svg" />
151
+ <img src="https://www.netlify.com/img/deploy/button.svg" />
152
+ ![The San Juan Mountains are beautiful!](/assets/images/san-juan-mountains.jpg "San Juan Mountains")
153
+ */
154
+
155
+ function findRelativeLinks(text) {
156
+ let matches
157
+ let relLinks = []
158
+ while ((matches = RELATIVE_LINKS_REGEX.exec(text)) !== null) {
159
+ if (matches.index === RELATIVE_LINKS_REGEX.lastIndex) {
160
+ RELATIVE_LINKS_REGEX.lastIndex++ // avoid infinite loops with zero-width matches
161
+ }
162
+ // console.log(matches)
163
+ const [ match, _, start, link, x ] = matches
164
+ const one = (start === '/') ? start : ''
165
+ const two = (link === '/') ? link : ''
166
+ relLinks.push(`${one}${two}${x}`)
167
+ }
168
+ return relLinks.filter(onlyUnique)
169
+ }
170
+
171
+ function findLinksInFrontMatter(data) {
172
+ const yamlStrings = traverse(data)
173
+ // console.log('yamlStrings', yamlStrings)
174
+ const linksInYml = yamlStrings.map((string) => {
175
+ if (LINK_PATTERN.test(string)) {
176
+ return [string]
177
+ }
178
+ // console.log('string', string)
179
+ const results = findLinks(string)
180
+ return results.links.concat(results.images)
181
+ })
182
+ .filter((x) => {
183
+ if (x && x.length) {
184
+ return x.length
185
+ }
186
+ return false
187
+ })
188
+ .flat()
189
+ // console.log('linksInYml', linksInYml)
190
+ return linksInYml
191
+ }
192
+
193
+ function traverse(x, arr = []) {
194
+ if (typeof x === 'string') {
195
+ arr.push(x)
196
+ } else if (Array.isArray(x)) {
197
+ traverseArray(x, arr)
198
+ } else if ((typeof x === 'object') && (x !== null)) {
199
+ traverseObject(x, arr)
200
+ }
201
+ return arr
202
+ }
203
+ function traverseArray(arr, acc) {
204
+ for (let i = 0; i < arr.length; i++) {
205
+ traverse(arr[i], acc)
206
+ }
207
+ }
208
+ function traverseObject(obj, acc) {
209
+ for (var key in obj) {
210
+ if (obj.hasOwnProperty(key)) {
211
+ traverse(obj[key], acc)
212
+ }
213
+ }
214
+ }
215
+
216
+ module.exports = {
217
+ findLinks,
218
+ findAbsoluteLinks,
219
+ findRelativeLinks
220
+ }
@@ -0,0 +1,32 @@
1
+ const { getLineNumberFromMatch } = require('./utils')
2
+
3
+ // https://regex101.com/r/he9l06/2
4
+ // http://xahlee.info/js/html5_non-closing_tag.html
5
+ // voidTags
6
+ const CLOSE_TAG_REGEX = /<(br|hr|img|embed|col|link|meta)(([^>]*)([^/])(>)|>)/g
7
+
8
+ function findUnmatchedHtmlTags(block, filePath) {
9
+ let matches
10
+ let errors = []
11
+ const msg = (filePath) ? ` in ${filePath}` : ''
12
+ while ((matches = CLOSE_TAG_REGEX.exec(block)) !== null) {
13
+ if (matches.index === CLOSE_TAG_REGEX.lastIndex) {
14
+ CLOSE_TAG_REGEX.lastIndex++ // avoid infinite loops with zero-width matches
15
+ }
16
+ // console.log(matches)
17
+ const [ _, tag, insideOrEnd ] = matches
18
+ const lineNumber = getLineNumberFromMatch(block, matches)
19
+ const fixed = (insideOrEnd === '>') ? '/>' : `${insideOrEnd.substring(0, insideOrEnd.length - 1)}/>`
20
+ errors.push({
21
+ message: `Unclosing HTML tag on line ${lineNumber}${msg}.\n Need closing tag "/>" on: \n${_}`,
22
+ brokenTag: _,
23
+ correctUsage: `<${tag}${fixed}`
24
+ })
25
+ }
26
+ return errors
27
+ }
28
+
29
+ module.exports = {
30
+ CLOSE_TAG_REGEX,
31
+ findUnmatchedHtmlTags,
32
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ title: Welcome to ABC
3
+ description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
4
+ thumbnail: https://dope-frontmatter.com/img/deploy/button.svg
5
+ categories:
6
+ - company
7
+ authors:
8
+ - Bob Bob
9
+ - Joe Smoe
10
+ ---
11
+
12
+ **Welcome to ABC!** Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur [keynote presentation](https://youtu.be/A1bL4pHuivU).
13
+
14
+
@@ -0,0 +1,32 @@
1
+ ---
2
+ draft: true
3
+ template: page
4
+ path: /foo/bar
5
+ title: Default title
6
+ components:
7
+ - type: PageHeading
8
+ heading: Nice
9
+ subHeading: Add it
10
+ - type: content
11
+ content: >-
12
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur
13
+
14
+
15
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur
16
+ - type: content
17
+ content: |-
18
+ More content
19
+
20
+ <ComponentXyz />
21
+
22
+ stuff
23
+
24
+ ---
25
+ - type: content
26
+ content: Even more content
27
+ seo:
28
+ title: xyz
29
+ description: seo description here
30
+ updatedBy: David Wells
31
+ updatedAt: 2022-11-10T01:52:37.383Z
32
+ ---