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

scriptype / writ-cms / 27473969531

13 Jun 2026 05:32PM UTC coverage: 58.928% (-0.8%) from 59.747%
27473969531

push

github

scriptype
Implement basic content edit

// TODO: Rename node folder name if title changes, instead of just
overriding title in front-matter

644 of 1062 branches covered (60.64%)

Branch coverage included in aggregate %.

0 of 41 new or added lines in 6 files covered. (0.0%)

2 existing lines in 2 files now uncovered.

2237 of 3827 relevant lines covered (58.45%)

1134.33 hits per line

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

0.0
/src/cms/api/models/post.js
NEW
1
const { writeFile, mkdir } = require('fs/promises')
×
NEW
2
const { join } = require('path')
×
3
const matter = require('gray-matter')
×
4
const { ['default']: filenamify } = require('filenamify')
×
5
const { unusedFilename } = require('unused-filename')
×
6
const { contentRootPath } = require('../helpers')
×
7

NEW
8
const createPostModel = ({ getSettings, getContentModel }) => {
×
9
  const createPost = async ({
×
10
    taxonomyPath,
11
    title,
12
    content,
13
    excerpt,
14
    extension,
15
    metadata
16
  }) => {
17
    const opts = {
×
18
      taxonomyPath: taxonomyPath || [],
×
19
      title: title || 'Untitled',
×
20
      content: content || '',
×
21
      excerpt: excerpt || '',
×
22
      extension: extension || 'md',
×
23
      metadata: metadata || {}
×
24
    }
25
    const { rootDirectory, contentDirectory } = getSettings()
×
26
    const root = await contentRootPath(rootDirectory, contentDirectory)
×
27

28
    const sanitizedTitle = filenamify(opts.title)
×
29

30
    const path = join(...[root].concat(opts.taxonomyPath).concat(sanitizedTitle))
×
31
    const unusedPath = await unusedFilename(path)
×
32

33
    const shouldOverrideTitle = (sanitizedTitle !== opts.title) || (unusedPath !== path)
×
34
    const metadataWithTitle = shouldOverrideTitle ?
×
35
      {
36
        ...opts.metadata,
37
        title: `${opts.title}`
38
      } : opts.metadata
39

40
    const fileContent = matter.stringify({
×
41
      data: metadataWithTitle,
42
      content: opts.content,
43
      excerpt: opts.excerpt
44
    })
45
    try {
×
46
      await mkdir(unusedPath, { recursive: true })
×
47
    } catch {}
48
    return writeFile(`${join(unusedPath, 'post')}.${opts.extension}`, fileContent)
×
49
  }
50

NEW
51
  const editPost = async ({
×
52
    path,
53
    title,
54
    content,
55
    excerpt,
56
    extension,
57
    metadata
58
  }) => {
NEW
59
    if (!path) {
×
NEW
60
      throw new Error('path is required')
×
61
    }
62

NEW
63
    const opts = {
×
64
      title: title || 'Untitled',
×
65
      content: content || '',
×
66
      excerpt: excerpt || '',
×
67
      extension: extension || 'md',
×
68
      metadata: metadata || {}
×
69
    }
70

NEW
71
    const collectionName = path.split('/')[0]
×
NEW
72
    const collection = getContentModel().subtree.collections.find(c => c.name === collectionName)
×
NEW
73
    const post = collection.subtree.posts.find(p => p.path === path)
×
74

NEW
75
    const metadataWithTitle = {
×
76
      ...opts.metadata,
77
      title: `${opts.title}`
78
    }
79

NEW
80
    const fileContent = matter.stringify({
×
81
      data: metadataWithTitle,
82
      content: opts.content,
83
      excerpt: opts.excerpt
84
    })
85

NEW
86
    const isFolder = !post.extension
×
NEW
87
    const targetPath = isFolder ?
×
88
      join(post.absolutePath, post.indexFile.name) :
89
      post.absolutePath
90

NEW
91
    return writeFile(targetPath, fileContent)
×
92
  }
93

UNCOV
94
  return {
×
95
    create: createPost,
96
    edit: editPost
97
  }
98
}
99

100
module.exports = createPostModel
×
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