-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathconfig.js
133 lines (124 loc) · 3.9 KB
/
config.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
const defaults = require("markdown-it/lib/presets/default")
const Hooks = require("./hooks")
const Renderer = require("./renderer")
module.exports = class Config {
constructor() {
this.markdown = defaults
this.markdown.options.html = true
this.markdown.options.langPrefix = "lang-"
this.Renderer = Renderer
this.commands = {}
this.infoStringCommands = {}
this.infoStringParsers = []
this.loadDefaultCommands()
this.datatypes = {
regexp: "(\\/(?:[^\\/\\\\]*(?:\\\\.[^\\/\\\\]*)*)\\/[gmiuy]*)",
string: '"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"',
number: "(-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)",
boolean: "(true|false)",
null: "(null)",
range: "(\\d+\\.\\.\\d+|\\d+:\\d+\\.\\.\\d+|\\d+)"
}
}
get hooks() {
this._hooks = this._hooks || new Hooks()
return this._hooks
}
loadDefaultCommands() {
this.commands[":"] = function(pi) {
pi.renderer.config.parseInfoString(pi.content.trim(), pi)
}
}
use(plugin) {
plugin.call(this, this)
}
addInfoStringParser(regexp, func) {
this.infoStringParsers.push({ regexp: regexp, func: func })
}
addInfoStringCommand(name, options = {}, func) {
if (typeof options === "function") {
func = options
options = {}
}
let regexpString = `^\\+${name}`
let parameters
if (options.types) {
parameters =
"(" + options.types.map(type => this.datatypes[type]).join("|") + ")"
if (options.multiple) {
parameters += `((?:,${parameters})*)`
}
regexpString += "=(" + parameters + ")"
}
const regexp = new RegExp(regexpString, "g")
const getArguments = argumentsString => {
const regexp = new RegExp(parameters)
const currentArgument = argumentsString.match(regexp)[1]
const moreArguments = argumentsString.substr(currentArgument.length + 1)
const argumentsArray = []
options.types.forEach(type => {
if (currentArgument.match(new RegExp(`^${this.datatypes[type]}$`))) {
switch (type) {
case "regexp":
argumentsArray.push(
new RegExp(
...currentArgument.match(/^\/(.*?)\/([gmiuy]*)$/).slice(1)
)
)
break
case "range":
argumentsArray.push(currentArgument)
break
default:
argumentsArray.push(JSON.parse(currentArgument))
}
}
})
if (moreArguments) {
argumentsArray.push(...getArguments(moreArguments))
}
return argumentsArray
}
this.infoStringParsers.push({
regexp: regexp,
func: function(...matches) {
let argumentsString = matches[1]
let argumentsArray = []
if (options.types) {
argumentsArray.push(...getArguments(argumentsString))
}
func.call(this, ...argumentsArray)
}
})
}
parseInfoString(infoString, target) {
if (!infoString) return
let keepGoing = true
while (infoString.length && keepGoing) {
keepGoing = false
infoString = infoString.trimLeft()
let infoStringBefore = infoString
this.infoStringParsers.forEach(parser => {
infoString = infoString.replace(parser.regexp, (...matches) => {
const position = matches[matches.length - 2]
if (position === 0) {
keepGoing = true
parser.func.apply(target, matches)
return ""
} else {
return matches[0]
}
})
})
if (infoString === infoStringBefore) {
const spacePosition = infoString.indexOf(" ")
if (spacePosition !== -1) {
const unknown = infoString.substr(0, spacePosition)
console.warn(`Unknown part in info string found: ${unknown}.`)
infoString = infoString.substr(infoString.indexOf(" ") + 1)
keepGoing = true
}
}
}
}
}