poops 1.0.18 → 1.0.20

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 (49) hide show
  1. package/README.md +71 -2
  2. package/lib/copy.js +121 -0
  3. package/lib/markups.js +226 -143
  4. package/lib/styles.js +65 -24
  5. package/lib/utils/helpers.js +197 -3
  6. package/package.json +8 -3
  7. package/poops.js +12 -1
  8. package/.eslintrc.yml +0 -10
  9. package/.github/dependabot.yml +0 -9
  10. package/.github/workflows/npm_publish.yml +0 -17
  11. package/.nojekyll +0 -1
  12. package/changelog/blog-functionality.html +0 -58
  13. package/changelog/feed.rss +0 -31
  14. package/changelog/front-matter.html +0 -61
  15. package/changelog/index.html +0 -74
  16. package/changelog/markdown-support.html +0 -56
  17. package/example/dist/css/styles.css +0 -7172
  18. package/example/dist/css/styles.css.map +0 -1
  19. package/example/dist/css/styles.min.css +0 -2
  20. package/example/dist/js/scripts.js +0 -35
  21. package/example/dist/js/scripts.js.map +0 -7
  22. package/example/dist/js/scripts.min.js +0 -2
  23. package/example/src/js/main.ts +0 -28
  24. package/example/src/js/scripts/utils.ts +0 -16
  25. package/example/src/markup/_data/features.yaml +0 -9
  26. package/example/src/markup/_data/links.json +0 -10
  27. package/example/src/markup/_data/poops.yaml +0 -7
  28. package/example/src/markup/_layouts/blog.html +0 -35
  29. package/example/src/markup/_layouts/default.html +0 -93
  30. package/example/src/markup/_partials/heading.html +0 -10
  31. package/example/src/markup/_partials/site-header.html +0 -17
  32. package/example/src/markup/changelog/blog-functionality.md +0 -9
  33. package/example/src/markup/changelog/feed.rss +0 -23
  34. package/example/src/markup/changelog/front-matter.md +0 -12
  35. package/example/src/markup/changelog/index.html +0 -30
  36. package/example/src/markup/changelog/markdown-support.md +0 -7
  37. package/example/src/markup/index.html +0 -33
  38. package/example/src/scss/_config.scss +0 -22
  39. package/example/src/scss/index.scss +0 -4
  40. package/example/src/scss/style/index.scss +0 -13
  41. package/example/src/scss/style/test.css +0 -3
  42. package/index.html +0 -166
  43. package/poop.png +0 -0
  44. package/script/build +0 -3
  45. package/script/publish +0 -138
  46. package/script/server +0 -3
  47. package/test.html +0 -96
  48. package/tsconfig.json +0 -16
  49. package//360/237/222/251.json +0 -55
package/lib/markups.js CHANGED
@@ -5,7 +5,7 @@ const nunjucks = require('nunjucks')
5
5
  const path = require('node:path')
6
6
  const PrintStyle = require('./utils/print-style.js')
7
7
 
8
- const { pathExists, pathIsDirectory, readDataFile, deleteDirectory } = helpers
8
+ const { pathExists, pathIsDirectory, readDataFile, deleteDirectory, mkDir, parseFrontMatter, clearFrontMatterCache } = helpers
9
9
  const pstyle = new PrintStyle()
10
10
 
