@nethru/ui 1.0.77 → 1.0.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Section.js +6 -3
- package/dist/{Editor.js → editor/Editor.js} +17 -6
- package/dist/editor/nScript.js +274 -0
- package/dist/editor/nScriptKeywords.js +2925 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/Section.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Paper } from "@mui/material";
|
|
2
|
+
import { forwardRef } from "react";
|
|
2
3
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
|
|
4
|
+
const Section = /*#__PURE__*/forwardRef(({
|
|
4
5
|
children,
|
|
5
6
|
sx,
|
|
6
7
|
...props
|
|
7
|
-
}) {
|
|
8
|
+
}, ref) => {
|
|
8
9
|
return /*#__PURE__*/_jsx(Paper, {
|
|
10
|
+
ref: ref,
|
|
9
11
|
variant: "outlined",
|
|
10
12
|
square: false,
|
|
11
13
|
sx: {
|
|
@@ -16,4 +18,5 @@ export default function Section({
|
|
|
16
18
|
...props,
|
|
17
19
|
children: children
|
|
18
20
|
});
|
|
19
|
-
}
|
|
21
|
+
});
|
|
22
|
+
export default Section;
|
|
@@ -3,6 +3,7 @@ import { Box, Typography } from "@mui/material";
|
|
|
3
3
|
import CodeMirror from '@uiw/react-codemirror';
|
|
4
4
|
import { javascript } from '@codemirror/lang-javascript';
|
|
5
5
|
import { json } from '@codemirror/lang-json';
|
|
6
|
+
import { nScript } from './nScript';
|
|
6
7
|
import { Decoration, EditorView } from "@codemirror/view";
|
|
7
8
|
import { RegExpCursor, SearchCursor } from '@codemirror/search';
|
|
8
9
|
import { StateEffect, StateField } from "@codemirror/state";
|
|
@@ -15,7 +16,7 @@ export default function Editor({
|
|
|
15
16
|
helperText,
|
|
16
17
|
basicSetup,
|
|
17
18
|
extensions = [],
|
|
18
|
-
|
|
19
|
+
format = 'javascript',
|
|
19
20
|
keyword,
|
|
20
21
|
isRegExp = false,
|
|
21
22
|
autoScrollToBottom = false,
|
|
@@ -78,10 +79,20 @@ export default function Editor({
|
|
|
78
79
|
extension: extension
|
|
79
80
|
};
|
|
80
81
|
}, []);
|
|
82
|
+
const languageExtension = useMemo(() => {
|
|
83
|
+
switch (format) {
|
|
84
|
+
case 'json':
|
|
85
|
+
return json();
|
|
86
|
+
case 'nscript':
|
|
87
|
+
return nScript;
|
|
88
|
+
default:
|
|
89
|
+
return javascript({
|
|
90
|
+
jsx: true
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}, [format]);
|
|
81
94
|
const extensionList = useMemo(() => {
|
|
82
|
-
const result = [
|
|
83
|
-
jsx: true
|
|
84
|
-
}), EditorView.lineWrapping, highlight.extension];
|
|
95
|
+
const result = [languageExtension, EditorView.lineWrapping, highlight.extension];
|
|
85
96
|
if (onScroll) {
|
|
86
97
|
result.push(EditorView.domEventHandlers({
|
|
87
98
|
scroll(event, view) {
|
|
@@ -92,7 +103,7 @@ export default function Editor({
|
|
|
92
103
|
}
|
|
93
104
|
result.push(...extensions);
|
|
94
105
|
return result;
|
|
95
|
-
}, [
|
|
106
|
+
}, [languageExtension, highlight.extension, extensions, onScroll]);
|
|
96
107
|
const handleUpdate = viewUpdate => {
|
|
97
108
|
setFocused(viewUpdate.view.hasFocus);
|
|
98
109
|
if (onUpdate) onUpdate(viewUpdate);
|
|
@@ -128,7 +139,7 @@ export default function Editor({
|
|
|
128
139
|
useEffect(() => {
|
|
129
140
|
if (focused && onFocus) onFocus();
|
|
130
141
|
if (!focused && onBlur) onBlur();
|
|
131
|
-
}, [focused]);
|
|
142
|
+
}, [focused, onFocus, onBlur]);
|
|
132
143
|
return /*#__PURE__*/_jsxs(Box, {
|
|
133
144
|
ref: ref,
|
|
134
145
|
children: [/*#__PURE__*/_jsx(CodeMirror, {
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import { LanguageSupport, StreamLanguage, syntaxTree } from "@codemirror/language";
|
|
3
|
+
import { nScriptKeywords } from "./nScriptKeywords";
|
|
4
|
+
|
|
5
|
+
// 현재 코드에서 사용하는 이름: 테마 스타일(색상)이름
|
|
6
|
+
var color = {
|
|
7
|
+
comment: "comment",
|
|
8
|
+
number: "number",
|
|
9
|
+
string: "string",
|
|
10
|
+
keyword: "keyword",
|
|
11
|
+
// 스크립트 변수
|
|
12
|
+
variable: "attributeValue",
|
|
13
|
+
// API 변수(속성)
|
|
14
|
+
function: "propertyName",
|
|
15
|
+
// API 함수
|
|
16
|
+
customer: "variableName",
|
|
17
|
+
// 고객사 변수 (읽기 전용)
|
|
18
|
+
operator: "squareBracket",
|
|
19
|
+
// 일반 연산자
|
|
20
|
+
punctuation: "punctuation" // 범위 관련 연산자
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// 기본 키워드
|
|
24
|
+
var defaultKeywords = ["if", "else"];
|
|
25
|
+
var operators = "+-/*%=|&<>~^?!";
|
|
26
|
+
var punc = ":;,.(){}[]";
|
|
27
|
+
var regexName = /^[a-zA-Z_]\w*/;
|
|
28
|
+
var regexColon = /[\s:]+/;
|
|
29
|
+
|
|
30
|
+
// 기본 토큰 처리기
|
|
31
|
+
function tokenBase(stream, state, prev) {
|
|
32
|
+
if (stream.sol()) state.indented = stream.indentation();
|
|
33
|
+
if (stream.eatSpace()) return null;
|
|
34
|
+
var ch = stream.peek();
|
|
35
|
+
// 주석
|
|
36
|
+
if (ch == "/") {
|
|
37
|
+
if (stream.match("//")) {
|
|
38
|
+
stream.skipToEnd();
|
|
39
|
+
return color.comment;
|
|
40
|
+
}
|
|
41
|
+
if (stream.match("/*")) {
|
|
42
|
+
state.tokenize.push(tokenComment);
|
|
43
|
+
return tokenComment(stream, state);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// 숫자
|
|
47
|
+
if ('0' <= ch && ch <= '9') {
|
|
48
|
+
stream.match(/^\d+/);
|
|
49
|
+
return color.number;
|
|
50
|
+
}
|
|
51
|
+
// 스크립트 변수
|
|
52
|
+
if (ch == '@' || ch == '#') {
|
|
53
|
+
stream.next();
|
|
54
|
+
stream.match(regexName);
|
|
55
|
+
stream.match(regexColon);
|
|
56
|
+
stream.match(regexName);
|
|
57
|
+
return color.variable;
|
|
58
|
+
}
|
|
59
|
+
// 테이블 변수
|
|
60
|
+
if (ch == '`') {
|
|
61
|
+
stream.next();
|
|
62
|
+
stream.match(regexName);
|
|
63
|
+
return color.variable;
|
|
64
|
+
}
|
|
65
|
+
// 고객사 변수
|
|
66
|
+
if (ch == '$') {
|
|
67
|
+
stream.next();
|
|
68
|
+
stream.match(regexName);
|
|
69
|
+
stream.match(regexColon);
|
|
70
|
+
stream.match(regexName);
|
|
71
|
+
return color.customer;
|
|
72
|
+
}
|
|
73
|
+
// 빠른 문자열 매개변수
|
|
74
|
+
if (ch == ':') {
|
|
75
|
+
stream.next();
|
|
76
|
+
stream.eatSpace();
|
|
77
|
+
stream.match(regexName);
|
|
78
|
+
return color.string;
|
|
79
|
+
}
|
|
80
|
+
// 일반 연산자
|
|
81
|
+
if (operators.indexOf(ch) > -1) {
|
|
82
|
+
stream.next();
|
|
83
|
+
return color.operator;
|
|
84
|
+
}
|
|
85
|
+
// 범위 관련 연산자
|
|
86
|
+
if (punc.indexOf(ch) > -1) {
|
|
87
|
+
stream.next();
|
|
88
|
+
stream.match("..");
|
|
89
|
+
return color.punctuation;
|
|
90
|
+
}
|
|
91
|
+
// 문자열
|
|
92
|
+
var stringMatch;
|
|
93
|
+
if (stringMatch = stream.match(/("""|"|')/)) {
|
|
94
|
+
var tokenize = tokenString.bind(null, stringMatch[0]);
|
|
95
|
+
state.tokenize.push(tokenize);
|
|
96
|
+
return tokenize(stream, state);
|
|
97
|
+
}
|
|
98
|
+
// 예약어
|
|
99
|
+
if (stream.match(regexName)) {
|
|
100
|
+
var ident = stream.current();
|
|
101
|
+
var api = nScriptKeywords.find(api => api.k === ident);
|
|
102
|
+
if (api) {
|
|
103
|
+
if (api.t.at(0) == '-') return color.keyword;else return color.function;
|
|
104
|
+
}
|
|
105
|
+
if (defaultKeywords.find(key => key === ident)) return color.keyword;
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
stream.next();
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 문자열 템플릿 토큰 처리기
|
|
113
|
+
function tokenUntilClosingParen() {
|
|
114
|
+
var depth = 0;
|
|
115
|
+
return function (stream, state, prev) {
|
|
116
|
+
var inner = tokenBase(stream, state, prev);
|
|
117
|
+
if (inner == color.punctuation) {
|
|
118
|
+
let cur = stream.current();
|
|
119
|
+
if (cur == "(" || cur == "{") {
|
|
120
|
+
// 소괄호 중괄호 모두 지원
|
|
121
|
+
++depth;
|
|
122
|
+
} else if (cur == ")" || cur == "}") {
|
|
123
|
+
// 소괄호 중괄호 모두 지원
|
|
124
|
+
if (depth == 0) {
|
|
125
|
+
stream.backUp(1);
|
|
126
|
+
state.tokenize.pop();
|
|
127
|
+
return state.tokenize[state.tokenize.length - 1](stream, state);
|
|
128
|
+
} else --depth;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return inner;
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 문자열 토큰 처리기
|
|
136
|
+
function tokenString(openQuote, stream, state) {
|
|
137
|
+
var singleLine = openQuote.length == 1;
|
|
138
|
+
var ch,
|
|
139
|
+
escaped = false;
|
|
140
|
+
while (ch = stream.peek()) {
|
|
141
|
+
if (escaped) {
|
|
142
|
+
stream.next();
|
|
143
|
+
if (ch == "(" || ch == "{") {
|
|
144
|
+
// 소괄호 중괄호 모두 지원
|
|
145
|
+
state.tokenize.push(tokenUntilClosingParen());
|
|
146
|
+
return color.string;
|
|
147
|
+
}
|
|
148
|
+
escaped = false;
|
|
149
|
+
} else if (stream.match(openQuote)) {
|
|
150
|
+
state.tokenize.pop();
|
|
151
|
+
return color.string;
|
|
152
|
+
} else {
|
|
153
|
+
stream.next();
|
|
154
|
+
escaped = ch == "$"; // 코틀린 방식 문자열 템플릿
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (singleLine) {
|
|
159
|
+
state.tokenize.pop();
|
|
160
|
+
}
|
|
161
|
+
return color.string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 주석 토큰 처리기
|
|
165
|
+
function tokenComment(stream, state) {
|
|
166
|
+
var ch;
|
|
167
|
+
while (ch = stream.next()) {
|
|
168
|
+
if (ch === "/" && stream.eat("*")) {
|
|
169
|
+
state.tokenize.push(tokenComment);
|
|
170
|
+
} else if (ch === "*" && stream.eat("/")) {
|
|
171
|
+
state.tokenize.pop();
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return color.comment;
|
|
176
|
+
}
|
|
177
|
+
function Context(prev, align, indented) {
|
|
178
|
+
this.prev = prev;
|
|
179
|
+
this.align = align;
|
|
180
|
+
this.indented = indented;
|
|
181
|
+
}
|
|
182
|
+
function pushContext(state, stream) {
|
|
183
|
+
var align = stream.match(/^\s*($|\/[\/\*]|[)}\]])/, false) ? null : stream.column() + 1;
|
|
184
|
+
state.context = new Context(state.context, align, state.indented);
|
|
185
|
+
}
|
|
186
|
+
function popContext(state) {
|
|
187
|
+
if (state.context) {
|
|
188
|
+
state.indented = state.context.indented;
|
|
189
|
+
state.context = state.context.prev;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// nScript 파서 메인 처리기
|
|
194
|
+
export const nScriptParser = {
|
|
195
|
+
name: "nScript",
|
|
196
|
+
startState: function () {
|
|
197
|
+
return {
|
|
198
|
+
prev: null,
|
|
199
|
+
context: null,
|
|
200
|
+
indented: 0,
|
|
201
|
+
tokenize: []
|
|
202
|
+
};
|
|
203
|
+
},
|
|
204
|
+
token: function (stream, state) {
|
|
205
|
+
var prev = state.prev;
|
|
206
|
+
state.prev = null;
|
|
207
|
+
var tokenize = state.tokenize[state.tokenize.length - 1] || tokenBase;
|
|
208
|
+
var style = tokenize(stream, state, prev);
|
|
209
|
+
if (!style || style == color.comment) state.prev = prev;else if (!state.prev) state.prev = style;
|
|
210
|
+
if (style == color.punctuation) {
|
|
211
|
+
var bracket = /[\(\[\{]|([\]\)\}])/.exec(stream.current());
|
|
212
|
+
if (bracket) (bracket[1] ? popContext : pushContext)(state, stream);
|
|
213
|
+
}
|
|
214
|
+
return style;
|
|
215
|
+
},
|
|
216
|
+
indent: function (state, textAfter, iCx) {
|
|
217
|
+
var cx = state.context;
|
|
218
|
+
if (!cx) return 0;
|
|
219
|
+
var closing = /^[\]\}\)]/.test(textAfter);
|
|
220
|
+
if (cx.align != null) return cx.align - (closing ? 1 : 0);
|
|
221
|
+
return cx.indented + (closing ? 0 : iCx.unit);
|
|
222
|
+
},
|
|
223
|
+
languageData: {
|
|
224
|
+
indentOnInput: /^\s*[\)\}\]]$/,
|
|
225
|
+
commentTokens: {
|
|
226
|
+
line: "//",
|
|
227
|
+
block: {
|
|
228
|
+
open: "/*",
|
|
229
|
+
close: "*/"
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
//closeBrackets: {brackets: ["(", "[", "{", "'", '"', "`"]}
|
|
233
|
+
closeBrackets: {
|
|
234
|
+
brackets: ["(", "[", "{", "'", '"']
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
export const nScriptLanguage = StreamLanguage.define(nScriptParser);
|
|
239
|
+
|
|
240
|
+
// nScript 자동 완성 메인 처리기
|
|
241
|
+
function nScriptCompletion(context) {
|
|
242
|
+
const {
|
|
243
|
+
state,
|
|
244
|
+
pos
|
|
245
|
+
} = context;
|
|
246
|
+
const nodeBefore = syntaxTree(state).resolveInner(pos, -1);
|
|
247
|
+
const typeName = nodeBefore.type.name;
|
|
248
|
+
//console.log(typeName);
|
|
249
|
+
|
|
250
|
+
// 주석이나 문자열 등은 스킵
|
|
251
|
+
if (typeName === color.comment || typeName === color.string || typeName === color.variable || typeName === color.customer) return null;
|
|
252
|
+
let word = context.matchBefore(/\w*/);
|
|
253
|
+
if (word.from == word.to && !context.explicit) return null;
|
|
254
|
+
return {
|
|
255
|
+
from: word.from,
|
|
256
|
+
options: [...nScriptKeywords.map(it => ({
|
|
257
|
+
//section: it.i,
|
|
258
|
+
//displayLabel: it.i + "." + it.k,
|
|
259
|
+
label: it.k,
|
|
260
|
+
type: it.t.at(0) == '-' ? it.t.at(3) == 'c' ? "constant" : "variable" : "function",
|
|
261
|
+
detail: it.t,
|
|
262
|
+
info: it.i + "." + it.k + it.t + " " + it.d,
|
|
263
|
+
boost: 1
|
|
264
|
+
})), ...defaultKeywords.map(it => ({
|
|
265
|
+
label: it,
|
|
266
|
+
type: "keyword",
|
|
267
|
+
boost: 0
|
|
268
|
+
}))]
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
export const nScriptExtension = nScriptLanguage.data.of({
|
|
272
|
+
autocomplete: nScriptCompletion
|
|
273
|
+
});
|
|
274
|
+
export const nScript = new LanguageSupport(nScriptLanguage, [nScriptExtension]);
|