-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
60 lines (53 loc) · 2.25 KB
/
index.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
'use strict'
const {keyword} = require('esutils')
// Follow Babel's implementation:
// <https://github.com/babel/babel/blob/add96d626d98133e26f62ec4c2aeee655bed069a/packages/babel-types/src/validators.js#L153:L164>
function isValidIdentifier (name) {
return !keyword.isReservedWordES6(name, true) && keyword.isIdentifierNameES6(name)
}
// Rewrite the name until it forms a valid identifier.
module.exports = function identifierfy (name, {prefixInvalidIdentifiers = true, prefixReservedWords = true} = {}) {
// Start with a valid character. This way if the first character in the name
// is not allowed to be used as the first character it can be prefixed with
// an underscore, without having to be dropped. The same goes for if the name
// is a reserved word.
let intermediate = '_'
// Flag whether the previous character was invalid (and thus dropped).
let prevWasInvalid = false
// Use for/of to iterate over the code points. This way surrogate pairs can
// be avoided.
for (let char of name) {
// Try to uppercase the immediately following (not all characters have an
// case equivalent though). Ignore if the dropped character was at the front
// of the name.
if (prevWasInvalid && intermediate !== '_') {
char = char.toUpperCase()
}
// Only include characters if the name remains valid.
if (isValidIdentifier(intermediate + char)) {
intermediate += char
prevWasInvalid = false
} else {
prevWasInvalid = true
}
}
// Return `null` if no characters from the original name survive the process.
if (intermediate === '_') return null
// If the name is valid without the underscore prefix return it as such,
// otherwise retain it, unless directed otherwise.
const withoutPrefix = intermediate.slice(1)
if (isValidIdentifier(withoutPrefix)) {
return withoutPrefix
} else if (prefixInvalidIdentifiers && prefixReservedWords) {
return intermediate
} else {
const isIdentifierName = keyword.isIdentifierNameES6(withoutPrefix)
const isReservedWord = keyword.isReservedWordES6(withoutPrefix, true)
if ((!isIdentifierName && !prefixInvalidIdentifiers) ||
(isReservedWord && !prefixReservedWords)) {
return withoutPrefix
} else {
return intermediate
}
}
}