amateras 0.10.1 → 0.10.2
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/README.md +29 -25
- package/build/core.js +1 -0
- package/build/css.js +1 -0
- package/build/for.js +1 -0
- package/build/i18n.js +1 -0
- package/build/idb.js +1 -0
- package/build/if.js +1 -0
- package/build/import-map.js +1 -0
- package/build/markdown.js +1 -0
- package/build/match.js +1 -0
- package/build/meta.js +1 -0
- package/build/prefetch.js +1 -0
- package/build/router.js +1 -0
- package/build/signal.js +1 -0
- package/build/ui.js +1 -0
- package/build/widget.js +1 -0
- package/package.json +7 -5
- package/packages/core/package.json +19 -0
- package/packages/core/src/env.browser.ts +21 -0
- package/packages/core/src/env.node.ts +21 -0
- package/packages/core/src/global.ts +5 -0
- package/packages/core/src/index.ts +184 -0
- package/packages/core/src/lib/hmr.ts +145 -0
- package/packages/core/src/lib/symbols.ts +2 -0
- package/packages/core/src/structure/ElementProto.ts +95 -0
- package/packages/core/src/structure/GlobalState.ts +9 -0
- package/packages/core/src/structure/NodeProto.ts +18 -0
- package/packages/core/src/structure/Proto.ts +90 -0
- package/packages/core/src/structure/ProxyProto.ts +20 -0
- package/packages/core/src/structure/TextProto.ts +22 -0
- package/packages/core/src/structure/WidgetEvent.ts +17 -0
- package/packages/css/README.md +128 -0
- package/packages/css/package.json +15 -0
- package/packages/css/src/ext/colors/amber.ts +25 -0
- package/packages/css/src/ext/colors/blackwhite.ts +13 -0
- package/packages/css/src/ext/colors/blue.ts +25 -0
- package/packages/css/src/ext/colors/cyan.ts +25 -0
- package/packages/css/src/ext/colors/emerald.ts +25 -0
- package/packages/css/src/ext/colors/fuchsia.ts +25 -0
- package/packages/css/src/ext/colors/gray.ts +25 -0
- package/packages/css/src/ext/colors/green.ts +25 -0
- package/packages/css/src/ext/colors/indigo.ts +25 -0
- package/packages/css/src/ext/colors/lime.ts +25 -0
- package/packages/css/src/ext/colors/neutral.ts +25 -0
- package/packages/css/src/ext/colors/orange.ts +25 -0
- package/packages/css/src/ext/colors/pink.ts +25 -0
- package/packages/css/src/ext/colors/purple.ts +25 -0
- package/packages/css/src/ext/colors/red.ts +25 -0
- package/packages/css/src/ext/colors/rose.ts +25 -0
- package/packages/css/src/ext/colors/sky.ts +25 -0
- package/packages/css/src/ext/colors/slate.ts +25 -0
- package/packages/css/src/ext/colors/stone.ts +25 -0
- package/packages/css/src/ext/colors/teal.ts +25 -0
- package/packages/css/src/ext/colors/violet.ts +25 -0
- package/packages/css/src/ext/colors/yellow.ts +25 -0
- package/packages/css/src/ext/colors/zinc.ts +25 -0
- package/packages/css/src/ext/colors.ts +23 -0
- package/packages/css/src/ext/keyframes.ts +37 -0
- package/packages/css/src/ext/property.ts +68 -0
- package/packages/css/src/ext/variable.ts +51 -0
- package/packages/css/src/index.ts +103 -0
- package/packages/css/src/lib/cache.ts +27 -0
- package/packages/css/src/lib/colorAssign.ts +6 -0
- package/packages/css/src/lib/createRule.ts +31 -0
- package/packages/css/src/lib/utils.ts +1 -0
- package/packages/css/src/structure/$CSS.ts +4 -0
- package/packages/css/src/structure/$CSSKeyframes.ts +13 -0
- package/packages/css/src/structure/$CSSProperty.ts +21 -0
- package/packages/css/src/structure/$CSSRule.ts +39 -0
- package/packages/css/src/structure/$CSSVariable.ts +34 -0
- package/packages/css/src/types.ts +300 -0
- package/packages/for/package.json +15 -0
- package/packages/for/src/global.ts +7 -0
- package/packages/for/src/index.ts +15 -0
- package/packages/for/src/structure/For.ts +74 -0
- package/packages/hmr/package.json +13 -0
- package/packages/hmr/src/index.ts +27 -0
- package/packages/i18n/README.md +73 -0
- package/packages/i18n/package.json +15 -0
- package/packages/i18n/src/index.ts +78 -0
- package/packages/i18n/src/structure/I18n.ts +51 -0
- package/packages/i18n/src/structure/I18nDictionary.ts +31 -0
- package/packages/i18n/src/structure/I18nTranslation.ts +51 -0
- package/packages/i18n/src/types.ts +77 -0
- package/packages/idb/README.md +127 -0
- package/packages/idb/package.json +16 -0
- package/packages/idb/src/core.ts +6 -0
- package/packages/idb/src/index.ts +17 -0
- package/packages/idb/src/lib/$IDBRequest.ts +8 -0
- package/packages/idb/src/structure/$IDB.ts +63 -0
- package/packages/idb/src/structure/$IDBCursor.ts +34 -0
- package/packages/idb/src/structure/$IDBIndex.ts +48 -0
- package/packages/idb/src/structure/$IDBStore.ts +103 -0
- package/packages/idb/src/structure/$IDBStoreBase.ts +30 -0
- package/packages/idb/src/structure/$IDBTransaction.ts +38 -0
- package/packages/idb/src/structure/builder/$IDBBuilder.ts +229 -0
- package/packages/idb/src/structure/builder/$IDBStoreBuilder.ts +100 -0
- package/packages/if/package.json +15 -0
- package/packages/if/src/global.ts +15 -0
- package/packages/if/src/index.ts +51 -0
- package/packages/if/src/structure/Condition.ts +44 -0
- package/packages/if/src/structure/ConditionStatement.ts +25 -0
- package/packages/if/src/structure/Else.ts +6 -0
- package/packages/if/src/structure/ElseIf.ts +6 -0
- package/packages/if/src/structure/If.ts +6 -0
- package/packages/markdown/README.md +53 -0
- package/packages/markdown/package.json +15 -0
- package/packages/markdown/src/index.ts +3 -0
- package/packages/markdown/src/lib/type.ts +26 -0
- package/packages/markdown/src/lib/util.ts +21 -0
- package/packages/markdown/src/structure/Markdown.ts +57 -0
- package/packages/markdown/src/structure/MarkdownLexer.ts +111 -0
- package/packages/markdown/src/structure/MarkdownParser.ts +34 -0
- package/packages/markdown/src/syntax/alert.ts +46 -0
- package/packages/markdown/src/syntax/blockquote.ts +35 -0
- package/packages/markdown/src/syntax/bold.ts +11 -0
- package/packages/markdown/src/syntax/code.ts +11 -0
- package/packages/markdown/src/syntax/codeblock.ts +44 -0
- package/packages/markdown/src/syntax/heading.ts +14 -0
- package/packages/markdown/src/syntax/horizontalRule.ts +11 -0
- package/packages/markdown/src/syntax/image.ts +23 -0
- package/packages/markdown/src/syntax/italic.ts +11 -0
- package/packages/markdown/src/syntax/link.ts +46 -0
- package/packages/markdown/src/syntax/list.ts +121 -0
- package/packages/markdown/src/syntax/table.ts +67 -0
- package/packages/markdown/src/syntax/text.ts +19 -0
- package/packages/match/package.json +15 -0
- package/packages/match/src/global.ts +14 -0
- package/packages/match/src/index.ts +33 -0
- package/packages/match/src/structure/Case.ts +15 -0
- package/packages/match/src/structure/Default.ts +12 -0
- package/packages/match/src/structure/Match.ts +78 -0
- package/packages/meta/package.json +14 -0
- package/packages/meta/src/index.ts +36 -0
- package/packages/meta/src/lib/resolveMeta.ts +27 -0
- package/packages/meta/src/types.ts +36 -0
- package/packages/prefetch/package.json +14 -0
- package/packages/prefetch/src/index.ts +70 -0
- package/packages/router/README.md +18 -0
- package/packages/router/package.json +16 -0
- package/packages/router/src/global.ts +22 -0
- package/packages/router/src/index.ts +106 -0
- package/packages/router/src/structure/Link.ts +17 -0
- package/packages/router/src/structure/NavLink.ts +19 -0
- package/packages/router/src/structure/Page.ts +30 -0
- package/packages/router/src/structure/Route.ts +123 -0
- package/packages/router/src/structure/RouteGroup.ts +24 -0
- package/packages/router/src/structure/RouteNode.ts +54 -0
- package/packages/router/src/structure/RouteSlot.ts +34 -0
- package/packages/router/src/structure/Router.ts +192 -0
- package/packages/router/src/structure/RouterConstructor.ts +18 -0
- package/packages/router/src/types.ts +41 -0
- package/packages/signal/README.md +93 -0
- package/packages/signal/package.json +15 -0
- package/packages/signal/src/index.ts +97 -0
- package/packages/signal/src/lib/track.ts +18 -0
- package/packages/signal/src/structure/Signal.ts +59 -0
- package/packages/ui/package.json +14 -0
- package/packages/ui/src/index.ts +4 -0
- package/packages/ui/src/lib/slideshowAnimations.ts +39 -0
- package/packages/ui/src/structure/Radio.ts +77 -0
- package/packages/ui/src/structure/Slide.ts +11 -0
- package/packages/ui/src/structure/Slideshow.ts +99 -0
- package/packages/utils/package.json +18 -0
- package/packages/utils/src/global.ts +39 -0
- package/packages/utils/src/index.bun.ts +3 -0
- package/packages/utils/src/index.ts +2 -0
- package/packages/utils/src/lib/debugger.ts +14 -0
- package/packages/utils/src/lib/utils.ts +119 -0
- package/packages/utils/src/structure/UID.ts +18 -0
- package/packages/widget/README.md +29 -0
- package/packages/widget/package.json +14 -0
- package/packages/widget/src/index.ts +82 -0
- package/packages/widget/src/structure/Widget.ts +42 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { HORIZONTAL_RULE } from "#lib/type";
|
|
2
|
+
import { setBlockTokenizer, setProcessor } from "#lib/util";
|
|
3
|
+
import type { MarkdownLexer } from "#structure/MarkdownLexer";
|
|
4
|
+
import type { MarkdownParser } from "#structure/MarkdownParser";
|
|
5
|
+
|
|
6
|
+
export const horizontalRuleProcessor = (parser: MarkdownParser) => setProcessor(parser, HORIZONTAL_RULE, _ => `<hr>`)
|
|
7
|
+
|
|
8
|
+
export const horizontalRuleTokenizer = (lexer: MarkdownLexer) => setBlockTokenizer(lexer, HORIZONTAL_RULE, {
|
|
9
|
+
regex: /^---/,
|
|
10
|
+
handle: _ => ({ content: [] })
|
|
11
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IMAGE } from "#lib/type";
|
|
2
|
+
import { setInlineTokenizer, setProcessor } from "#lib/util";
|
|
3
|
+
import type { MarkdownLexer } from "#structure/MarkdownLexer";
|
|
4
|
+
import type { MarkdownParser } from "#structure/MarkdownParser";
|
|
5
|
+
|
|
6
|
+
export const imageProcessor = (parser: MarkdownParser) => setProcessor(parser, IMAGE, token => {
|
|
7
|
+
const { url, title } = token.data!;
|
|
8
|
+
return `<img alt="${parser.parse(token.content!)}" src="${url}"${title ? ` title="${title}"` : ''}>`
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
export const imageTokenizer = (lexer: MarkdownLexer) => setInlineTokenizer(lexer, IMAGE, {
|
|
12
|
+
regex: /^!\[(.+?)\]\((.+?)\)/,
|
|
13
|
+
handle: matches => {
|
|
14
|
+
const [_, alt, detail] = matches as [string, string, string];
|
|
15
|
+
const [__, url, title] = detail.match(/(\w\w+?:\/\/[^\s]+)(?: "(.+?)")?/) as [string, string, string];
|
|
16
|
+
return {
|
|
17
|
+
content: lexer.inlineTokenize(alt),
|
|
18
|
+
data: {
|
|
19
|
+
url, title
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ITALIC } from "#lib/type";
|
|
2
|
+
import { setInlineTokenizer, setProcessor } from "#lib/util";
|
|
3
|
+
import type { MarkdownLexer } from "#structure/MarkdownLexer";
|
|
4
|
+
import type { MarkdownParser } from "#structure/MarkdownParser";
|
|
5
|
+
|
|
6
|
+
export const italicProcessor = (parser: MarkdownParser) => setProcessor(parser, ITALIC, token => `<i>${parser.parse(token.content!)}</i>`)
|
|
7
|
+
|
|
8
|
+
export const italicTokenizer = (lexer: MarkdownLexer) => setInlineTokenizer(lexer, ITALIC, {
|
|
9
|
+
regex: /\*(.+?)\*/,
|
|
10
|
+
handle: matches => ({ content: lexer.inlineTokenize(matches[1]!) })
|
|
11
|
+
})
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { LINK, QUICK_LINK } from "#lib/type";
|
|
2
|
+
import { setInlineTokenizer, setProcessor } from "#lib/util";
|
|
3
|
+
import type { MarkdownLexer, Token } from "#structure/MarkdownLexer";
|
|
4
|
+
import type { MarkdownParser } from "#structure/MarkdownParser";
|
|
5
|
+
import { isUndefined } from "@amateras/utils";
|
|
6
|
+
|
|
7
|
+
export const linkProcessor = (parser: MarkdownParser) => {
|
|
8
|
+
const linkProcessor = (token: Token) => {
|
|
9
|
+
const {href, email, title} = token.data!;
|
|
10
|
+
return `<a href="${isUndefined(href) ? `mailto:${email}` : href}"${title ? ` title="${title}"` : ''}>${token.text ?? parser.parse(token.content!)}</a>`
|
|
11
|
+
}
|
|
12
|
+
setProcessor(parser, QUICK_LINK, linkProcessor)
|
|
13
|
+
setProcessor(parser, LINK, linkProcessor)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const linkTokenizer = (lexer: MarkdownLexer) => {
|
|
17
|
+
|
|
18
|
+
setInlineTokenizer(lexer, LINK, {
|
|
19
|
+
regex: /\[(.+?)\]\(((?:\w+?@(?:\w|\.\w)+)|(?:\w\w+?:[^\s)]+))(?: "(.+)?")?\)/,
|
|
20
|
+
handle: matches => {
|
|
21
|
+
const [_, alt, detail, title] = matches as [string, string, string, string];
|
|
22
|
+
const match = detail.match(/(?:\w+?@(?:\w|\.\w)+)|(?:\w\w+?:\/\/[^\s]+)/);
|
|
23
|
+
const [resolver] = match!;
|
|
24
|
+
const email_or_href = resolver.includes('@') ? { email: resolver }: { href: resolver };
|
|
25
|
+
return {
|
|
26
|
+
content: lexer.inlineTokenize(alt),
|
|
27
|
+
data: {
|
|
28
|
+
title, ...email_or_href
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
setInlineTokenizer(lexer, QUICK_LINK, {
|
|
34
|
+
regex: /<((?:\w+?@(?:\w|\.\w)+)|(?:\w\w+?:[^\s>]+))>/,
|
|
35
|
+
handle: matches => {
|
|
36
|
+
const [_, detail] = matches as [string, string];
|
|
37
|
+
const match = detail.match(/(?:\w+?@(?:\w|\.\w)+)|(?:\w\w+?:\/\/[^\s]+)/);
|
|
38
|
+
const [resolver] = match!;
|
|
39
|
+
const email_or_href = resolver.includes('@') ? { email: resolver }: { href: resolver };
|
|
40
|
+
return {
|
|
41
|
+
content: resolver,
|
|
42
|
+
data: email_or_href
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { EMPTY_LINE, ORDERED_LIST_ITEM, TEXT_LINE, UNORDERED_LIST_ITEM } from "#lib/type";
|
|
2
|
+
import { htmltag, setBlockTokenizer, setProcessor } from "#lib/util";
|
|
3
|
+
import type { MarkdownLexer, Token } from "#structure/MarkdownLexer";
|
|
4
|
+
import type { MarkdownParser } from "#structure/MarkdownParser";
|
|
5
|
+
import { isEqual, isString } from "@amateras/utils";
|
|
6
|
+
|
|
7
|
+
export const listProcessor = (parser: MarkdownParser) => {
|
|
8
|
+
const listType = (type: string) => type === ORDERED_LIST_ITEM ? 'ol' : 'ul'
|
|
9
|
+
const listProcessor = (token: Token, tokens: Token[]) => {
|
|
10
|
+
let i = 0;
|
|
11
|
+
// cache the list by deep number
|
|
12
|
+
const deepListMap = new Map<number, List>();
|
|
13
|
+
|
|
14
|
+
const listGenerator = (type: string, deep: number) => {
|
|
15
|
+
const getList = deepListMap.get(deep)
|
|
16
|
+
const list = getList && listType(type) === getList.tagname ? getList : List(listType(type), []);
|
|
17
|
+
deepListMap.set(deep, list);
|
|
18
|
+
|
|
19
|
+
while (i < tokens.length) {
|
|
20
|
+
const token = tokens[i]!;
|
|
21
|
+
const tokenType = token.type;
|
|
22
|
+
// if token type not equal list item / empty line / text line, then finish loop
|
|
23
|
+
if (!isEqual(tokenType, [ORDERED_LIST_ITEM, UNORDERED_LIST_ITEM, EMPTY_LINE, TEXT_LINE])) { i--; break};
|
|
24
|
+
// if token type equal text line
|
|
25
|
+
if (tokenType === TEXT_LINE) {
|
|
26
|
+
const text = token.content![0]?.text;
|
|
27
|
+
// if text start with double space
|
|
28
|
+
if (text?.match(/^\s\s/)) {
|
|
29
|
+
const match = text.match(/^(\s+)(.+)?/)!;
|
|
30
|
+
// if no content, then next token
|
|
31
|
+
if (!match[2]) { i++; continue }
|
|
32
|
+
token.data = { deep: Math.trunc(match[1]!.length / 2) - 1 }
|
|
33
|
+
}
|
|
34
|
+
// if text start with tab
|
|
35
|
+
else if (text?.match(/^\t/)) {
|
|
36
|
+
const match = text.match(/^(\t+)(.+)?/)!;
|
|
37
|
+
// if no content, then next token
|
|
38
|
+
if (!match[2]) { i++; continue }
|
|
39
|
+
token.data = { deep: match[1]!.length - 1 }
|
|
40
|
+
}
|
|
41
|
+
// else break
|
|
42
|
+
else {i--; break};
|
|
43
|
+
}
|
|
44
|
+
// if token type equal empty line, jump to next token
|
|
45
|
+
if (tokenType === EMPTY_LINE) i++;
|
|
46
|
+
// if token deep number not equal latest deep of list
|
|
47
|
+
else if (token.data!.deep !== deep) {
|
|
48
|
+
// if bigger, push deeper list into current list item
|
|
49
|
+
if (token.data!.deep > deep) deepListMap.get(deep)?.items.at(-1)?.content.push(listGenerator(tokenType, token.data!.deep))
|
|
50
|
+
// else delete current deep cache and return to upper list
|
|
51
|
+
else { deepListMap.delete(deep); break; }
|
|
52
|
+
}
|
|
53
|
+
// if token type equal text line, convert this list to paragraph mode
|
|
54
|
+
else if (tokenType === TEXT_LINE) {
|
|
55
|
+
list.paragraph = true;
|
|
56
|
+
list.items.at(-1)?.content.push(parser.parse(token.content!))
|
|
57
|
+
i++
|
|
58
|
+
}
|
|
59
|
+
// if list type not equal, then finish loop
|
|
60
|
+
else if (tokenType !== type) {
|
|
61
|
+
deepListMap.delete(deep);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
// push list item
|
|
65
|
+
else {
|
|
66
|
+
list.items.push(ListItem([parser.parse(token.content!)]));
|
|
67
|
+
i++
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return list;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
html: `${listGenerator(token.type, token.data!.deep)}`,
|
|
75
|
+
skipTokens: i
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface ListItem { content: (string | List)[], toString(): string }
|
|
80
|
+
const ListItem = (content: (string | List)[]): ListItem => ({
|
|
81
|
+
content: content,
|
|
82
|
+
toString() { return htmltag('li', this.content.join('')) }
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
interface List { tagname: string, items: ListItem[], paragraph: boolean, toString(): string }
|
|
86
|
+
const List = (tagname: 'ul' | 'ol', items: ListItem[]): List => ({
|
|
87
|
+
tagname: tagname,
|
|
88
|
+
items: items,
|
|
89
|
+
paragraph: false,
|
|
90
|
+
toString() {
|
|
91
|
+
if (this.paragraph) this.items.forEach(item => item.content.forEach((text, i) => isString(text) && (item.content[i] = htmltag('p', text))))
|
|
92
|
+
return htmltag(this.tagname, this.items.join(''))
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
setProcessor(parser, UNORDERED_LIST_ITEM, listProcessor);
|
|
97
|
+
setProcessor(parser, ORDERED_LIST_ITEM, listProcessor);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const listTokenizer = (lexer: MarkdownLexer) => {
|
|
101
|
+
const listHandle = (matches: RegExpMatchArray) => {
|
|
102
|
+
const prefix = matches[0].split(/[-*]/)[0]!;
|
|
103
|
+
const spaces = prefix.match(/\s/)?.length ?? 0;
|
|
104
|
+
const tabs = prefix.match(/\t/)?.length ?? 0;
|
|
105
|
+
return ({
|
|
106
|
+
content: lexer.inlineTokenize(matches[1]!),
|
|
107
|
+
data: {
|
|
108
|
+
deep: Math.trunc(tabs + spaces / 2)
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
setBlockTokenizer(lexer, UNORDERED_LIST_ITEM, {
|
|
113
|
+
regex: /^(?:[\s\t]+)?[-*] (.+)/,
|
|
114
|
+
handle: listHandle
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
setBlockTokenizer(lexer, ORDERED_LIST_ITEM, {
|
|
118
|
+
regex: /^(?:[\s\t]+)?\d+\. (.+)/,
|
|
119
|
+
handle: listHandle
|
|
120
|
+
})
|
|
121
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { BLOCK, TABLE, TABLE_COLUMN, TABLE_ROW } from "#lib/type";
|
|
2
|
+
import { htmltag, setBlockTokenizer, setProcessor } from "#lib/util";
|
|
3
|
+
import type { BlockToken, MarkdownLexer } from "#structure/MarkdownLexer";
|
|
4
|
+
import type { MarkdownParser } from "#structure/MarkdownParser";
|
|
5
|
+
import { _Array_from } from "@amateras/utils";
|
|
6
|
+
|
|
7
|
+
export const tableProcessor = (parser: MarkdownParser) => setProcessor(parser, TABLE, (token) => {
|
|
8
|
+
let thead = '';
|
|
9
|
+
let tbody = '';
|
|
10
|
+
let rowIndex = 0;
|
|
11
|
+
for (const row of token.content!) {
|
|
12
|
+
let rowHTML = '';
|
|
13
|
+
for (let i = 0; i < row.content!.length; i++) {
|
|
14
|
+
const col = row.content![i]!;
|
|
15
|
+
const align = token.data!.align[i];
|
|
16
|
+
const tagname = rowIndex === 0 ? 'th' : 'td';
|
|
17
|
+
rowHTML += `<${tagname} align="${align ?? 'left'}">${parser.parse(col.content!)}</${tagname}>`
|
|
18
|
+
}
|
|
19
|
+
if (rowIndex === 0) thead += htmltag('thead', htmltag('tr', rowHTML));
|
|
20
|
+
else tbody += htmltag('tr', rowHTML);
|
|
21
|
+
rowIndex++
|
|
22
|
+
}
|
|
23
|
+
tbody = htmltag('tbody', tbody);
|
|
24
|
+
return htmltag('table', thead + tbody)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export const tableTokenizer = (lexer: MarkdownLexer) => setBlockTokenizer(lexer, TABLE, {
|
|
28
|
+
regex: /\|(?:.+\|)+/,
|
|
29
|
+
handle(_, position, lines) {
|
|
30
|
+
const tokens: BlockToken[] = [];
|
|
31
|
+
const align = []
|
|
32
|
+
while (position < lines.length) {
|
|
33
|
+
const row: BlockToken = {
|
|
34
|
+
type: TABLE_ROW,
|
|
35
|
+
layout: BLOCK,
|
|
36
|
+
content: []
|
|
37
|
+
}
|
|
38
|
+
const line = lines[position]!;
|
|
39
|
+
const matches = _Array_from(line.matchAll(/\| ([^|]+)/g));
|
|
40
|
+
if (!matches.length) break;
|
|
41
|
+
for (const match of matches) {
|
|
42
|
+
const text = match[1]!;
|
|
43
|
+
const separator = text.match(/(:)?---+(:)?/);
|
|
44
|
+
if (separator) {
|
|
45
|
+
const [_, LEFT, RIGHT] = separator;
|
|
46
|
+
align.push(RIGHT ? LEFT ? 'center' : 'right' : 'left');
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
row.content.push({
|
|
50
|
+
type: TABLE_COLUMN,
|
|
51
|
+
content: lexer.inlineTokenize(text.trim()),
|
|
52
|
+
layout: BLOCK
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
if (row.content.length) tokens.push(row);
|
|
56
|
+
position++
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
content: tokens,
|
|
60
|
+
data: { align },
|
|
61
|
+
multiLine: {
|
|
62
|
+
skip: position,
|
|
63
|
+
tokens: []
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EMPTY_LINE, TEXT, TEXT_LINE } from "#lib/type";
|
|
2
|
+
import { htmltag, setProcessor } from "#lib/util";
|
|
3
|
+
import type { MarkdownParser } from "#structure/MarkdownParser";
|
|
4
|
+
|
|
5
|
+
export const textProcessor = (parser: MarkdownParser) => setProcessor(parser, TEXT, token => token.text!);
|
|
6
|
+
|
|
7
|
+
export const textLineProcessor = (parser: MarkdownParser) => setProcessor(parser, TEXT_LINE, (_, tokens) => {
|
|
8
|
+
let html = '';
|
|
9
|
+
let i = 0;
|
|
10
|
+
for (const token of tokens) {
|
|
11
|
+
if (token.type === EMPTY_LINE) break;
|
|
12
|
+
html += parser.parse(token.content!);
|
|
13
|
+
i++;
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
html: htmltag('p', html),
|
|
17
|
+
skipTokens: i
|
|
18
|
+
};
|
|
19
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@amateras/match",
|
|
3
|
+
"peerDependencies": {
|
|
4
|
+
"@amateras/core": "workspace:*",
|
|
5
|
+
"@amateras/signal": "workspace:*",
|
|
6
|
+
"@amateras/utils": "workspace:*"
|
|
7
|
+
},
|
|
8
|
+
"imports": {
|
|
9
|
+
"#structure/*": "./src/structure/*.ts",
|
|
10
|
+
"#lib/*": "./src/lib/*.ts"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./src/index.ts"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as _Case from "#structure/Case";
|
|
2
|
+
import * as _Default from "#structure/Default";
|
|
3
|
+
import * as _Match from "#structure/Match";
|
|
4
|
+
import type { Signal } from "@amateras/signal";
|
|
5
|
+
|
|
6
|
+
declare global {
|
|
7
|
+
export var Match: typeof _Match.Match
|
|
8
|
+
export var Case: typeof _Case.Case
|
|
9
|
+
export var Default: typeof _Default.Default
|
|
10
|
+
|
|
11
|
+
export function $<T>(Match: typeof _Match.Match, expression: Signal<T>, layout: _Match.MatchLayout<T>): _Match.Match<T>
|
|
12
|
+
export function $(Case: typeof _Case.Case, condition: any, layout: _Case.CaseLayout): _Case.Case;
|
|
13
|
+
export function $(Default: typeof _Default.Default, layout: _Default.DefaultLayout): _Default.Default;
|
|
14
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Case } from "#structure/Case";
|
|
2
|
+
import { Default } from "#structure/Default";
|
|
3
|
+
import { Match } from "#structure/Match";
|
|
4
|
+
import { Proto } from '@amateras/core';
|
|
5
|
+
import { _instanceof, is, isEqual } from '@amateras/utils';
|
|
6
|
+
import './global';
|
|
7
|
+
|
|
8
|
+
globalThis.Match = Match;
|
|
9
|
+
globalThis.Case = Case;
|
|
10
|
+
globalThis.Default = Default;
|
|
11
|
+
|
|
12
|
+
$.process.craft.add((value, arg1, arg2) => {
|
|
13
|
+
if (import.meta.hot) {
|
|
14
|
+
if (_instanceof(Proto.proto, Match)) {
|
|
15
|
+
if (!isEqual(value, [Case, Default])) throw 'Match layout only includes Case and Default';
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
if (value === Case) throw 'Case must be inside Match layout';
|
|
19
|
+
if (value === Default) throw 'Default must be inside Match layout';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (value === Match) {
|
|
23
|
+
let proto = new Match(arg1, arg2);
|
|
24
|
+
proto.parent = Proto.proto;
|
|
25
|
+
return proto
|
|
26
|
+
}
|
|
27
|
+
if (value === Case) {
|
|
28
|
+
return is(Proto.proto, Match)?.case(arg1, arg2)
|
|
29
|
+
}
|
|
30
|
+
if (value === Default) {
|
|
31
|
+
return is(Proto.proto, Match)?.default(arg1)
|
|
32
|
+
}
|
|
33
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { symbol_Statement } from "@amateras/core";
|
|
2
|
+
import { Proto } from "@amateras/core";
|
|
3
|
+
import { isArray } from "@amateras/utils";
|
|
4
|
+
|
|
5
|
+
export type CaseLayout = () => void;
|
|
6
|
+
|
|
7
|
+
export class Case extends Proto {
|
|
8
|
+
static override [symbol_Statement] = true;
|
|
9
|
+
declare statementType: 'Case';
|
|
10
|
+
condition: any[]
|
|
11
|
+
constructor(condition: any, layout: CaseLayout) {
|
|
12
|
+
super(layout);
|
|
13
|
+
this.condition = isArray(condition) ? condition : [condition];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { symbol_Statement } from "@amateras/core";
|
|
2
|
+
import { Proto } from "@amateras/core";
|
|
3
|
+
|
|
4
|
+
export type DefaultLayout = () => void;
|
|
5
|
+
|
|
6
|
+
export class Default extends Proto {
|
|
7
|
+
static override [symbol_Statement] = true;
|
|
8
|
+
declare statementType: 'Default';
|
|
9
|
+
constructor(layout: DefaultLayout) {
|
|
10
|
+
super(layout);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { symbol_Statement } from "@amateras/core";
|
|
2
|
+
import { ProxyProto } from "@amateras/core";
|
|
3
|
+
import type { Signal } from "@amateras/signal";
|
|
4
|
+
import { _null, forEach } from "@amateras/utils";
|
|
5
|
+
import { Case, type CaseLayout } from "./Case";
|
|
6
|
+
import { Default, type DefaultLayout } from "./Default";
|
|
7
|
+
|
|
8
|
+
export type MatchLayout<T> = (match: MatchCraftFunction<T>) => void;
|
|
9
|
+
export interface MatchCraftFunction<T> {
|
|
10
|
+
(d: typeof Default, layout: DefaultLayout): void;
|
|
11
|
+
(c: typeof Case, condition: T | T[], layout: CaseLayout): void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class Match<T = any> extends ProxyProto {
|
|
15
|
+
static override [symbol_Statement] = true;
|
|
16
|
+
declare statementType: 'Match';
|
|
17
|
+
exp$: Signal<T>
|
|
18
|
+
declare protos: Set<Case>;
|
|
19
|
+
cases = new Set<Case>();
|
|
20
|
+
matched: Case | Default | null = _null;
|
|
21
|
+
#default: Default | null = _null;
|
|
22
|
+
constructor(expression: Signal<T>, layout: MatchLayout<T>) {
|
|
23
|
+
super(() => {
|
|
24
|
+
layout((constructor, arg1, arg2?) => {
|
|
25
|
+
$(constructor as any, arg1, arg2);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
this.exp$ = expression;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override build(): this {
|
|
32
|
+
super.build();
|
|
33
|
+
this.validate();
|
|
34
|
+
// update function for Signal subscribe
|
|
35
|
+
let update = () => {
|
|
36
|
+
let prevMatchedProto = this.matched;
|
|
37
|
+
let matchProto = this.validate();
|
|
38
|
+
if (prevMatchedProto === matchProto) return;
|
|
39
|
+
forEach(this.cases, proto => proto !== matchProto && proto.removeNode())
|
|
40
|
+
if (matchProto !== this.#default) this.#default?.removeNode();
|
|
41
|
+
this.node?.replaceWith(...this.toDOM());
|
|
42
|
+
}
|
|
43
|
+
// build cases proto and subscribe expression signal
|
|
44
|
+
forEach(this.cases, proto => {
|
|
45
|
+
proto.build();
|
|
46
|
+
this.exp$.subscribe(update);
|
|
47
|
+
proto.disposers.add(() => this.exp$.unsubscribe(update));
|
|
48
|
+
})
|
|
49
|
+
this.#default?.build();
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
case(condition: T, layout: CaseLayout) {
|
|
54
|
+
let caseProto = new Case(condition, layout);
|
|
55
|
+
this.cases.add(caseProto);
|
|
56
|
+
return caseProto;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
default(layout: DefaultLayout) {
|
|
60
|
+
let defaultProto = new Default(layout);
|
|
61
|
+
this.#default = defaultProto;
|
|
62
|
+
return defaultProto;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
validate() {
|
|
66
|
+
this.clear();
|
|
67
|
+
for (let proto of this.cases) {
|
|
68
|
+
if (proto.condition.includes(this.exp$.value)) {
|
|
69
|
+
proto.parent = this;
|
|
70
|
+
return this.matched = proto;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (this.#default) {
|
|
74
|
+
this.#default.parent = this;
|
|
75
|
+
return this.matched = this.#default;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@amateras/meta",
|
|
3
|
+
"peerDependencies": {
|
|
4
|
+
"@amateras/core": "workspace:*",
|
|
5
|
+
"@amateras/utils": "workspace:*"
|
|
6
|
+
},
|
|
7
|
+
"imports": {
|
|
8
|
+
"#structure/*": "./src/structure/*.ts",
|
|
9
|
+
"#lib/*": "./src/lib/*.ts"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./src/index.ts"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { resolveMeta } from "#lib/resolveMeta";
|
|
2
|
+
import { onclient, onserver } from "@amateras/core";
|
|
3
|
+
import { Proto } from "@amateras/core";
|
|
4
|
+
import { _Object_assign } from "@amateras/utils";
|
|
5
|
+
import type { MetaConfig } from "./types";
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
export namespace $ {
|
|
9
|
+
function meta(config: MetaConfig): void
|
|
10
|
+
|
|
11
|
+
export namespace meta {
|
|
12
|
+
function resolve(config: MetaConfig): void
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare module '@amateras/core' {
|
|
19
|
+
export interface GlobalState {
|
|
20
|
+
meta: MetaConfig;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_Object_assign($, {
|
|
25
|
+
meta(config: MetaConfig) {
|
|
26
|
+
if (onclient()) return;
|
|
27
|
+
let proto = Proto.proto;
|
|
28
|
+
if (proto) proto.global.meta = config;
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
if (onserver()) {
|
|
33
|
+
_Object_assign($.meta, {
|
|
34
|
+
resolve: resolveMeta
|
|
35
|
+
})
|
|
36
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { _Object_entries, forEach, isArray, isString } from "@amateras/utils";
|
|
2
|
+
import type { MetaConfig, MetaOutput } from "../types";
|
|
3
|
+
|
|
4
|
+
export function resolveMeta(config: MetaConfig) {
|
|
5
|
+
let metaList: MetaOutput[] = [];
|
|
6
|
+
|
|
7
|
+
let {description, og, twitter} = config;
|
|
8
|
+
if (description) metaList.push({name: 'description', content: description});
|
|
9
|
+
if (og) determine(og, metaList, 'og', 'property');
|
|
10
|
+
if (twitter) determine(twitter as any, metaList, 'twitter', 'name')
|
|
11
|
+
return metaList;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const determine = (obj: MetaConfig, metaList: MetaOutput[], context: string, propName: 'name' | 'property') => {
|
|
15
|
+
let getProperty = (property: string) => context ? `${context}:${property}` : property;
|
|
16
|
+
let push = (property: string, content: string) => metaList.push({[propName]: getProperty(property), content} as MetaOutput);
|
|
17
|
+
for (const [property, content] of _Object_entries(obj)) {
|
|
18
|
+
if (isString(content)) push(property, content);
|
|
19
|
+
else {
|
|
20
|
+
if (isArray(content)) forEach(content as [], c => {
|
|
21
|
+
if (isString(c)) push(property, c);
|
|
22
|
+
else determine(c, metaList, getProperty(property), propName)
|
|
23
|
+
});
|
|
24
|
+
else determine(content as any, metaList, getProperty(property), propName);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type MetaConfig = {
|
|
2
|
+
description?: string;
|
|
3
|
+
og?: {
|
|
4
|
+
title?: string;
|
|
5
|
+
type?: string;
|
|
6
|
+
image?: string | string[] | OpenGraphMediaConfig | OpenGraphMediaConfig[];
|
|
7
|
+
url?: string;
|
|
8
|
+
audio?: string | string[] | OpenGraphAudioConfig | OpenGraphAudioConfig[];
|
|
9
|
+
description?: string;
|
|
10
|
+
determiner?: string;
|
|
11
|
+
locale?: string | {
|
|
12
|
+
alternate?: string;
|
|
13
|
+
};
|
|
14
|
+
site_name?: string;
|
|
15
|
+
video?: string | string[] | OpenGraphVideoConfig | OpenGraphVideoConfig[];
|
|
16
|
+
}
|
|
17
|
+
twitter?: {
|
|
18
|
+
card?: 'summary' | 'summary_large_image' | 'app' | 'player';
|
|
19
|
+
site?: `@${string}`;
|
|
20
|
+
creator?: `@${string}`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type OpenGraphMediaConfig = {
|
|
25
|
+
url?: string;
|
|
26
|
+
secure_url?: string;
|
|
27
|
+
type?: string;
|
|
28
|
+
width?: string;
|
|
29
|
+
height?: string;
|
|
30
|
+
alt?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type OpenGraphAudioConfig = Pick<OpenGraphMediaConfig, 'url' | 'secure_url' | 'type'>;
|
|
34
|
+
export type OpenGraphVideoConfig = Omit<OpenGraphMediaConfig, 'alt'>
|
|
35
|
+
|
|
36
|
+
export type MetaOutput = {property: string, content: string} | {name: string, content: string};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@amateras/prefetch",
|
|
3
|
+
"peerDependencies": {
|
|
4
|
+
"@amateras/core": "workspace:*",
|
|
5
|
+
"@amateras/utils": "workspace:*"
|
|
6
|
+
},
|
|
7
|
+
"imports": {
|
|
8
|
+
"#structure/*": "./src/structure/*.ts",
|
|
9
|
+
"#lib/*": "./src/lib/*.ts"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./src/index.ts"
|
|
13
|
+
}
|
|
14
|
+
}
|