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

IT-Service-NPM / remark-include-code / 25315281276

04 May 2026 11:00AM UTC coverage: 97.625% (+0.2%) from 97.401%
25315281276

push

github

sergey-s-betke
refactor: refactor `editorconfigFileProperties`

66 of 72 branches covered (91.67%)

Branch coverage included in aggregate %.

8 of 8 new or added lines in 2 files covered. (100.0%)

4 existing lines in 1 file now uncovered.

715 of 728 relevant lines covered (98.21%)

20.03 hits per line

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

96.24
/src/code-content.ts
1
import { readFileSync } from 'node:fs';
25✔
2
import { readFile } from 'node:fs/promises';
25✔
3
import type { LeafDirective } from 'mdast-util-directive';
25✔
4
import type { VFile } from 'vfile';
25✔
5
import iconv from 'iconv-lite';
25✔
6
import type { IDirectiveAttributes } from './options.js';
25✔
7

25✔
8
/**
25✔
9
 * Class for code file content
25✔
10
 *
25✔
11
 * @param file - Current markdown file
25✔
12
 * @param node - `::include-code` directive Node
25✔
13
 * @param attributes - `::include-code` attributes
25✔
14
 * @param content - file content
25✔
15
 *
25✔
16
 * @internal
25✔
17
 */
25✔
18
export class CodeFileContent {
25✔
19

25✔
20
  protected readonly file: VFile;
25✔
21
  protected readonly node: LeafDirective;
23✔
22
  protected readonly attributes: IDirectiveAttributes;
23✔
23
  protected fileContent: Buffer<ArrayBuffer>;
23✔
24
  protected _content: string;
25✔
25

25✔
26
  public constructor(
25✔
27
    file: VFile,
23✔
28
    node: LeafDirective,
23✔
29
    attributes: IDirectiveAttributes,
23✔
30
    content: Buffer<ArrayBuffer>
23✔
31
  ) {
23✔
32
    this.file = file;
23✔
33
    this.node = node;
23✔
34
    this.attributes = attributes;
23✔
35
    this.fileContent = content;
23✔
36
    this._content = '';
23✔
37
  }
23✔
38

25✔
39
  public static readFileSync(
25✔
40
    file: VFile,
6✔
41
    node: LeafDirective,
6✔
42
    attributes: IDirectiveAttributes,
6✔
43
    path: string
6✔
44
  ): CodeFileContent {
6✔
45
    const self = new CodeFileContent(
6✔
46
      file, node, attributes,
6✔
47
      Buffer.alloc(0)
6✔
48
    );
6✔
49
    try {
6✔
50
      self.fileContent = readFileSync(path);
6✔
51
    } catch (error) {
6✔
52
      self.catchFileError(error);
6✔
53
    };
6✔
54
    return self;
6✔
55
  }
6✔
56

25✔
57
  public static async readFile(
25✔
58
    file: VFile,
17✔
59
    node: LeafDirective,
17✔
60
    attributes: IDirectiveAttributes,
17✔
61
    path: string
17✔
62
  ): Promise<CodeFileContent> {
17✔
63
    const self = new CodeFileContent(
17✔
64
      file, node, attributes,
17✔
65
      Buffer.alloc(0)
17✔
66
    );
17✔
67
    try {
17✔
68
      self.fileContent = await readFile(path);
17✔
69
    } catch (error) {
17✔
70
      self.catchFileError(error);
17✔
71
    };
17✔
72
    return self;
17✔
73
  }
17✔
74

25✔
75
  public get content(): string {
25✔
76
    return this._content;
19✔
77
  }
19✔
78

25✔
79
  public toString(): string {
25✔
UNCOV
80
    return this.content;
×
UNCOV
81
  }
×
82

25✔
83
  public decode(): this {
25✔
84
    this._content = iconv.decode(this.fileContent, this.attributes.encoding);
19✔
85
    return this;
19✔
86
  }
19✔
87

25✔
88
  public normalizeEOL(): this {
25✔
89
    this._content = this._content.replaceAll(/\r?\n/g, '\n');
19✔
90
    return this;
19✔
91
  }
19✔
92

25✔
93
  public trimFinalNewline(): this {
25✔
94
    if (this.attributes.trimFinalNewline) {
19✔
95
      this._content = this._content.replace(/\n$/, '');
19✔
96
    }
19✔
97
    return this;
19✔
98
  }
19✔
99

25✔
100
  public selectLinesRange(): this {
25✔
101
    const contentLines = this._content.split('\n');
19✔
102
    this._content = contentLines
19✔
103
      .slice(
19✔
104
        (this.attributes.fromLine ?? 1) - 1,
19✔
105
        this.attributes.toLine ?? contentLines.length
19✔
106
      )
19✔
107
      .join('\n');
19✔
108
    return this;
19✔
109
  }
19✔
110

25✔
111
  public replaceTabs(): this {
25✔
112
    if (this.attributes.tabWidth !== undefined) {
19✔
113
      const w = this.attributes.tabWidth;
19✔
114
      this._content = this._content.replaceAll(
19✔
115
        new RegExp(
19✔
116
          String.raw`(?<=^( {${w.toString()}}| {0,${(w - 1).toString()}}\t)*) {0,${(w - 1).toString()}}\t`,
19✔
117
          'gm'
19✔
118
        ),
19✔
119
        ' '.repeat(w)
19✔
120
      );
19✔
121
    }
19✔
122
    return this;
19✔
123
  }
19✔
124

25✔
125
  public normalizeIndent(): this {
25✔
126
    if (
19✔
127
      this.attributes.trimExtraIndent &&
19✔
128
      (this.attributes.tabWidth !== undefined)
19✔
129
    ) {
19✔
130
      // eslint-disable-next-line sonarjs/slow-regex
19✔
131
      const indentsWidth = /^\s*(?=\S)/gmd
19✔
132
        .exec(this._content)
19✔
133
        ?.indices
19✔
134
        ?.map(
19✔
135
          (
19✔
136
            indentPosition?: [number, number]
2✔
137
          ): number =>
2✔
138
            indentPosition ? indentPosition[1] - indentPosition[0] : 0
2!
139
        );
19✔
140
      const extraIndentWidth = indentsWidth ?
19✔
141
        // eslint-disable-next-line unicorn/no-null
19✔
142
        Math.min.apply(null, indentsWidth) : 0;
19!
143
      if (extraIndentWidth) {
19✔
144
        this._content = this._content.replaceAll(
1✔
145
          new RegExp(String.raw`^ {${extraIndentWidth.toString()}}`, 'gm'),
1✔
146
          ''
1✔
147
        );
1✔
148
      }
1✔
149
    }
19✔
150
    return this;
19✔
151
  }
19✔
152

25✔
153
  protected catchFileError(error: any): void {
25✔
154
    if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
4✔
155
      const errorMessage = `::include-code, file(s) "${this.attributes.file}" not found`;
4✔
156
      if (this.attributes.optional) {
4✔
157
        throw this.file.info(errorMessage, this.node);
2✔
158
      } else {
2✔
159
        this.file.fail(errorMessage, this.node);
2✔
160
      }
2✔
161
    } else {
4!
UNCOV
162
      throw error;
×
UNCOV
163
    }
×
164
  }
4✔
165

25✔
166
}
25✔
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