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

arlac77 / content-entry-filesystem / 15557869734

10 Jun 2025 11:08AM CUT coverage: 90.995%. Remained the same
15557869734

push

github

arlac77
chore(deps): lock

30 of 38 branches covered (78.95%)

Branch coverage included in aggregate %.

162 of 173 relevant lines covered (93.64%)

7.17 hits per line

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

91.0
/src/content-entry-filesystem.mjs
1
import { join } from "node:path";
2✔
2
import { createReadStream, createWriteStream, constants } from "node:fs";
2✔
3
import { Readable, Writable } from "node:stream";
2✔
4
import { access, stat } from "node:fs/promises";
2✔
5
import { StreamContentEntry } from "content-entry";
2✔
6

2✔
7
/**
2✔
8
 * A ContentEntry backed by a file.
2✔
9
 */
2✔
10
export class FileSystemEntry extends StreamContentEntry {
2✔
11
  /** @type {string} */ baseDir;
10✔
12

10✔
13
  /**
10✔
14
   * @param {string} name of the file
10✔
15
   * @param {string|Object} options directory the file is located in
10✔
16
   * @property {string} name of the file
10✔
17
   * @property {object|string} options directory the file is located in
10✔
18
   * @property {string} options.basedir directory the file is located in
10✔
19
   */
10✔
20
  constructor(name, options) {
10✔
21
    super(name, options, async entry =>
18✔
22
      Readable.toWeb(createReadStream(entry.filename))
8✔
23
    );
18✔
24

18✔
25
    if (typeof options === "string") {
18✔
26
      this.baseDir = options;
16✔
27
    } else {
18✔
28
      this.baseDir = options.baseDir;
2✔
29
    }
2✔
30
  }
18✔
31

10✔
32
  /**
10✔
33
   * Absolute file path.
10✔
34
   * @return {string}
10✔
35
   */
10✔
36
  get filename() {
10✔
37
    return join(this.baseDir, this.name);
24✔
38
  }
24✔
39

10✔
40
  /**
10✔
41
   * Check for presence of the entry.
10✔
42
   * @return {Promise<boolean>|boolean}
10✔
43
   */
10✔
44
  get isExistent() {
10✔
45
    return exits(this.filename);
4✔
46
  }
4✔
47

10✔
48
  /**
10✔
49
   * Check is entry represents an empty file.
10✔
50
   * @return {Promise<boolean>|boolean}
10✔
51
   */
10✔
52
  get isEmpty() {
10✔
53
    return empty(this.filename);
4✔
54
  }
4✔
55

10✔
56
  getStat() {
10✔
57
    return this._stat || stat(this.filename).then(stat => (this._stat = stat));
20✔
58
  }
20✔
59

10✔
60
  /**
10✔
61
   * @return {number|Promise<number>}
10✔
62
   */
10✔
63
  get mode() {
10✔
64
    if (this._mode !== undefined) {
12✔
65
      return this._mode;
2✔
66
    }
2✔
67

10✔
68
    const stat = this.getStat();
10✔
69
    return stat.then
10✔
70
      ? stat.then(stat => {
12!
71
          this._mode = stat.mode;
×
72
          return this._mode;
×
73
        })
×
74
      : stat.mode;
12✔
75
  }
12✔
76

10✔
77
  set mode(value) {
10✔
78
    super.mode = value;
2✔
79
  }
2✔
80

10✔
81
  /**
10✔
82
   * @return {number|Promise<number>}
10✔
83
   */
10✔
84
  get size() {
10✔
85
    const stat = this.getStat();
2✔
86
    return stat.then ? stat.then(stat => stat.size) : stat.size;
2!
87
  }
2✔
88

10✔
89
  /**
10✔
90
   * @return {Promise<Date>}
10✔
91
   */
10✔
92
  get atime() {
10✔
93
    const stat = this.getStat();
×
94
    return stat.then ? stat.then(stat => stat.atime) : stat.atime;
×
95
  }
×
96

10✔
97
  /**
10✔
98
   * @return {Promise<Date>}
10✔
99
   */
10✔
100
  get ctime() {
10✔
101
    const stat = this.getStat();
2✔
102
    return stat.then ? stat.then(stat => stat.ctime) : stat.ctime;
2!
103
  }
2✔
104

10✔
105
  /**
10✔
106
   * @return {Promise<Date>}
10✔
107
   */
10✔
108
  get mtime() {
10✔
109
    const stat = this.getStat();
2✔
110
    return stat.then ? stat.then(stat => stat.mtime) : stat.mtime;
2!
111
  }
2✔
112

10✔
113
  /**
10✔
114
   * @return {Promise<number>}
10✔
115
   */
10✔
116
  get uid() {
10✔
117
    const stat = this.getStat();
2✔
118
    return stat.then ? stat.then(stat => stat.uid) : stat.uid;
2!
119
  }
2✔
120

10✔
121
  /**
10✔
122
   * @return {Promise<number>}
10✔
123
   */
10✔
124
  get gid() {
10✔
125
    const stat = this.getStat();
2✔
126
    return stat.then ? stat.then(stat => stat.gid) : stat.gid;
2!
127
  }
2✔
128

10✔
129
  /**
10✔
130
   * @return {WritableStream}
10✔
131
   */
10✔
132
  get writeStream() {
10✔
133
    return Writable.toWeb(createWriteStream(this.filename));
×
134
  }
×
135

10✔
136
  /**
10✔
137
   *
10✔
138
   * @returns {Object}
10✔
139
   */
10✔
140
  toJSON() {
10✔
141
    const json = super.toJSON();
2✔
142

2✔
143
    if (this._stat?.next || this._stat === undefined) {
2!
144
      delete json.mode;
×
145
    } else {
2✔
146
      json.mode = this._stat.mode;
2✔
147
    }
2✔
148
    json.baseDir = this.baseDir;
2✔
149
    return json;
2✔
150
  }
2✔
151
}
10✔
152

2✔
153
async function exits(file) {
4✔
154
  try {
4✔
155
    await access(file, constants.F_OK);
4✔
156
  } catch {
2✔
157
    return false;
2✔
158
  }
2✔
159

2✔
160
  return true;
2✔
161
}
4✔
162

2✔
163
async function empty(file) {
4✔
164
  try {
4✔
165
    const s = await stat(file);
4✔
166
    return s.size === 0;
2✔
167
  } catch (e) {
2✔
168
    if (e.code === "ENOENT") {
2✔
169
      return true;
2✔
170
    }
2✔
171
    throw e;
×
172
  }
×
173
}
4✔
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

© 2025 Coveralls, Inc