-
Notifications
You must be signed in to change notification settings - Fork 264
Expand file tree
/
Copy pathgitattributes.ts
More file actions
72 lines (62 loc) · 2.41 KB
/
gitattributes.ts
File metadata and controls
72 lines (62 loc) · 2.41 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
import micromatch from 'micromatch';
// GitAttributes holds parsed .gitattributes rules for overriding language detection.
export interface GitAttributes {
rules: GitAttributeRule[];
}
interface GitAttributeRule {
pattern: string;
attrs: Record<string, string>;
}
// parseGitAttributes parses the content of a .gitattributes file.
// Each non-comment, non-empty line has the form: pattern attr1 attr2=value ...
// Attributes can be:
// - "linguist-vendored" (set/true), "-linguist-vendored" (unset/false)
// - "linguist-language=Go"
// - etc.
export function parseGitAttributes(content: string): GitAttributes {
const rules: GitAttributeRule[] = [];
for (const raw of content.split('\n')) {
const line = raw.trim();
if (line === '' || line.startsWith('#')) {
continue;
}
const fields = line.split(/\s+/);
if (fields.length < 2) {
continue;
}
const pattern = fields[0];
const attrs: Record<string, string> = {};
for (const field of fields.slice(1)) {
if (field.startsWith('!')) {
// !attr means unspecified (reset to default)
attrs[field.slice(1)] = 'unspecified';
} else if (field.startsWith('-')) {
// -attr means unset (false)
attrs[field.slice(1)] = 'false';
} else {
const eqIdx = field.indexOf('=');
if (eqIdx !== -1) {
// attr=value
attrs[field.slice(0, eqIdx)] = field.slice(eqIdx + 1);
} else {
// attr alone means set (true)
attrs[field] = 'true';
}
}
}
rules.push({ pattern, attrs });
}
return { rules };
}
// resolveLanguageFromGitAttributes returns the linguist-language override for
// the given file path based on the parsed .gitattributes rules, or undefined
// if no rule matches. Last matching rule wins, consistent with gitattributes semantics.
export function resolveLanguageFromGitAttributes(filePath: string, gitAttributes: GitAttributes): string | undefined {
let language: string | undefined;
for (const rule of gitAttributes.rules) {
if (micromatch.isMatch(filePath, rule.pattern) && rule.attrs['linguist-language']) {
language = rule.attrs['linguist-language'];
}
}
return language;
}