nsp-server-pages 0.0.1

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.
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseEL = void 0;
4
+ const trim = (str) => str.replace(/^\s+/s, "").replace(/\s+$/s, "");
5
+ const wordMap = {
6
+ and: "&&",
7
+ div: "/",
8
+ empty: "!",
9
+ eq: "==",
10
+ false: "false",
11
+ ge: ">=",
12
+ gt: ">",
13
+ instanceof: "instanceof",
14
+ le: "<=",
15
+ lt: "<",
16
+ mod: "%",
17
+ ne: "!=",
18
+ not: "!",
19
+ null: "null",
20
+ or: "||",
21
+ true: "true",
22
+ };
23
+ const numericRE = `[0-9]+(?![0-9])`;
24
+ const floatRE = `${numericRE}(?:\\.${numericRE})?(?!\\.)`;
25
+ const stringRE = `"(?:\\\\\\.|[^\\\\"])*"|'(?:\\\\\\.|[^\\\\'])*'`;
26
+ const nameRE = `[A-Za-z_][A-Za-z_0-9]*(?![A-Za-z_0-9])`;
27
+ const tagFnRE = `${nameRE}:${nameRE}\\(`;
28
+ const variableRE = `${nameRE}(?:\\.${nameRE}|\\[(?:${numericRE}|${stringRE})\\])*`;
29
+ const opRE = `[+\\-\\*/%=<>()!|&:?,]+(?![+\\-\\*/%=<>()!|&:?,])`;
30
+ const itemRE = [tagFnRE, variableRE, floatRE, stringRE, opRE].join("|");
31
+ const tagFnRegExp = new RegExp(`^${tagFnRE}$`, "s");
32
+ const variableRegExp = new RegExp(`^${variableRE}$`, "s");
33
+ const itemRegExp = new RegExp(`(${itemRE})`, "s");
34
+ /**
35
+ * Simplified transformer for expression language
36
+ */
37
+ const parseEL = (app, src) => new ElParser(app, src);
38
+ exports.parseEL = parseEL;
39
+ class ElParser {
40
+ constructor(app, src) {
41
+ this.app = app;
42
+ this.src = src;
43
+ //
44
+ }
45
+ /**
46
+ * Compile ${EL} to JavaScript function instance
47
+ */
48
+ toFn() {
49
+ const { app } = this;
50
+ const { nspKey, vKey } = app.options;
51
+ const js = this.toJS();
52
+ try {
53
+ const fn = Function(nspKey, vKey, `return ${js}`);
54
+ return (context) => fn(app, context);
55
+ }
56
+ catch (e) {
57
+ app.log("ElParser: " + js?.substring(0, 1000));
58
+ throw e;
59
+ }
60
+ }
61
+ /**
62
+ * Transpile ${EL} to JavaScript source code
63
+ */
64
+ toJS(_) {
65
+ const { app } = this;
66
+ const { prefilter, postfilter } = app.options;
67
+ let src = trim(this.src);
68
+ if (prefilter)
69
+ src = prefilter(src);
70
+ if (src == null)
71
+ return 'null';
72
+ const array = src.split(itemRegExp);
73
+ const { nspKey, vKey } = app.options;
74
+ for (let i = 0; i < array.length; i++) {
75
+ let exp = array[i];
76
+ if (i & 1) {
77
+ if (wordMap[exp]) {
78
+ // eq, and, or
79
+ array[i] = wordMap[exp];
80
+ }
81
+ else if (tagFnRegExp.test(exp)) {
82
+ // taglib function
83
+ exp = exp.replace(/\($/, "");
84
+ array[i] = `${nspKey}.fn(${JSON.stringify(exp)})(`;
85
+ }
86
+ else if (variableRegExp.test(exp)) {
87
+ // variable
88
+ exp = exp.replace(/\./g, "?.");
89
+ exp = exp.replace(/\[/g, "?.[");
90
+ exp = exp.replace(/\s+$/, "");
91
+ array[i] = `${vKey}.${exp}`;
92
+ }
93
+ }
94
+ else {
95
+ // less spaces
96
+ array[i] = exp.replace(/\s+/sg, " ");
97
+ }
98
+ }
99
+ let js = array.join("");
100
+ if (postfilter)
101
+ js = postfilter(js);
102
+ return js;
103
+ }
104
+ }
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.jspToJS = exports.parseJSP = void 0;
4
+ const parse_text_js_1 = require("./parse-text.js");
5
+ const parse_attr_js_1 = require("./parse-attr.js");
6
+ const parse_scriptlet_js_1 = require("./parse-scriptlet.js");
7
+ const emptyText = {
8
+ '""': true,
9
+ "''": true,
10
+ "``": true,
11
+ "null": true,
12
+ "undefined": true,
13
+ "": true,
14
+ };
15
+ const isElement = (node) => ("function" === typeof node?.toJS);
16
+ /**
17
+ * Parser for JSP document
18
+ */
19
+ const parseJSP = (app, src) => new JspParser(app, src);
20
+ exports.parseJSP = parseJSP;
21
+ /**
22
+ * Root element or an taglib element
23
+ */
24
+ class Element {
25
+ constructor(app, tagName, tagLine) {
26
+ this.app = app;
27
+ this.tagName = tagName;
28
+ this.tagLine = tagLine;
29
+ this.children = [];
30
+ //
31
+ }
32
+ append(node) {
33
+ this.children.push(node);
34
+ }
35
+ /**
36
+ * Transpile JSP document to JavaScript source code
37
+ */
38
+ toJS(option) {
39
+ const { app, tagLine } = this;
40
+ const { comment, nspKey, vKey } = app.options;
41
+ const indent = +app.options.indent || 0;
42
+ const currentIndent = +option?.indent || 0;
43
+ const nextIndent = currentIndent + indent;
44
+ const currentLF = currentIndent ? "\n" + " ".repeat(currentIndent) : "\n";
45
+ const nextLF = nextIndent ? "\n" + " ".repeat(nextIndent) : "\n";
46
+ const { children } = this;
47
+ const args = children.map(item => {
48
+ if (isElement(item)) {
49
+ return item.toJS({ indent: nextIndent });
50
+ }
51
+ else if (!/\S/.test(item)) {
52
+ // item with only whitespace
53
+ return '""';
54
+ }
55
+ else {
56
+ let js = (0, parse_text_js_1.parseText)(app, item).toJS({ indent: nextIndent });
57
+ if (/\(.+?\)|\$\{.+?}/s.test(js)) {
58
+ js = `${vKey} => ${js}`; // array function
59
+ }
60
+ return js;
61
+ }
62
+ }).filter(v => !emptyText[v]);
63
+ const hasBody = !!children.length;
64
+ // keep at least single empty string if all arguments are empty strings
65
+ if (hasBody && !args.length) {
66
+ args.push('""');
67
+ }
68
+ const { tagName } = this;
69
+ const isRoot = !tagName;
70
+ const last = args.length - 1;
71
+ args.forEach((v, idx) => {
72
+ const isComment = /^\/\/[^\n]*$/s.test(v);
73
+ if (idx !== last && !isComment) {
74
+ args[idx] += ",";
75
+ }
76
+ else if (idx === last && isComment) {
77
+ args[idx] += currentLF;
78
+ }
79
+ });
80
+ let body = args.join(nextLF);
81
+ const bodyL = /^`\n/s.test(body) ? (isRoot ? "" : " ") : nextLF;
82
+ const bodyR = /(\n`|[)\s])$/s.test(body) ? "" : currentLF;
83
+ if (isRoot) {
84
+ return `${nspKey}.bundle(${bodyL}${body}${bodyR})`; // root element
85
+ }
86
+ // attributes as the second argument
87
+ let attr = (0, parse_attr_js_1.parseAttr)(app, tagLine).toJS({ indent: args.length ? nextIndent : currentIndent });
88
+ if (/\(.+?\)|\$\{.+?}/s.test(attr)) {
89
+ attr = `${vKey} => (${attr})`; // array function
90
+ }
91
+ const commentV = comment ? `// ${tagLine?.replace(/\s*[\r\n]\s*/g, " ") ?? ""}${currentLF}` : "";
92
+ const nameV = JSON.stringify(tagName);
93
+ const hasAttr = /:/.test(attr);
94
+ const attrV = (hasBody || hasAttr) ? `, ${attr}` : "";
95
+ const bodyV = hasBody ? `,${bodyL}${body}${bodyR}` : "";
96
+ return `${commentV}${nspKey}.tag(${nameV}${attrV}${bodyV})`;
97
+ }
98
+ }
99
+ /**
100
+ * Tree of elements
101
+ */
102
+ class Tree {
103
+ constructor(root) {
104
+ this.root = root;
105
+ this.tree = [];
106
+ this.tree.push(root);
107
+ }
108
+ append(node) {
109
+ this.tree.at(0).append(node);
110
+ }
111
+ open(node) {
112
+ this.append(node);
113
+ this.tree.unshift(node);
114
+ }
115
+ close(tagName) {
116
+ const openTag = this.getTagName();
117
+ if (openTag !== tagName) {
118
+ throw new Error(`mismatch closing tag: ${openTag} !== ${tagName}`);
119
+ }
120
+ this.tree.shift();
121
+ }
122
+ getTagName() {
123
+ return this.tree.at(0).tagName;
124
+ }
125
+ isRoot() {
126
+ return this.tree.length === 1;
127
+ }
128
+ }
129
+ class JspParser {
130
+ constructor(app, src) {
131
+ this.app = app;
132
+ this.src = src;
133
+ //
134
+ }
135
+ /**
136
+ * Transpile JSP document to JavaScript source code
137
+ */
138
+ toJS(option) {
139
+ const { app, src } = this;
140
+ return (0, exports.jspToJS)(app, src, option);
141
+ }
142
+ /**
143
+ * Compile JSP document to JavaScript function
144
+ */
145
+ toFn() {
146
+ const { app } = this;
147
+ const { nspKey } = app.options;
148
+ const js = this.toJS();
149
+ try {
150
+ const fn = Function(nspKey, `return ${js}`);
151
+ return fn(app);
152
+ }
153
+ catch (e) {
154
+ app.log("JspParser: " + js?.substring(0, 1000));
155
+ throw e;
156
+ }
157
+ }
158
+ }
159
+ const nameRE = `[A-Za-z][A-Za-z0-9]*`;
160
+ const stringRE = `"(?:\\\\[.]|[^\\\\"])*"|'(?:\\\\[.]|[^\\\\'])*'`;
161
+ const insideRE = `[^"']|${stringRE}`;
162
+ const tagRegExp = new RegExp(`(</?${nameRE}:(?:${insideRE})*?>)|(<%(?:${insideRE})*?%>)`, "s");
163
+ const jspToJS = (app, src, option) => {
164
+ const root = new Element(app);
165
+ const tree = new Tree(root);
166
+ const { trimSpaces } = app.options;
167
+ const array = src.split(tagRegExp);
168
+ for (let i = 0; i < array.length; i++) {
169
+ const i3 = i % 3;
170
+ let str = array[i];
171
+ if (i3 === 1 && str) {
172
+ // taglib
173
+ const tagName = str.match(/^<\/?([^\s=/>]+)/)?.[1];
174
+ if (/^<\//.test(str)) {
175
+ tree.close(tagName);
176
+ continue;
177
+ }
178
+ const element = new Element(app, tagName, str);
179
+ if (/\/\s*>$/.test(str)) {
180
+ tree.append(element);
181
+ }
182
+ else {
183
+ tree.open(element);
184
+ }
185
+ }
186
+ else if (i3 === 2 && str) {
187
+ // <% scriptlet %>
188
+ const item = (0, parse_scriptlet_js_1.parseScriptlet)(app, str);
189
+ tree.append(item);
190
+ }
191
+ else if (i3 === 0) {
192
+ // text node
193
+ if (trimSpaces !== false) {
194
+ str = str.replace(/^\s*[\r\n]/s, "\n");
195
+ str = str.replace(/\s*[\r\n]\s*$/s, "\n");
196
+ str = str.replace(/^[ \t]+/s, " ");
197
+ str = str.replace(/[ \t]+$/s, " ");
198
+ }
199
+ tree.append(str);
200
+ }
201
+ }
202
+ if (!tree.isRoot()) {
203
+ throw new Error("missing closing tag: " + tree.getTagName());
204
+ }
205
+ return root.toJS(option);
206
+ };
207
+ exports.jspToJS = jspToJS;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseScriptlet = void 0;
4
+ const parse_el_js_1 = require("./parse-el.js");
5
+ /**
6
+ * Parser for Directive, Declaration, Scriptlet
7
+ * <%-- comment --%>
8
+ * <%@ directive %>
9
+ * <%! declaration(s) %>
10
+ * <% scriptlet %>
11
+ * <%= expression %>
12
+ */
13
+ const parseScriptlet = (app, src) => new ScriptletParser(app, src);
14
+ exports.parseScriptlet = parseScriptlet;
15
+ const typeMap = {
16
+ "<%-": "comment",
17
+ "<%@": "directive",
18
+ "<%!": "declaration",
19
+ "<%=": "expression",
20
+ };
21
+ class ScriptletParser {
22
+ constructor(app, src) {
23
+ this.app = app;
24
+ this.src = src;
25
+ //
26
+ }
27
+ /**
28
+ * Compile <% scriptlet %> to JavaScript function instance
29
+ */
30
+ toFn() {
31
+ const { app } = this;
32
+ const { nspKey } = app.options;
33
+ const js = this.toJS();
34
+ const isComment = /^\/\/[^\n]*$/s.test(js);
35
+ if (isComment)
36
+ return () => null;
37
+ try {
38
+ const fn = Function(nspKey, `return ${js}`);
39
+ return fn(app);
40
+ }
41
+ catch (e) {
42
+ app.log("ScriptletParser: " + js?.substring(0, 1000));
43
+ throw e;
44
+ }
45
+ }
46
+ /**
47
+ * Transpile <% scriptlet %> to JavaScript source code
48
+ */
49
+ toJS(option) {
50
+ const { app } = this;
51
+ const { nspKey, vKey } = app.options;
52
+ let { src } = this;
53
+ const type = typeMap[src.substring(0, 3)] || "scriptlet";
54
+ if (type === "comment") {
55
+ src = src.replace(/\s\s+/sg, " ");
56
+ return `// ${src}`;
57
+ }
58
+ if (type === "expression") {
59
+ src = src.replace(/^<%=\s*/s, "");
60
+ src = src.replace(/\s*%>$/s, "");
61
+ src = (0, parse_el_js_1.parseEL)(app, src).toJS(option);
62
+ return `${vKey} => (${src})`;
63
+ }
64
+ app.log(`${type} found: ${src?.substring(0, 1000)}`);
65
+ src = /`|\$\{/.test(src) ? JSON.stringify(src) : "`" + src + "`";
66
+ src = `${vKey} => ${nspKey}.emit("${type}", ${src}, ${vKey})`;
67
+ return src;
68
+ }
69
+ }
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseText = void 0;
4
+ const parse_el_js_1 = require("./parse-el.js");
5
+ const parse_scriptlet_js_1 = require("./parse-scriptlet.js");
6
+ /**
7
+ * escape special characters in Template Literal
8
+ */
9
+ const escapeTL = (str) => str.replace(/([\\`$])/g, "\\$1");
10
+ const TLStringify = (str) => ("`" + escapeTL(str) + "`");
11
+ const stringify = (str) => (/[\r\n"<>]/.test(str) ? TLStringify(str) : JSON.stringify(str));
12
+ /**
13
+ * Regular expression to match ${expression} in text
14
+ */
15
+ const stringRE = `"(?:\\\\[.]|[^\\\\"])*"|'(?:\\\\[.]|[^\\\\'])*'`;
16
+ const insideRE = `[^"']|${stringRE}`;
17
+ const bodyRE = `([$#][{](?:${insideRE})*?})|(<%=(?:${insideRE})*?%>)`;
18
+ const bodyRegExp = new RegExp(bodyRE, "s");
19
+ /**
20
+ * Parser for: text content
21
+ */
22
+ const parseText = (app, src) => new TextParser(app, src);
23
+ exports.parseText = parseText;
24
+ class TextParser {
25
+ constructor(app, src) {
26
+ this.app = app;
27
+ this.src = src;
28
+ //
29
+ }
30
+ /**
31
+ * Transpile ${expression} and <% scriptlet %> to JavaScript source code
32
+ */
33
+ toJS(option) {
34
+ return textToJS(this.app, this.src, option);
35
+ }
36
+ /**
37
+ * Compile ${expression} and <% scriptlet %> to JavaScript function instance
38
+ */
39
+ toFn() {
40
+ const { app } = this;
41
+ const { nspKey, vKey } = app.options;
42
+ const js = this.toJS();
43
+ try {
44
+ const fn = Function(nspKey, vKey, `return ${js}`);
45
+ return (context) => fn(app, context);
46
+ }
47
+ catch (e) {
48
+ app.log("TextParser: " + js?.substring(0, 1000));
49
+ throw e;
50
+ }
51
+ }
52
+ }
53
+ /**
54
+ * Transpile ${expression}, #{async expression} and <% scriptlet %> to JavaScript source code
55
+ */
56
+ const textToJS = (app, src, option) => {
57
+ const array = src.split(bodyRegExp);
58
+ const items = [];
59
+ for (let i = 0; i < array.length; i++) {
60
+ const i3 = i % 3;
61
+ let value = array[i];
62
+ if (!value)
63
+ continue;
64
+ if (i3 === 1) {
65
+ // ${expression}, #{async expression}
66
+ const isAsync = /^#/s.test(value);
67
+ value = value.replace(/^[$#]\{\s*/s, "");
68
+ value = value.replace(/\s*}$/s, "");
69
+ const item = (0, parse_el_js_1.parseEL)(app, value);
70
+ if (isAsync) {
71
+ items.push({ toJS: (option) => `await ${item.toJS(option)}` });
72
+ }
73
+ else {
74
+ items.push(item);
75
+ }
76
+ }
77
+ else if (i3 === 2) {
78
+ // <% scriptlet %>
79
+ const item = (0, parse_scriptlet_js_1.parseScriptlet)(app, value);
80
+ items.push(item);
81
+ }
82
+ else {
83
+ // text literal
84
+ items.push(value);
85
+ }
86
+ }
87
+ // empty string
88
+ if (!items.length)
89
+ return '""';
90
+ // single element
91
+ if (items.length === 1) {
92
+ const item = items[0];
93
+ if (typeof item === "string") {
94
+ return stringify(item);
95
+ }
96
+ else {
97
+ return "(" + item.toJS(option) + ")";
98
+ }
99
+ }
100
+ let hasAwait = false;
101
+ items.forEach((item, i) => {
102
+ if (typeof item === "string") {
103
+ items[i] = escapeTL(item);
104
+ }
105
+ else {
106
+ const js = item.toJS(option);
107
+ if (/^\(?await\s/.test(js))
108
+ hasAwait = true;
109
+ items[i] = "${" + js + "}";
110
+ }
111
+ });
112
+ let out = "`" + items.join("") + "`";
113
+ // wrap in async function if it has an await
114
+ if (hasAwait) {
115
+ out = `(async () => (${out}))()`;
116
+ }
117
+ return out;
118
+ };
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.prepareTag = exports.addTagLib = void 0;
4
+ const to_xml_1 = require("to-xml");
5
+ const addTagLib = (app, tagLibDef) => {
6
+ const { fnMap, tagMap } = app;
7
+ const { ns, fn, tag } = tagLibDef;
8
+ if (fn) {
9
+ for (const name in fn) {
10
+ fnMap.set(`${ns}:${name}`, fn[name]);
11
+ }
12
+ }
13
+ if (tag) {
14
+ for (const name in tag) {
15
+ tagMap.set(`${ns}:${name}`, tag[name]);
16
+ }
17
+ }
18
+ };
19
+ exports.addTagLib = addTagLib;
20
+ const prepareTag = (app, name, attr, body) => {
21
+ const { tagMap, options } = app;
22
+ const tagFn = tagMap.get(name) || defaultTagFn;
23
+ const conf = options.conf[name];
24
+ const attrFn = !attr ? () => ({}) : (typeof attr !== "function") ? () => attr : attr;
25
+ const tagDef = { name, app, conf, attr: attrFn, body };
26
+ return tagFn(tagDef);
27
+ };
28
+ exports.prepareTag = prepareTag;
29
+ const defaultTagFn = (tagDef) => {
30
+ const { name } = tagDef;
31
+ // tagDef.app.log(`Unknown tag: ${name}`);
32
+ return (context) => {
33
+ const attr = tagDef.attr(context);
34
+ const body = tagDef.body(context);
35
+ const xml = {};
36
+ xml[name] = { "@": attr };
37
+ let tag = (0, to_xml_1.toXML)(xml);
38
+ if (body === null) {
39
+ return tag;
40
+ }
41
+ tag = tag.replace(/\/>$/, `>`);
42
+ return tagDef.app.concat(tag, body, `</${name}>`);
43
+ };
44
+ };
package/index.d.ts ADDED
@@ -0,0 +1,141 @@
1
+ /**
2
+ * nsp-server-pages
3
+ *
4
+ * @see https://github.com/kawanet/nsp-server-pages
5
+ */
6
+
7
+ export const createNSP: (options?: NSP.Options) => NSP.App;
8
+
9
+ declare namespace NSP {
10
+ type NodeFn<T> = (context?: T) => string | Promise<string>;
11
+
12
+ type Node<T> = string | NodeFn<T>;
13
+
14
+ type AttrFn<A, T = any> = (context?: T) => A;
15
+
16
+ type TagFn<A, T = any> = (tag: TagDef<A, T>) => NodeFn<T>;
17
+
18
+ type LoaderFn = (path: string) => Promise<NSP.NodeFn<any>>;
19
+
20
+ type TextFlex = string | Promise<string> | (string | Promise<string>)[];
21
+
22
+ interface TagDef<A, T = any> {
23
+ app: NSP.App;
24
+ conf: any;
25
+ name: string;
26
+ attr: AttrFn<A, T>;
27
+ body: NodeFn<T>;
28
+ }
29
+
30
+ interface Options {
31
+ logger?: { log: (message: string) => void };
32
+
33
+ /**
34
+ * tag configuration
35
+ */
36
+ conf?: { [tagName: string]: any };
37
+
38
+ /**
39
+ * variable name for context
40
+ */
41
+ vKey?: string;
42
+
43
+ /**
44
+ * variable name for NSP.App instance
45
+ */
46
+ nspKey?: string;
47
+
48
+ /**
49
+ * indent size for JavaScript source generated
50
+ */
51
+ indent?: number;
52
+
53
+ /**
54
+ * add comments at toJS() result
55
+ */
56
+ comment?: boolean;
57
+
58
+ /**
59
+ * remove edge spaces in HTML in some cases
60
+ */
61
+ trimSpaces?: boolean;
62
+
63
+ /**
64
+ * expression filter before transpile starts
65
+ */
66
+ prefilter?: (src: string) => string;
67
+
68
+ /**
69
+ * expression filter after transpile done
70
+ */
71
+ postfilter?: (src: string) => string;
72
+ }
73
+
74
+ interface App {
75
+ fnMap: Map<string, (...args: any[]) => any>;
76
+ loaders: LoaderFn[];
77
+ options: Options;
78
+ tagMap: Map<string, TagFn<any>>;
79
+
80
+ addTagLib(tagLibDef: TagLibDef): void;
81
+
82
+ bundle<T>(...node: Node<T>[]): NodeFn<T>;
83
+
84
+ concat(...text: TextFlex[]): string | Promise<string>;
85
+
86
+ emit<T>(type: "error", e: Error, context?: T): string;
87
+
88
+ emit<T>(type: "directive", src: string, context?: T): string;
89
+
90
+ emit<T>(type: "declaration", src: string, context?: T): string;
91
+
92
+ emit<T>(type: "scriptlet", src: string, context?: T): string;
93
+
94
+ fn(name: string): (...args: any[]) => any;
95
+
96
+ load<T>(path: string): Promise<NSP.NodeFn<T>>;
97
+
98
+ loadFile<T>(file: string): Promise<NSP.NodeFn<T>>;
99
+
100
+ loadJS<T>(file: string): Promise<NSP.NodeFn<T>>;
101
+
102
+ loadJSP<T>(file: string): Promise<NSP.NodeFn<T>>;
103
+
104
+ log(message: string): void;
105
+
106
+ mount(match: RegExp | string, fn: LoaderFn): void;
107
+
108
+ on(type: "error", fn: <T>(e: Error, context?: T) => string | void): void;
109
+
110
+ on(type: "directive", fn: <T>(src: string, context?: T) => string | void): void;
111
+
112
+ on(type: "declaration", fn: <T>(src: string, context?: T) => string | void): void;
113
+
114
+ on(type: "scriptlet", fn: <T>(src: string, context?: T) => string | void): void;
115
+
116
+ parse(src: string): Parser;
117
+
118
+ tag<A, T = any>(name: string, attr?: A | AttrFn<A, T>, ...body: Node<T>[]): NodeFn<T>;
119
+ }
120
+
121
+ interface TagLibDef {
122
+ ns: string;
123
+
124
+ fn?: { [name: string]: (...args: any[]) => any };
125
+
126
+ tag?: { [name: string]: TagFn<any> };
127
+ }
128
+
129
+ interface ToJSOption {
130
+ indent?: number;
131
+ }
132
+
133
+ /**
134
+ * Parser for JSP document
135
+ */
136
+ interface Parser {
137
+ toJS(option?: ToJSOption): string;
138
+
139
+ toFn<T>(): NodeFn<T>;
140
+ }
141
+ }
package/index.js ADDED
@@ -0,0 +1 @@
1
+ export {createNSP} from "./src/app.js";