11
11
  class RelativeLoader extends nunjucks.Loader {
@@ -13,7 +13,7 @@ class RelativeLoader extends nunjucks.Loader {
13
13
  super()
14
14
  this.templatesDir = templatesDir
15
15
  this.includePaths = includePaths || []
16
- this.includePaths.push('_*') // XXX: It is better to define templates and layouts directories in the config file? then all toghether include paths?
16
+ this.includePaths.push('_*') // XXX: It is better to define templates and layouts directories in the config file? then all together include paths?
17
17
  }
18
18
 
19
19
  getSource(name) {
@@ -31,12 +31,16 @@ class RelativeLoader extends nunjucks.Loader {
31
31
  return { src: '', path: fullPath, noCache: true }
32
32
  }
33
33
 
34
- let source = fs.readFileSync(fullPath, 'utf-8')
34
+ let source = ''
35
35
  let frontMatter = {}
36
- const match = source.match(/^\s*---\s*([\s\S]*?)---\s*/)
37
- if (match) {
38
- frontMatter = require('yaml').parse(match[1])
39
- source = source.slice(match[0].length) // Remove front matter
36
+
37
+ try {
38
+ const frontMatterResult = parseFrontMatter(fullPath)
39
+ frontMatter = frontMatterResult.frontMatter
40
+ source = frontMatterResult.content
41
+ } catch (err) {
42
+ console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${fullPath}${pstyle.reset}`)
43
+ console.log(err)
40
44
  }
41
45
 
42
46
  if (path.extname(fullPath) === '.md') {
@@ -194,7 +198,15 @@ module.exports = class Markups {
194
198
  getSingleCollectionData(collectionName) {
195
199
  const collectionData = []
196
200
  glob.sync(path.join(process.cwd(), this.config.markup.in, collectionName, '**/*.+(html|njk|md)'), { ignore: ['**/index.+(html|njk|md)'] }).forEach((file) => {
197
- const frontMatter = this.getFrontMatter(file)
201
+ let frontMatter = {}
202
+
203
+ try {
204
+ const frontMatterResult = parseFrontMatter(file)
205
+ frontMatter = frontMatterResult.frontMatter
206
+ } catch (err) {
207
+ console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${file}${pstyle.reset}`)
208
+ console.log(err)
209
+ }
198
210
 
199
211
  if (frontMatter.published === false) return // Skip unpublished items
200
212
 
@@ -223,69 +235,109 @@ module.exports = class Markups {
223
235
  const collectionData = {}
224
236
 
225
237
  for (const indexFile of indexFiles) {
226
- const frontMatter = this.getFrontMatter(indexFile)
238
+ let frontMatter = {}
239
+
240
+ try {
241
+ const frontMatterResult = parseFrontMatter(indexFile)
242
+ frontMatter = frontMatterResult.frontMatter
243
+ } catch (err) {
244
+ console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${indexFile}${pstyle.reset}`)
245
+ console.log(err)
246
+ }
247
+
227
248
  if (!frontMatter.collection) continue
228
249
 
229
250
  if (frontMatter.collection === true) {
230
251
  frontMatter.collection = path.basename(path.dirname(indexFile))
231
252
  }
232
253
 
233
- if (frontMatter.collection.trim() === '') continue
254
+ const collectionName = frontMatter.collection.trim()
234
255
 
235
- const collection = { name: frontMatter.collection }
256
+ if (collectionName === '') continue
236
257
 
237
- if (frontMatter.paginate && !isNaN(parseInt(frontMatter.paginate))) {
238
- collection.paginate = parseInt(frontMatter.paginate)
239
- }
258
+ frontMatter.name = collectionName
259
+ const collection = this.buildCollectionObject(frontMatter)
260
+ if (!collection) continue
261
+ collectionData[collection.name] = collection
262
+ }
240
263
 
241
- if (frontMatter.sort) {
242
- collection.sort = frontMatter.sort
243
- }
264
+ return collectionData
265
+ }
244
266
 
245
- if (typeof collection.sort === 'string') {
246
- collection.sort = { by: collection.sort }
247
- }
267
+ getCollectionDataBasedOnConfig(collectionConfig) {
268
+ if (!collectionConfig) return {}
248
269
 
249
- if (!collection.sort) {
250
- collection.sort = { by: 'date' }
251
- }
270
+ const items = Array.isArray(collectionConfig)
271
+ ? collectionConfig
272
+ : [collectionConfig]
252
273
 
253
- if (!collection.sort.by) {
254
- collection.sort.by = 'date'
255
- }
274
+ const collectionData = {}
256
275
 
257
- if (collection.sort.by === 'date') {
258
- collection.sort.type = 'date'
259
- } else {
260
- collection.sort.type = 'alphabetical'
261
- }
276
+ for (let item of items) {
277
+ if (typeof item === 'string') item = { name: item }
278
+ if (!item || !item.name) continue
279
+ const collection = this.buildCollectionObject(item)
280
+ if (collection) collectionData[item.name] = collection
281
+ }
262
282
 
263
- if (!collection.sort.order) {
264
- collection.sort.order = collection.sort.type === 'date' ? 'desc' : 'asc'
265
- }
283
+ return collectionData
284
+ }
266
285
 
267
- collectionData[collection.name] = collection
286
+ buildCollectionObject(collectionProtoObject) {
287
+ const collection = {
288
+ name: collectionProtoObject.name,
289
+ items: this.getSingleCollectionData(collectionProtoObject.name)
290
+ }
268
291
 
269
- collectionData[collection.name].items = this.getSingleCollectionData(collection.name)
292
+ if (collection.items.length === 0) return null
270
293
 
271
- collectionData[collection.name].items.sort((a, b) => {
272
- if (collection.sort.type === 'date') {
273
- if (collection.sort.order === 'asc') {
274
- return new Date(a[collection.sort.by]) - new Date(b[collection.sort.by])
275
- }
294
+ if (collectionProtoObject.paginate && !isNaN(parseInt(collectionProtoObject.paginate))) {
295
+ collection.paginate = parseInt(collectionProtoObject.paginate)
296
+ }
276
297
 
277
- return new Date(b[collection.sort.by]) - new Date(a[collection.sort.by])
278
- } else {
279
- if (collection.sort.order === 'asc') {
280
- return a[collection.sort.by] > b[collection.sort.by] ? 1 : -1
281
- }
298
+ if (collectionProtoObject.sort) {
299
+ collection.sort = collectionProtoObject.sort
300
+ }
282
301
 
283
- return a[collection.sort.by] < b[collection.sort.by] ? 1 : -1
284
- }
285
- })
302
+ if (typeof collection.sort === 'string') {
303
+ collection.sort = { by: collection.sort }
286
304
  }
287
305
 
288
- return collectionData
306
+ if (!collection.sort) {
307
+ collection.sort = { by: 'date' }
308
+ }
309
+
310
+ if (!collection.sort.by) {
311
+ collection.sort.by = 'date'
312
+ }
313
+
314
+ if (collection.sort.by === 'date') {
315
+ collection.sort.type = 'date'
316
+ } else {
317
+ collection.sort.type = 'alphabetical'
318
+ }
319
+
320
+ if (!collection.sort.order) {
321
+ collection.sort.order = collection.sort.type === 'date' ? 'desc' : 'asc'
322
+ }
323
+
324
+ collection.items.sort((a, b) => {
325
+ if (collection.sort.type === 'date') {
326
+ if (collection.sort.order === 'asc') {
327
+ return new Date(a[collection.sort.by]) - new Date(b[collection.sort.by])
328
+ }
329
+
330
+ return new Date(b[collection.sort.by]) - new Date(a[collection.sort.by])
331
+ } else {
332
+ if (collection.sort.order === 'asc') {
333
+ return a[collection.sort.by] > b[collection.sort.by] ? 1 : -1
334
+ }
335
+
336
+ return a[collection.sort.by] < b[collection.sort.by] ? 1 : -1
337
+ }
338
+ })
339
+
340
+ return collection
289
341
  }
290
342
 
291
343
  clearCollectionOutputDir(collectionName) {
@@ -293,15 +345,27 @@ module.exports = class Markups {
293
345
  deleteDirectory(collectionDirectoryPath) // Remove collection directory
294
346
  }
295
347
 
296
- getRelativePathPrefix(outputDir) {
297
- const relativeDir = path.relative(process.cwd(), outputDir)
348
+ getRelativePathPrefix(outputDir, fromDir) {
349
+ let relativeDir = path.relative(process.cwd(), outputDir)
350
+ const fromRelativeDir = fromDir ? path.relative(process.cwd(), fromDir) : ''
351
+
352
+ if (fromRelativeDir && relativeDir.startsWith(fromRelativeDir)) {
353
+ relativeDir = relativeDir.replace(fromRelativeDir, '')
354
+ }
355
+
356
+ return this.getUpDirPrefix(relativeDir)
357
+ }
358
+
359
+ getUpDirPrefix(relativeDir) {
298
360
  if (relativeDir.trim() === '') return ''
361
+ if (relativeDir.startsWith(path.sep)) relativeDir = relativeDir.slice(1)
362
+ if (relativeDir.endsWith(path.sep)) relativeDir = relativeDir.slice(0, -1)
299
363
  const relativePathParts = relativeDir.split(path.sep)
300
- let relativePathPrefix = ''
364
+ let upDir = ''
301
365
  for (let i = 0; i < relativePathParts.length; i++) {
302
- relativePathPrefix += '../'
366
+ upDir += `..${path.sep}`
303
367
  }
304
- return relativePathPrefix
368
+ return upDir
305
369
  }
306
370
 
307
371
  getPageUrl(outputPath) {
@@ -323,8 +387,6 @@ module.exports = class Markups {
323
387
  }
324
388
 
325
389
  compileEntry(templateName, additionalContext) {
326
- const source = fs.readFileSync(templateName, 'utf-8')
327
- const match = source.match(/^\s*---\s*([\s\S]*?)---\s*/) // Front matter match
328
390
  const context = { page: {} }
329
391
  let pageUrl
330
392
 
@@ -335,13 +397,13 @@ module.exports = class Markups {
335
397
  }
336
398
  Object.assign(context, additionalContext)
337
399
  }
338
- if (match) {
339
- try {
340
- context.page = require('yaml').parse(match[1]) // Pass front matter to the template
341
- } catch (err) {
342
- console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${templateName}${pstyle.reset}`)
343
- console.log(err)
344
- }
400
+
401
+ try {
402
+ const frontMatterResult = parseFrontMatter(templateName)
403
+ context.page = frontMatterResult.frontMatter
404
+ } catch (err) {
405
+ console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${templateName}${pstyle.reset}`)
406
+ console.log(err)
345
407
  }
346
408
 
347
409
  if (pageUrl) context.page.url = pageUrl
@@ -358,106 +420,122 @@ module.exports = class Markups {
358
420
  })
359
421
  }
360
422
 
423
+ getCollectionIndexFile(collectionName) {
424
+ const indexFiles = glob.sync(path.join(process.cwd(), this.config.markup.in, collectionName, 'index.+(html|njk|md)'))
425
+ if (indexFiles.length === 0) return null
426
+ return indexFiles[0]
427
+ }
428
+
429
+ buildCollectionPaginationData(collectionData) {
430
+ if (!collectionData) return
431
+
432
+ for (const collectionName of Object.keys(collectionData)) {
433
+ const collection = collectionData[collectionName]
434
+
435
+ if (!collection.paginate) continue
436
+
437
+ collection.pages = []
438
+ let pageItems = []
439
+ for (const item of collection.items) {
440
+ if (pageItems.length === collection.paginate) {
441
+ collection.pages.push(pageItems)
442
+ pageItems = []
443
+ }
444
+ pageItems.push(item)
445
+ }
446
+ collection.pages.push(pageItems)
447
+
448
+ collection.totalPages = collection.pages.length
449
+ }
450
+ }
451
+
452
+ generateCollectionPaginationPages(collectionData, compilePromises) {
453
+ if (!collectionData) return
454
+
455
+ for (const collectionName of Object.keys(collectionData)) {
456
+ const collection = collectionData[collectionName]
457
+ const file = this.getCollectionIndexFile(collectionName)
458
+
459
+ if (!collection.totalPages || collection.totalPages === 0) {
460
+ collection.totalPages = 1
461
+ collection.pages = [collection.items]
462
+ }
463
+
464
+ for (let i = 0; i < collection.totalPages; i++) {
465
+ collection.pageItems = collection.pages[i]
466
+ collection.pageNumber = i + 1
467
+ collection.pageUrl = collection.pageNumber === 1 ? collection.name : `${collection.name}/${collection.pageNumber}`
468
+ collection.nextPage = collection.pageNumber === collection.totalPages ? null : collection.pageNumber + 1
469
+ collection.nextPageUrl = collection.pageNumber === collection.totalPages ? null : `${collection.name}/${collection.pageNumber + 1}`
470
+ collection.prevPage = collection.pageNumber === 1 ? null : collection.pageNumber - 1
471
+ collection.prevPageUrl = collection.pageNumber === 1 ? null : `${collection.name}/${collection.pageNumber - 1}`
472
+ if (collection.prevPage === 1) {
473
+ collection.prevPageUrl = collection.name
474
+ }
475
+
476
+ const markupOut = path.join(process.cwd(), this.config.markup.out, collection.pageUrl, 'index.html')
477
+ const fromPath = path.join(process.cwd(), this.config.markup.out)
478
+ const markupOutDir = path.dirname(markupOut)
479
+
480
+ mkDir(markupOutDir)
481
+
482
+ collectionData.relativePathPrefix = this.getRelativePathPrefix(markupOutDir, fromPath)
483
+ collectionData._url = this.getPageUrl(markupOut)
484
+
485
+ if (!file) {
486
+ continue
487
+ }
488
+
489
+ const compilePromise = this.compileEntry(file, collectionData).then((result) => {
490
+ fs.writeFileSync(markupOut, result)
491
+ })
492
+ compilePromises.push(compilePromise)
493
+ }
494
+ }
495
+ }
496
+
361
497
  compile() {
362
- // TODO: should support multiple markup paths, for loop here!
363
498
  if (!this.config.markup || !this.config.markup.in) return
364
499
 
365
500
  const markupIn = path.join(process.cwd(), this.config.markup.in)
501
+ const compilePromises = []
366
502
 
367
503
  if (!pathExists(markupIn)) {
368
504
  console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset} ${pstyle.dim}Markup path does not exist:${pstyle.reset} ${pstyle.italic + pstyle.underline}${markupIn}${pstyle.reset}`)
369
505
  return
370
506
  }
371
507
 
508
+ const collectionData = {
509
+ ...this.collectionAutoDiscovery(),
510
+ ...this.getCollectionDataBasedOnConfig(this.config.markup.options.collections)
511
+ }
512
+
513
+ // Create collection pages
514
+ this.buildCollectionPaginationData(collectionData)
515
+ this.generateCollectionPaginationPages(collectionData, compilePromises)
516
+
372
517
  if (pathIsDirectory(markupIn)) {
373
518
  const markupFiles = [...glob.sync(path.join(markupIn, this.generateMarkupGlobPattern(this.includePaths))), ...glob.sync(path.join(markupIn, '*.+(html|xml|rss|atom|json|njk|md)'))]
374
- const collectionData = this.collectionAutoDiscovery()
375
- const compilePromises = []
519
+
376
520
  markupFiles.forEach((file) => {
377
521
  const relativePath = path.relative(markupIn, file)
378
522
  const relativePathParts = relativePath.split(path.sep)
379
523
 
380
- // Create pagination for collection pages
524
+ // Collection pages already generated, skip them
381
525
  if (relativePathParts.length > 1 &&
382
526
  collectionData[relativePathParts[0]] &&
383
- (relativePathParts[1] === 'index.html' || relativePathParts[1] === 'index.njk' || relativePathParts[1] === 'index.md') &&
527
+ /^index\.(html|njk|md)$/.test(relativePathParts[1]) &&
384
528
  collectionData[relativePathParts[0]].items.length > 0) {
385
- let frontMatter = {}
386
- const source = fs.readFileSync(file, 'utf-8')
387
- const match = source.match(/^\s*---\s*([\s\S]*?)---\s*/) // Front matter match
388
- if (match) {
389
- try {
390
- frontMatter = require('yaml').parse(match[1]) // Pass front matter to the template
391
- } catch (err) {
392
- console.log(`${pstyle.redBright + pstyle.bold}[error]${pstyle.reset}${pstyle.dim} Failed parsing front matter:${pstyle.reset} ${pstyle.italic + pstyle.underline}${file}${pstyle.reset}`)
393
- console.log(err)
394
- }
395
- }
396
-
397
- if (frontMatter.paginate && !isNaN(parseInt(frontMatter.paginate))) {
398
- frontMatter.paginate = parseInt(frontMatter.paginate)
399
- }
400
-
401
- // TODO: sorting should be done via frontMatter not the config file. Collection autodiscovery from frontMatter as well
402
-
403
- const collectionName = relativePathParts[0]
404
-
405
- if (frontMatter.paginate) {
406
- const collection = collectionData[collectionName]
407
- collection.paginate = frontMatter.paginate
408
- collection.pages = []
409
- let pageItems = []
410
- for (const item of collection.items) {
411
- if (pageItems.length === collection.paginate) {
412
- collection.pages.push(pageItems)
413
- pageItems = []
414
- }
415
- pageItems.push(item)
416
- }
417
- collection.pages.push(pageItems)
418
-
419
- collection.totalPages = collection.pages.length
420
-
421
- for (let i = 0; i < collection.totalPages; i++) {
422
- collection.pageItems = collection.pages[i]
423
- collection.pageNumber = i + 1
424
- collection.pageUrl = collection.pageNumber === 1 ? collectionName : `${collectionName}/${collection.pageNumber}`
425
- collection.nextPage = collection.pageNumber === collection.totalPages ? null : collection.pageNumber + 1
426
- collection.nextPageUrl = collection.pageNumber === collection.totalPages ? null : `${collectionName}/${collection.pageNumber + 1}`
427
- collection.prevPage = collection.pageNumber === 1 ? null : collection.pageNumber - 1
428
- collection.prevPageUrl = collection.pageNumber === 1 ? null : `${collectionName}/${collection.pageNumber - 1}`
429
- if (collection.prevPage === 1) {
430
- collection.prevPageUrl = collectionName
431
- }
432
-
433
- const markupOut = path.join(process.cwd(), this.config.markup.out, collection.pageUrl, 'index.html')
434
- const markupOutDir = path.dirname(markupOut)
435
-
436
- if (!pathExists(markupOutDir)) {
437
- fs.mkdirSync(markupOutDir, { recursive: true })
438
- }
439
-
440
- collectionData.relativePathPrefix = this.getRelativePathPrefix(markupOutDir)
441
- collectionData._url = this.getPageUrl(markupOut)
442
-
443
- const compilePromise = this.compileEntry(file, collectionData).then((result) => {
444
- fs.writeFileSync(markupOut, result)
445
- })
446
- compilePromises.push(compilePromise)
447
- }
448
- }
449
-
450
529
  return
451
530
  }
452
531
 
453
- let markupOut = path.join(process.cwd(), relativePath)
532
+ let markupOut = path.join(process.cwd(), this.config.markup.out, relativePath)
533
+ const fromPath = path.join(process.cwd(), this.config.markup.out)
454
534
  const markupOutDir = path.dirname(markupOut)
455
535
 
456
- if (!pathExists(markupOutDir)) {
457
- fs.mkdirSync(markupOutDir, { recursive: true })
458
- }
536
+ mkDir(markupOutDir)
459
537
 
460
- collectionData.relativePathPrefix = this.getRelativePathPrefix(markupOutDir)
538
+ collectionData.relativePathPrefix = this.getRelativePathPrefix(markupOutDir, fromPath)
461
539
  collectionData._url = this.getPageUrl(markupOut)
462
540
 
463
541
  const compilePromise = this.compileEntry(file, collectionData).then((result) => {
@@ -470,27 +548,32 @@ module.exports = class Markups {
470
548
  return new Promise((resolve, reject) => {
471
549
  Promise.all(compilePromises).then(() => {
472
550
  console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.dim}Compiled: ${pstyle.reset}${markupFiles.length} file${markupFiles.length > 1 ? 's' : ''} into ${pstyle.italic + pstyle.underline}${this.config.markup.out}${pstyle.reset}`)
551
+ clearFrontMatterCache()
473
552
  resolve()
474
553
  }).catch((err) => {
475
554
  console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.redBright + pstyle.bold}[error]${pstyle.reset} ${pstyle.dim}Failed compiling${pstyle.reset + pstyle.bell}`)
476
555
  console.log(err)
556
+ clearFrontMatterCache()
477
557
  reject(err)
478
558
  })
479
559
  })
480
560
  } else {
481
561
  let markupOut = path.join(process.cwd(), this.config.markup.out)
482
562
  const markupOutDir = path.dirname(markupOut)
483
- const additionalContext = {}
484
- additionalContext.relativePathPrefix = this.getRelativePathPrefix(markupOutDir)
485
- additionalContext._url = this.getPageUrl(markupOut)
563
+ mkDir(markupOutDir)
564
+
565
+ collectionData.relativePathPrefix = this.getRelativePathPrefix(markupOutDir)
566
+ collectionData._url = this.getPageUrl(markupOut)
486
567
 
487
- return this.compileEntry(markupIn, additionalContext).then((result) => {
568
+ return this.compileEntry(markupIn, collectionData).then((result) => {
488
569
  markupOut = this.replaceOutExtensions(markupOut)
489
570
  fs.writeFileSync(markupOut, result)
490
571
  console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.dim}Compiled:${pstyle.reset} ${pstyle.italic + pstyle.underline}${path.relative(process.cwd(), path.join(process.cwd(), this.config.markup.out, path.basename(markupIn)))}${pstyle.reset}`)
572
+ clearFrontMatterCache()
491
573
  }).catch((err) => {
492
574
  console.log(`${pstyle.cyanBright + pstyle.bold}[markup]${pstyle.reset} ${pstyle.redBright + pstyle.bold}[error]${pstyle.reset} ${pstyle.dim}Failed compiling:${pstyle.reset} ${pstyle.italic + pstyle.underline}${path.relative(process.cwd(), path.join(process.cwd(), this.config.markup.out, path.basename(markupIn)))}${pstyle.reset + pstyle.bell}`)
493
575
  console.log(err)
576
+ clearFrontMatterCache()
494
577
  })
495
578
  }
496
579
  }
package/lib/styles.js CHANGED
@@ -20,47 +20,88 @@ const {
20
20
  const pstyle = new PrintStyle()
21
21
 
22
22
  function tryToFindFile(filePath, extensions) {
23
- const fileExt = extensions.find(ext => fs.existsSync(`${filePath}.${ext}`))
24
- if (fileExt) {
25
- return `${filePath}.${fileExt}`
23
+ const pathParts = path.parse(filePath)
24
+ if (pathParts.ext && pathParts.ext.length > 0 && extensions.includes(pathParts.ext.slice(1))) {
25
+ if (fs.existsSync(filePath)) return filePath
26
26
  }
27
+
28
+ let fileExt = extensions.find(ext => fs.existsSync(`${filePath}.${ext}`))
29
+ if (fileExt) return `${filePath}.${fileExt}`
30
+
31
+ if (!pathParts.name.startsWith('_')) {
32
+ pathParts.name = `_${pathParts.name}`
33
+ const underscoredFilePath = path.format(pathParts)
34
+ fileExt = extensions.find(ext => fs.existsSync(`${underscoredFilePath}.${ext}`))
35
+ if (fileExt) return `${underscoredFilePath}.${fileExt}`
36
+ }
37
+
27
38
  return null
28
39
  }
29
40
 
41
+ function extractMainPathFromPackageJson(packageJsonPath) {
42
+ if (!pathExists(packageJsonPath, 'package.json')) return null
43
+
44
+ const pkg = require(path.join(process.cwd(), packageJsonPath, 'package.json'))
45
+
46
+ const mainPath = pkg.sass || pkg.scss || pkg.style || pkg.css || pkg.main
47
+ if (!mainPath) return null
48
+
49
+ return mainPath
50
+ }
51
+
52
+ function getPackagePath(url) {
53
+ const parts = path.parse(url)
54
+ if (!parts.dir) return null
55
+ const dirChunks = parts.dir.split(path.sep)
56
+ if (dirChunks.length === 0) return null
57
+ if (dirChunks[0].startsWith('@') && dirChunks.length > 1) {
58
+ return path.join(dirChunks[0], dirChunks[1])
59
+ }
60
+ return dirChunks[0]
61
+ }
62
+
30
63
  function sassPathResolver(url, resolvePath, infilePath) {
64
+ // check if resole path, like `node_modules` exists
31
65
  const resolvedPath = pathToFileURL(resolvePath)
32
66
  if (!fs.existsSync(resolvedPath.pathname)) return null
33
67
  const importPath = path.relative(process.cwd(), path.join(resolvedPath.pathname, url))
34
68
 
35
- if (!fs.existsSync(importPath)) { // Will this ever fire?
36
- const correctFile = tryToFindFile(importPath, ['sass', 'scss', 'css'])
37
- if (correctFile) return new URL(correctFile, resolvedPath)
38
- }
69
+ // 1. Maybe it's a directory?
70
+ if (pathExists(importPath) && pathIsDirectory(importPath)) {
71
+ // Try to find an index file within the directory
72
+ const correctIndexFile = tryToFindFile(path.join(importPath, 'index'), ['sass', 'scss', 'css'])
73
+ if (correctIndexFile) return new URL(correctIndexFile, resolvedPath)
39
74
 
40
- if (pathIsDirectory(importPath) && !pathExists(importPath, 'index.sass') && !pathExists(importPath, 'index.scss')) {
41
- const correctFile = tryToFindFile(importPath, ['sass', 'scss', 'css'])
75
+ // package.json discovery
76
+ const style = extractMainPathFromPackageJson(importPath)
42
77
 
43
- if (correctFile) return new URL(correctFile, resolvedPath)
78
+ const stylePath = new URL(path.join(importPath, style), resolvedPath)
79
+ if (fs.existsSync(stylePath)) return stylePath
80
+ }
44
81
 
45
- if (!pathExists(importPath, 'package.json')) return null
82
+ // 2. Maybe it's a file?
83
+ if (pathExists(importPath)) return pathToFileURL(importPath)
46
84
 
47
- const pkg = require(path.join(process.cwd(), importPath, 'package.json'))
85
+ // 2.1 Try to find the correct file with different formats
86
+ const correctFile = tryToFindFile(importPath, ['sass', 'scss', 'css'])
87
+ if (correctFile) return new URL(correctFile, resolvedPath)
48
88
 
49
- let style = pkg.sass || pkg.scss || pkg.style || pkg.css || pkg.main
50
- if (!style) return null
89
+ // 2.2 Maybe it's a file within a package?
90
+ const packagePath = getPackagePath(url)
91
+ if (packagePath) {
92
+ const packageFullPath = path.relative(process.cwd(), path.join(resolvedPath.pathname, packagePath))
93
+ const stylePath = extractMainPathFromPackageJson(packageFullPath)
51
94
 
52
- if (!Array.isArray(style)) {
53
- style = [style]
54
- }
95
+ if (stylePath) {
96
+ const styleDir = path.dirname(stylePath)
97
+ const styleFinalPath = path.join(packageFullPath, styleDir, url.replace(packagePath, ''))
55
98
 
56
- for (const styleEntry of style) {
57
- if (typeof styleEntry !== 'string') continue
58
- const stylePath = new URL(path.join(importPath, styleEntry), resolvedPath)
59
- if (fs.existsSync(stylePath)) return stylePath
99
+ const correctPackageFile = tryToFindFile(styleFinalPath, ['sass', 'scss', 'css'])
100
+ if (correctPackageFile) return new URL(correctPackageFile, resolvedPath)
60
101
  }
61
102
  }
62
103
 
63
- return new URL(importPath, resolvedPath)
104
+ return null
64
105
  }
65
106
 
66
107
  module.exports = class Styles {
@@ -90,8 +131,8 @@ module.exports = class Styles {
90
131
  // Resolve `includePaths`.
91
132
  findFileUrl(url) {
92
133
  for (const includePath of includePaths) {
93
- const resolvedPath = sassPathResolver(url, includePath)
94
- if (resolvedPath) return resolvedPath
134
+ const resolvedPath = sassPathResolver(url, includePath, infilePath)
135
+ if (resolvedPath && pathExists(resolvedPath.pathname)) return resolvedPath
95
136
  }
96
137
  return null
97
138
  }