/
plugins.js
104 lines (90 loc) 路 2.71 KB
/
plugins.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
import {
assertString,
assertFunction,
assertObject,
type ValidatorSet,
type Validator,
} from "./option-assertions";
// Note: The casts here are just meant to be static assertions to make sure
// that the assertion functions actually assert that the value's type matches
// the declared types.
const VALIDATORS: ValidatorSet = {
name: (assertString: Validator<$PropertyType<PluginObject, "name">>),
manipulateOptions: (assertFunction: Validator<
$PropertyType<PluginObject, "manipulateOptions">,
>),
pre: (assertFunction: Validator<$PropertyType<PluginObject, "pre">>),
post: (assertFunction: Validator<$PropertyType<PluginObject, "post">>),
inherits: (assertFunction: Validator<
$PropertyType<PluginObject, "inherits">,
>),
visitor: (assertVisitorMap: Validator<
$PropertyType<PluginObject, "visitor">,
>),
parserOverride: (assertFunction: Validator<
$PropertyType<PluginObject, "parserOverride">,
>),
generatorOverride: (assertFunction: Validator<
$PropertyType<PluginObject, "generatorOverride">,
>),
};
function assertVisitorMap(key: string, value: mixed): VisitorMap {
const obj = assertObject(key, value);
if (obj) {
Object.keys(obj).forEach(prop => assertVisitorHandler(prop, obj[prop]));
if (obj.enter || obj.exit) {
throw new Error(
`.${key} cannot contain catch-all "enter" or "exit" handlers. Please target individual nodes.`,
);
}
}
return (obj: any);
}
function assertVisitorHandler(
key: string,
value: mixed,
): VisitorHandler | void {
if (value && typeof value === "object") {
Object.keys(value).forEach(handler => {
if (handler !== "enter" && handler !== "exit") {
throw new Error(
`.visitor["${key}"] may only have .enter and/or .exit handlers.`,
);
}
});
} else if (typeof value !== "function") {
throw new Error(`.visitor["${key}"] must be a function`);
}
return (value: any);
}
type VisitorHandler = Function | { enter?: Function, exit?: Function };
export type VisitorMap = {
[string]: VisitorHandler,
};
export type PluginObject = {
name?: string,
manipulateOptions?: Function,
pre?: Function,
post?: Function,
inherits?: Function,
visitor?: VisitorMap,
parserOverride?: Function,
generatorOverride?: Function,
};
export function validatePluginObject(obj: {}): PluginObject {
const rootPath: RootPath = {
type: "root",
source: "plugin",
};
Object.keys(obj).forEach(key => {
const validator = VALIDATORS[key];
const optLoc = {
type: "option",
name: key,
parent: rootPath,
};
if (validator) validator(optLoc, obj[key]);
else throw new Error(`.${key} is not a valid Plugin property`);
});
return (obj: any);
}