forked from adamlaska/browser-compat-data
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.js
More file actions
119 lines (107 loc) · 2.72 KB
/
utils.js
File metadata and controls
119 lines (107 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
'use strict';
const { platform } = require('os');
const chalk = require('chalk');
/** @type {{readonly [char: string]: string}} */
const INVISIBLES_MAP = Object.freeze(
Object.assign(Object.create(null), {
'\0': '\\0', // ␀ (0x00)
'\b': '\\b', // ␈ (0x08)
'\t': '\\t', // ␉ (0x09)
'\n': '\\n', // ␊ (0x0A)
'\v': '\\v', // ␋ (0x0B)
'\f': '\\f', // ␌ (0x0C)
'\r': '\\r', // ␍ (0x0D)
}),
);
const INVISIBLES_REGEXP = /[\0\x08-\x0D]/g;
/** Used to check if the process is running in a CI environment. */
const IS_CI = process.env.CI && String(process.env.CI).toLowerCase() === 'true';
/** Determines if the OS is Windows */
const IS_WINDOWS = platform() === 'win32';
/**
* Escapes common invisible characters.
*
* @param {string} str
*/
function escapeInvisibles(str) {
// This should now be O(n) instead of O(n*m),
// where n = string length; m = invisible characters
return INVISIBLES_REGEXP[Symbol.replace](str, char => {
return INVISIBLES_MAP[char] || char;
});
}
/**
* Gets the row and column matching the index in a string.
*
* @param {string} str
* @param {number} index
* @return {[number, number] | [null, null]}
*/
function indexToPosRaw(str, index) {
let line = 1,
col = 1;
let prevChar = null;
if (
typeof str !== 'string' ||
typeof index !== 'number' ||
index > str.length
) {
return [null, null];
}
for (let i = 0; i < index; i++) {
const char = str[i];
switch (char) {
case '\n':
if (prevChar === '\r') break;
case '\r':
line++;
col = 1;
break;
case '\t':
// Use JSON `tab_size` value from `.editorconfig`
col += 2;
break;
default:
col++;
break;
}
prevChar = char;
}
return [line, col];
}
/**
* Gets the row and column matching the index in a string and formats it.
*
* @param {string} str
* @param {number} index
* @return {string} The line and column in the form of: `"(Ln <ln>, Col <col>)"`
*/
function indexToPos(str, index) {
const [line, col] = indexToPosRaw(str, index);
return `(Ln ${line}, Col ${col})`;
}
/**
* @param {string} actual
* @param {string} expected
* @return {string}
*/
function jsonDiff(actual, expected) {
const actualLines = actual.split(/\n/);
const expectedLines = expected.split(/\n/);
for (let i = 0; i < actualLines.length; i++) {
if (actualLines[i] !== expectedLines[i]) {
return chalk`{bold line #${i + 1}}
{yellow Actual: {bold ${escapeInvisibles(actualLines[i])}}}
{green Expected: {bold ${escapeInvisibles(expectedLines[i])}}}`;
}
}
}
module.exports = {
INVISIBLES_MAP,
IS_CI,
IS_WINDOWS,
escapeInvisibles,
indexToPosRaw,
indexToPos,
jsonDiff,
};