-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathvalidators.ts
More file actions
124 lines (109 loc) · 2.96 KB
/
Copy pathvalidators.ts
File metadata and controls
124 lines (109 loc) · 2.96 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
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
import {
CODE,
STATE,
Parser,
type StateDefinition,
type Meta,
} from "../internal";
import {
shouldTerminateConciseAttrValue,
shouldTerminateHtmlAttrValue,
} from "../states";
const ROOT_STATE: StateDefinition = {
name: "ROOT",
enter() {
return ROOT_RANGE;
},
exit() {},
char() {},
eol() {},
eof() {},
return() {},
};
const ROOT_RANGE = {
state: ROOT_STATE,
parent: undefined as unknown as Meta,
start: 0,
end: 0,
};
export enum Validity {
invalid,
valid,
enclosed,
}
export function isValidStatement(code: string): Validity {
return isValid(code, true, prepareStatement);
}
function prepareStatement(expr: STATE.ExpressionMeta) {
expr.operators = true;
expr.terminatedByEOL = true;
expr.consumeIndentedContent = true;
}
export function isValidScriptlet(code: string): Validity {
return isValid(code, true, prepareScriptlet);
}
function prepareScriptlet(expr: STATE.ExpressionMeta) {
expr.operators = true;
expr.terminatedByEOL = true;
}
export function isValidAttrValue(code: string, concise: boolean): Validity {
return isValid(code, concise, prepareAttrValue);
}
function prepareAttrValue(expr: STATE.ExpressionMeta, concise: boolean) {
expr.operators = true;
expr.terminatedByWhitespace = true;
expr.shouldTerminate = concise
? shouldTerminateConciseAttrValue
: shouldTerminateHtmlAttrValue;
}
function isValid(
data: string,
concise: boolean,
prepare: (expr: STATE.ExpressionMeta, concise: boolean) => void,
): Validity {
const parser = new Parser({});
const maxPos = (parser.maxPos = data.length);
parser.pos = 0;
parser.data = data;
parser.indent = "";
parser.forward = 1;
parser.textPos = -1;
parser.isConcise = concise;
parser.beginMixedMode = parser.endingMixedModeAtEOL = false;
parser.lines = parser.activeTag = parser.activeAttr = undefined;
parser.activeState = ROOT_STATE;
parser.activeRange = ROOT_RANGE;
const expr = parser.enterState(STATE.EXPRESSION);
let isEnclosed = true;
prepare(expr, concise);
while (parser.pos < maxPos) {
const code = data.charCodeAt(parser.pos);
if (code === CODE.NEWLINE) {
if (isEnclosed && !expr.groupStack.length) isEnclosed = false;
parser.forward = 1;
parser.activeState.eol.call(parser, 1, parser.activeRange);
} else if (
code === CODE.CARRIAGE_RETURN &&
data.charCodeAt(parser.pos + 1) === CODE.NEWLINE
) {
if (isEnclosed && !expr.groupStack.length) isEnclosed = false;
parser.forward = 2;
parser.activeState.eol.call(parser, 2, parser.activeRange);
} else {
parser.forward = 1;
parser.activeState.char.call(parser, code, parser.activeRange);
}
if (parser.activeRange === ROOT_RANGE) {
return Validity.invalid;
}
parser.pos += parser.forward;
}
if (
parser.pos === maxPos &&
parser.activeRange === expr &&
!expr.groupStack.length
) {
return isEnclosed ? Validity.enclosed : Validity.valid;
}
return Validity.invalid;
}