-
Notifications
You must be signed in to change notification settings - Fork 61.6k
/
Copy pathutils.js
142 lines (129 loc) · 4.63 KB
/
utils.js
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import { addError, filterTokens } from 'markdownlint-rule-helpers'
import matter from 'gray-matter'
// Adds an error object with details conditionally via the onError callback
export function addFixErrorDetail(onError, lineNumber, expected, actual, range, fixInfo) {
addError(onError, lineNumber, `Expected: ${expected}`, ` Actual: ${actual}`, range, fixInfo)
}
export function forEachInlineChild(params, type, handler) {
filterTokens(params, 'inline', (token) => {
for (const child of token.children.filter((c) => c.type === type)) {
handler(child, token)
}
})
}
export function getRange(line, content) {
if (content.length === 0) {
// This function assumes that the content is something. If it's an
// empty string it can never produce a valid range.
throw new Error('invalid content (empty)')
}
const startColumnIndex = line.indexOf(content)
return startColumnIndex !== -1 ? [startColumnIndex + 1, content.length] : null
}
export function isStringQuoted(text) {
// String starts with either a single or double quote
// ends with either a single or double quote
// and optionally ends with a question mark or exclamation point
// because that punctuation can exist outside of the quoted string
return /^['"].*['"][?!]?$/.test(text)
}
export function isStringPunctuated(text) {
// String ends with punctuation of either
// . ? ! and optionally ends with single
// or double quotes. This also allows
// for single or double quotes before
// the punctuation.
return /^.*[.?!]['"]?$/.test(text)
}
export function doesStringEndWithPeriod(text) {
// String ends with punctuation of either
// . ? ! and optionally ends with single
// or double quotes. This also allows
// for single or double quotes before
// the punctuation.
return /^.*\.['"]?$/.test(text)
}
export function quotePrecedesLinkOpen(text) {
if (!text) return false
return text.endsWith('"') || text.endsWith("'")
}
// Filters a list of tokens by token type only when they match
// a specific token type order.
// For example, if a list of tokens contains:
//
// [
// { type: 'inline'},
// { type: 'list_item_close'},
// { type: 'list_item_open'},
// { type: 'paragraph_open'},
// { type: 'inline'},
// { type: 'paragraph_close'},
// ]
//
// And if the `tokenOrder` being looked for is:
//
// [
// 'list_item_open',
// 'paragraph_open',
// 'inline'
// ]
//
// Then the return value would be the items that match that sequence:
// Index 2-4:
// [
// { type: 'inline'}, <-- Index 0 - NOT INCLUDED
// { type: 'list_item_close'}, <-- Index 1 - NOT INCLUDED
// { type: 'list_item_open'}, <-- Index 2 - INCLUDED
// { type: 'paragraph_open'}, <-- Index 3 - INCLUDED
// { type: 'inline'}, <-- Index 4 - INCLUDED
// { type: 'paragraph_close'}, <-- Index 5 - NOT INCLUDED
// ]
//
export function filterTokensByOrder(tokens, tokenOrder) {
const matches = []
// Get a list of token indexes that match the
// first token (root) in the tokenOrder array
const tokenRootIndexes = []
const firstTokenOrderType = tokenOrder[0]
tokens.forEach((token, index) => {
if (token.type === firstTokenOrderType) {
tokenRootIndexes.push(index)
}
})
// Loop through each root token index and check if
// the order matches the tokenOrder array
for (const tokenRootIndex of tokenRootIndexes) {
for (let i = 1; i < tokenOrder.length; i++) {
if (tokens[tokenRootIndex + i].type !== tokenOrder[i]) {
// This tokenRootIndex was a possible start,
// but doesn't match the tokenOrder perfectly, so break out
// of the inner loop before it reaches the end.
break
}
if (i === tokenOrder.length - 1) {
matches.push(...tokens.slice(tokenRootIndex, tokenRootIndex + i + 1))
}
}
}
return matches
}
export const docsDomains = ['docs.github.com', 'help.github.com', 'developer.github.com']
// Lines is an array of strings read from a
// Markdown file a split around new lines.
// This is the format we get from Markdownlint.
// Returns null if the lines do not contain
// frontmatter properties.
export function getFrontmatter(lines) {
const fmString = lines.join('\n')
const { data } = matter(fmString)
// If there is no frontmatter or the frontmatter contains
// no keys, matter will return an empty object.
if (Object.keys(data).length === 0) return null
return data
}
export function getFrontmatterLines(lines) {
const indexStart = lines.indexOf('---')
if (indexStart === -1) return []
const indexEnd = lines.indexOf('---', indexStart + 1)
return lines.slice(indexStart, indexEnd + 1)
}