• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

scriptype / writ-cms / 18128625706

30 Sep 2025 11:38AM UTC coverage: 73.078% (-2.4%) from 75.488%
18128625706

push

github

scriptype
Facets wip5

Handle permalinking from entries to collection facets through its faceted fields. Every facet field becomes an object: { value, facetPermalink }. If the field is a link to another entry (already object), then the facetPermalink property is added on top of existing entry object.

490 of 795 branches covered (61.64%)

Branch coverage included in aggregate %.

8 of 25 new or added lines in 4 files covered. (32.0%)

118 existing lines in 9 files now uncovered.

2276 of 2990 relevant lines covered (76.12%)

313.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.71
/src/compiler/contentModel2/models/collection/post.js
1
const { join } = require('path')
9✔
2
const makeSlug = require('slug')
9✔
3
const { isTemplateFile, parseArray, makePermalink, makeDateSlug } = require('../../helpers')
9✔
4
const models = {
9✔
5
  _baseEntry: require('../_baseEntry'),
6
  attachment: require('../attachment')
7
}
8

9
function handleFacetPermalinking(post, facets) {
10
  const collectionContext = post.context.throwUntil(c => c.facetKeys).peek()
126✔
11
  const facetKeys = collectionContext.facetKeys
63✔
12
  if (facetKeys?.length) {
63!
NEW
13
    facetKeys.forEach(facetKey => {
×
NEW
14
      const facetValue = post[facetKey]
×
NEW
15
      if (!facetValue) {
×
NEW
16
        return
×
17
      }
NEW
18
      const facetRootPermalink = facets.find(f => f.key === facetKey).permalink
×
NEW
19
      if (facetValue?.slug) {
×
NEW
20
        facetValue.facetPermalink = makePermalink(facetRootPermalink, facetValue.slug)
×
NEW
21
      } else if (Array.isArray(facetValue)) {
×
NEW
22
        post[facetKey] = facetValue.map(facetValueItem => {
×
NEW
23
          return {
×
24
            value: facetValueItem,
25
            facetPermalink: makePermalink(facetRootPermalink, makeSlug(facetValueItem))
26
          }
27
        })
NEW
28
      } else if (facetValue instanceof Date) {
×
NEW
29
        post[facetKey] = {
×
30
          value: facetValue,
31
          facetPermalink: makePermalink(facetRootPermalink, makeDateSlug(facetValue))
32
        }
33
      } else {
NEW
34
        post[facetKey] = {
×
35
          value: facetValue,
36
          facetPermalink: makePermalink(facetRootPermalink, makeSlug(facetValue))
37
        }
38
      }
39
    })
40
  }
41
}
42

43
const defaultSettings = {
9✔
44
  entryAlias: undefined
45
}
46
module.exports = function Post(settings = defaultSettings) {
9✔
47
  const indexFileNameOptions = [settings.entryAlias, 'post', 'index'].filter(Boolean)
126✔
48

49
  const isPostIndexFile = (node) => {
126✔
50
    return (
90✔
51
      isTemplateFile(node) &&
153✔
52
      node.name.match(
53
        new RegExp(`^(${indexFileNameOptions.join('|')})\\..+$`)
54
      )
55
    )
56
  }
57

58
  return {
126✔
59
    match: (node) => (
60
      isTemplateFile(node) || node.children?.find(isPostIndexFile)
99✔
61
    ),
62

63
    create: (node, context) => {
64
      const baseEntryProps = models._baseEntry(node, indexFileNameOptions)
63✔
65

66
      const permalink = makePermalink(
63✔
67
        context.peek().permalink,
68
        baseEntryProps.slug
69
      ) + (node.children ? '' : '.html')
63✔
70

71
      const outputPath = join(context.peek().outputPath, baseEntryProps.slug)
63✔
72

73
      const postContext = {
63✔
74
        title: baseEntryProps.title,
75
        slug: baseEntryProps.slug,
76
        permalink,
77
        outputPath,
78
      }
79

80
      return {
63✔
81
        ...baseEntryProps,
82
        ...postContext,
83
        context,
84
        contentType: context.peek().entryContentType,
85
        tags: parseArray(baseEntryProps.tags),
86
        date: new Date(baseEntryProps.date || baseEntryProps.stats.birthtime || Date.now()),
63!
87
        attachments: baseEntryProps.attachments.map(
88
          attachment => attachment(context.push({
36✔
89
            ...postContext,
90
            key: 'post'
91
          }))
92
        )
93
      }
94
    },
95

96
    afterEffects: (contentModel, post, facets) => {
97
      handleFacetPermalinking(post, facets)
63✔
98

99
      post.attachments.forEach(attachment => {
63✔
100
        models.attachment().afterEffects(contentModel, attachment)
36✔
101
      })
102
    },
103

104
    render: (renderer, post, { contentModel, settings, debug }) => {
UNCOV
105
      const renderPost = () => {
×
UNCOV
106
        const data = {
×
107
          ...contentModel,
108
          post,
109
          settings,
110
          debug
111
        }
112
        const entryAlias = post.context.peek().entryAlias
×
UNCOV
113
        if (entryAlias) {
×
UNCOV
114
          data[entryAlias] = data.post
×
115
        }
116

UNCOV
117
        return renderer.render({
×
118
          templates: [
119
            `pages/${post.template}`,
120
            `pages/post/${post.contentType}`,
121
            `pages/post/default`
122
          ],
123
          outputPath: join(...[
124
            post.outputPath,
125
            post.hasIndex ? 'index' : ''
×
126
          ].filter(Boolean)) + '.html',
127
          content: post.content,
128
          data
129
        })
130
      }
131

UNCOV
132
      const renderAttachments = () => {
×
133
        return Promise.all(
×
134
          post.attachments.map(attachment => {
UNCOV
135
            return models.attachment().render(renderer, attachment)
×
136
          })
137
        )
138
      }
139

UNCOV
140
      return Promise.all([
×
141
        renderPost(),
142
        renderAttachments()
143
      ])
144
    }
145
  }
146
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc