Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OS-agnostic handling of end-of-line characters #524

Merged
merged 2 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const jestConfig = {
preset: 'ts-jest/presets/default-esm',
testEnvironment: 'node',
testMatch: ['<rootDir>/test/**/*-test.ts'],
setupFiles: ['<rootDir>/test/jest.setup.cjs'],
transform: {
'^.+\\.tsx?$': ['ts-jest', { useESM: true }],
},
Expand Down
3 changes: 2 additions & 1 deletion lib/config-list.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EOL } from 'node:os';
import {
BEGIN_CONFIG_LIST_MARKER,
END_CONFIG_LIST_MARKER,
Expand Down Expand Up @@ -111,5 +112,5 @@ export function updateConfigsList(
ignoreConfig
);

return `${preList}${BEGIN_CONFIG_LIST_MARKER}\n\n${list}\n\n${END_CONFIG_LIST_MARKER}${postList}`;
return `${preList}${BEGIN_CONFIG_LIST_MARKER}${EOL}${EOL}${list}${EOL}${EOL}${END_CONFIG_LIST_MARKER}${postList}`;
}
11 changes: 7 additions & 4 deletions lib/generator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EOL } from 'node:os';
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname, join, relative, resolve } from 'node:path';
import { getAllNamedOptions, hasOptions } from './rule-options.js';
Expand Down Expand Up @@ -168,16 +169,18 @@ export async function generate(path: string, options?: GenerateOptions) {
// The rule doc header will be added later.
let newRuleDocContents = [
ruleDocSectionInclude.length > 0
? ruleDocSectionInclude.map((title) => `## ${title}`).join('\n\n')
? ruleDocSectionInclude
.map((title) => `## ${title}`)
.join(`${EOL}${EOL}`)
: undefined,
ruleHasOptions
? `## Options\n\n${BEGIN_RULE_OPTIONS_LIST_MARKER}\n${END_RULE_OPTIONS_LIST_MARKER}`
? `## Options${EOL}${EOL}${BEGIN_RULE_OPTIONS_LIST_MARKER}${EOL}${END_RULE_OPTIONS_LIST_MARKER}`
: undefined,
]
.filter((section) => section !== undefined)
.join('\n\n');
.join(`${EOL}${EOL}`);
if (newRuleDocContents !== '') {
newRuleDocContents = `\n${newRuleDocContents}\n`;
newRuleDocContents = `${EOL}${newRuleDocContents}${EOL}`;
}

mkdirSync(dirname(pathToDoc), { recursive: true });
Expand Down
16 changes: 10 additions & 6 deletions lib/markdown.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { EOL } from 'node:os';

// General helpers for dealing with markdown files / content.

/**
Expand All @@ -12,7 +14,7 @@ export function replaceOrCreateHeader(
newHeader: string,
marker: string
) {
const lines = markdown.split('\n');
const lines = markdown.split(EOL);

const titleLineIndex = lines.findIndex((line) => line.startsWith('# '));
const markerLineIndex = lines.indexOf(marker);
Expand All @@ -22,16 +24,18 @@ export function replaceOrCreateHeader(
// Any YAML front matter or anything else above the title should be kept as-is ahead of the new header.
const preHeader = lines
.slice(0, Math.max(titleLineIndex, dashesLineIndex2 + 1))
.join('\n');
.join(EOL);

// Anything after the marker comment, title, or YAML front matter should be kept as-is after the new header.
const postHeader = lines
.slice(
Math.max(markerLineIndex + 1, titleLineIndex + 1, dashesLineIndex2 + 1)
)
.join('\n');
.join(EOL);

return `${preHeader ? `${preHeader}\n` : ''}${newHeader}\n${postHeader}`;
return `${
preHeader ? `${preHeader}${EOL}` : ''
}${newHeader}${EOL}${postHeader}`;
}

/**
Expand All @@ -42,7 +46,7 @@ export function findSectionHeader(
str: string
): string | undefined {
// Get all the matching strings.
const regexp = new RegExp(`## .*${str}.*\n`, 'giu');
const regexp = new RegExp(`## .*${str}.*${EOL}`, 'giu');
const sectionPotentialMatches = [...markdown.matchAll(regexp)].map(
(match) => match[0]
);
Expand All @@ -64,7 +68,7 @@ export function findSectionHeader(
}

export function findFinalHeaderLevel(str: string) {
const lines = str.split('\n');
const lines = str.split(EOL);
const finalHeader = lines.reverse().find((line) => line.match('^(#+) .+$'));
return finalHeader ? finalHeader.indexOf(' ') : undefined;
}
Expand Down
3 changes: 2 additions & 1 deletion lib/rule-doc-notices.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EOL } from 'node:os';
import { END_RULE_HEADER_MARKER } from './comment-markers.js';
import {
EMOJI_DEPRECATED,
Expand Down Expand Up @@ -523,5 +524,5 @@ export function generateRuleHeaderLines(
),
'',
END_RULE_HEADER_MARKER,
].join('\n');
].join(EOL);
}
3 changes: 2 additions & 1 deletion lib/rule-list-legend.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EOL } from 'node:os';
import {
EMOJI_DEPRECATED,
EMOJI_FIXABLE,
Expand Down Expand Up @@ -287,5 +288,5 @@ export function generateLegend(
);
}

return legends.join('\\\n'); // Back slash ensures these end up displayed on separate lines.
return legends.join(`\\${EOL}`); // Back slash ensures these end up displayed on separate lines.
}
7 changes: 4 additions & 3 deletions lib/rule-list.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EOL } from 'node:os';
import {
BEGIN_RULE_LIST_MARKER,
END_RULE_LIST_MARKER,
Expand Down Expand Up @@ -288,7 +289,7 @@ function generateRuleListMarkdownForRulesAndHeaders(
);
}

return parts.join('\n\n');
return parts.join(`${EOL}${EOL}`);
}

/**
Expand Down Expand Up @@ -546,7 +547,7 @@ export function updateRulesList(
urlRuleDoc
);

const newContent = `${legend ? `${legend}\n\n` : ''}${list}`;
const newContent = `${legend ? `${legend}${EOL}${EOL}` : ''}${list}`;

return `${preList}${BEGIN_RULE_LIST_MARKER}\n\n${newContent}\n\n${END_RULE_LIST_MARKER}${postList}`;
return `${preList}${BEGIN_RULE_LIST_MARKER}${EOL}${EOL}${newContent}${EOL}${EOL}${END_RULE_LIST_MARKER}${postList}`;
}
3 changes: 2 additions & 1 deletion lib/rule-options-list.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EOL } from 'node:os';
import {
BEGIN_RULE_OPTIONS_LIST_MARKER,
END_RULE_OPTIONS_LIST_MARKER,
Expand Down Expand Up @@ -159,5 +160,5 @@ export function updateRuleOptionsList(
// New rule options list.
const list = generateRuleOptionsListMarkdown(rule);

return `${preList}${BEGIN_RULE_OPTIONS_LIST_MARKER}\n\n${list}\n\n${END_RULE_OPTIONS_LIST_MARKER}${postList}`;
return `${preList}${BEGIN_RULE_OPTIONS_LIST_MARKER}${EOL}${EOL}${list}${EOL}${EOL}${END_RULE_OPTIONS_LIST_MARKER}${postList}`;
}
4 changes: 3 additions & 1 deletion lib/string.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { EOL } from 'node:os';

export function toSentenceCase(str: string) {
return str.replace(/^\w/u, function (txt) {
return txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase();
Expand All @@ -20,7 +22,7 @@ export function capitalizeOnlyFirstLetter(str: string) {
}

function sanitizeMarkdownTableCell(text: string): string {
return text.replace(/\|/gu, '\\|').replace(/\n/gu, '<br/>');
return text.replace(/\|/gu, '\\|').replace(new RegExp(EOL, 'gu'), '<br/>');
Dismissed Show dismissed Hide dismissed
}

export function sanitizeMarkdownTable(
Expand Down
6 changes: 6 additions & 0 deletions test/jest.setup.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const os = require('node:os');
const sinon = require('sinon');

module.exports = function () {
sinon.stub(os, 'EOL').value('\n'); // Stub os.EOL to always be '\n' for testing/snapshot purposes.
};
Loading