@ryusenkei/maezae 0.2.0 → 0.3.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.
- package/README.md +2 -0
- package/dist/analytics.d.ts +1 -0
- package/dist/analytics.js +33 -0
- package/dist/body.d.ts +1 -24
- package/dist/body.js +1 -333
- package/dist/declared-9_jI3JXH.js +336 -0
- package/dist/delivery.d.ts +1 -211
- package/dist/integrations.d.ts +1 -72
- package/dist/integrations.js +12 -2
- package/dist/model.d.ts +1 -82
- package/dist/model.js +339 -1
- package/dist/preview.d.ts +1 -2
- package/dist/preview.js +1 -1
- package/dist/{src-CA_67dWy.js → src-Baj-EC2G.js} +105 -3
- package/dist/trace.d.ts +1 -0
- package/dist/trace.js +1 -0
- package/dist/types/access/src/index.d.ts +5 -0
- package/dist/types/access/src/jwt.d.ts +42 -0
- package/dist/types/access/src/oidc.d.ts +47 -0
- package/dist/types/access/src/signed.d.ts +47 -0
- package/dist/types/access/src/span.d.ts +23 -0
- package/dist/types/access/src/traceparent.d.ts +21 -0
- package/dist/types/analytics/src/day.d.ts +2 -0
- package/dist/types/analytics/src/index.d.ts +4 -0
- package/dist/types/analytics/src/record.d.ts +22 -0
- package/dist/types/analytics/src/schedule.d.ts +2 -0
- package/dist/types/analytics/src/source.d.ts +33 -0
- package/dist/types/analytics/src/store.d.ts +24 -0
- package/dist/types/body/src/components.d.ts +25 -0
- package/dist/types/body/src/declared.d.ts +34 -0
- package/dist/types/body/src/derive.d.ts +13 -0
- package/dist/types/body/src/description.d.ts +8 -0
- package/dist/types/body/src/href.d.ts +4 -0
- package/dist/types/body/src/index.d.ts +11 -0
- package/dist/types/body/src/library.d.ts +94 -0
- package/dist/types/body/src/markdown.d.ts +14 -0
- package/dist/types/body/src/normalize.d.ts +7 -0
- package/dist/types/body/src/profile.d.ts +48 -0
- package/dist/types/body/src/schema.d.ts +6 -0
- package/dist/types/body/src/standard.d.ts +20 -0
- package/dist/types/body/src/types.d.ts +91 -0
- package/dist/types/cms-contract/src/apiKeys.d.ts +13 -0
- package/dist/types/cms-contract/src/assets.d.ts +10 -0
- package/dist/types/cms-contract/src/builtins.d.ts +17 -0
- package/dist/types/cms-contract/src/embeds.d.ts +56 -0
- package/dist/types/cms-contract/src/errorLabels.d.ts +22 -0
- package/dist/types/cms-contract/src/errors.d.ts +97 -0
- package/dist/types/cms-contract/src/extensions.d.ts +75 -0
- package/dist/types/cms-contract/src/fieldRules.d.ts +37 -0
- package/dist/types/cms-contract/src/functions.d.ts +71 -0
- package/dist/types/cms-contract/src/index.d.ts +19 -0
- package/dist/types/cms-contract/src/labels.d.ts +6 -0
- package/dist/types/cms-contract/src/modules.d.ts +144 -0
- package/dist/types/cms-contract/src/paths.d.ts +6 -0
- package/dist/types/cms-contract/src/pending.d.ts +4 -0
- package/dist/types/cms-contract/src/permissions.d.ts +69 -0
- package/dist/types/cms-contract/src/roles.d.ts +35 -0
- package/dist/types/cms-contract/src/settings.d.ts +19 -0
- package/dist/types/cms-contract/src/transfer.d.ts +48 -0
- package/dist/types/cms-contract/src/views.d.ts +21 -0
- package/dist/types/cms-contract/src/webhooks.d.ts +45 -0
- package/dist/types/delivery-client/src/client.d.ts +63 -0
- package/dist/types/delivery-client/src/index.d.ts +5 -0
- package/dist/types/delivery-client/src/media.d.ts +12 -0
- package/dist/types/delivery-client/src/query.d.ts +68 -0
- package/dist/types/delivery-client/src/schema.d.ts +19 -0
- package/dist/types/delivery-client/src/values.d.ts +63 -0
- package/dist/types/model/src/asset.d.ts +89 -0
- package/dist/types/model/src/capabilities.d.ts +20 -0
- package/dist/types/model/src/changes.d.ts +23 -0
- package/dist/types/model/src/check.d.ts +10 -0
- package/dist/types/model/src/image.d.ts +38 -0
- package/dist/types/model/src/index.d.ts +14 -0
- package/dist/types/model/src/input.d.ts +26 -0
- package/dist/types/model/src/media.d.ts +5 -0
- package/dist/types/model/src/model.d.ts +194 -0
- package/dist/types/model/src/page.d.ts +47 -0
- package/dist/types/model/src/rules.d.ts +15 -0
- package/dist/types/model/src/schema.d.ts +3 -0
- package/dist/types/model/src/screens.d.ts +72 -0
- package/dist/types/model/src/time.d.ts +25 -0
- package/dist/types/model/src/values.d.ts +24 -0
- package/dist/types/sdk/src/analytics.d.ts +2 -0
- package/dist/types/sdk/src/body.d.ts +2 -0
- package/dist/types/sdk/src/defaults.d.ts +5 -0
- package/dist/types/sdk/src/delivery.d.ts +2 -0
- package/dist/types/sdk/src/integrations.d.ts +4 -0
- package/dist/types/sdk/src/model.d.ts +5 -0
- package/dist/types/sdk/src/preview.d.ts +2 -0
- package/dist/types/sdk/src/trace.d.ts +2 -0
- package/package.json +10 -2
- package/dist/index-C8duwjns.d.ts +0 -157
- package/dist/index-CLDe_wBc.d.ts +0 -340
- package/dist/signed-B_58gV21.d.ts +0 -44
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ maezae の SDK(導入先のサイト向け)
|
|
|
10
10
|
| `@ryusenkei/maezae/body` | 本文のブロックの型と描画の補助 |
|
|
11
11
|
| `@ryusenkei/maezae/model` | コンテンツスキーマの型・ページのパス・画像の切り抜き |
|
|
12
12
|
| `@ryusenkei/maezae/preview` | プレビューと下書きの取得の署名(ヘッダー `x-preview-signature`) |
|
|
13
|
+
| `@ryusenkei/maezae/analytics` | サイトの閲覧の記録(CMS の閲覧数の集計と同じ形式) |
|
|
14
|
+
| `@ryusenkei/maezae/trace` | CMS のログと相関を取るトレースの区間 |
|
|
13
15
|
| `@ryusenkei/maezae/integrations` | 外の関数・Webhook が受け取る本文の型と署名の検証(ヘッダー `x-cms-signature`) |
|
|
14
16
|
|
|
15
17
|
## 取得(Cloudflare Workers の service binding)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './types/sdk/src/analytics.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// ../analytics/src/day.ts
|
|
2
|
+
/** 時間帯 timeZone での日付(YYYY-MM-DD、例: timeZone は Asia/Tokyo) */
|
|
3
|
+
const dayIn = (timeZone, at = /* @__PURE__ */ new Date()) => new Intl.DateTimeFormat("en-CA", {
|
|
4
|
+
timeZone,
|
|
5
|
+
year: "numeric",
|
|
6
|
+
month: "2-digit",
|
|
7
|
+
day: "2-digit"
|
|
8
|
+
}).format(at);
|
|
9
|
+
// ../analytics/src/record.ts
|
|
10
|
+
const BOT = /bot|crawl|spider|slurp|preview|monitor|headless/i;
|
|
11
|
+
/** ボットの UA か */
|
|
12
|
+
const isBot = (userAgent) => BOT.test(userAgent ?? "");
|
|
13
|
+
/** 閲覧を1件記録(対象: GET で応答が200の HTML・ボット以外、記録の失敗は無視) */
|
|
14
|
+
function recordView(dataset, request, response, { classify, timeZone, tenant }) {
|
|
15
|
+
if (!dataset || request.method !== "GET" || response.status !== 200) return;
|
|
16
|
+
if (!response.headers.get("content-type")?.includes("text/html") || isBot(request.headers.get("user-agent"))) return;
|
|
17
|
+
const path = new URL(request.url).pathname;
|
|
18
|
+
const { kind, id } = classify(path);
|
|
19
|
+
try {
|
|
20
|
+
dataset.writeDataPoint({
|
|
21
|
+
blobs: [
|
|
22
|
+
kind,
|
|
23
|
+
id,
|
|
24
|
+
path,
|
|
25
|
+
dayIn(timeZone),
|
|
26
|
+
"view",
|
|
27
|
+
tenant ?? ""
|
|
28
|
+
],
|
|
29
|
+
indexes: [tenant ?? kind]
|
|
30
|
+
});
|
|
31
|
+
} catch {}
|
|
32
|
+
}
|
|
33
|
+
export { recordView };
|
package/dist/body.d.ts
CHANGED
|
@@ -1,24 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/** meta description の長さの上限(検索結果で省略されにくい字数の目安) */
|
|
3
|
-
export declare const DESCRIPTION_MAX = 120;
|
|
4
|
-
/**
|
|
5
|
-
* 説明を meta description の長さに調整
|
|
6
|
-
* - 上限を超える場合: 上限までの最後の句点まで
|
|
7
|
-
* - 句点がない場合: 上限で切って省略の記号
|
|
8
|
-
*/
|
|
9
|
-
export declare function descriptionOf(excerpt: string, max?: number): string;
|
|
10
|
-
/** 読了時間の既定の分速(字/分) */
|
|
11
|
-
export declare const READING_SPEED = 500;
|
|
12
|
-
/** 断片の列の文字(装飾・リンクは文字、インラインのコンポーネントは中の文字) */
|
|
13
|
-
export declare const plainOf: (rich: Rich) => string;
|
|
14
|
-
/** 本文の注が参照する出典の ID(出現の順、重複あり) */
|
|
15
|
-
export declare function citesOf<M>(body: Body<M>): string[];
|
|
16
|
-
/** 本文の導入の文字(最初の見出しまでの段落をつなげたもの、導入がなければ空) */
|
|
17
|
-
export declare function excerptOf<M>(body: Body<M>): string;
|
|
18
|
-
/** 読了時間(分、本文の文字列の字数を分速 speed で割った概算、1分以上) */
|
|
19
|
-
export declare const readMinOf: <M>(body: Body<M>, speed?: number) => number;
|
|
20
|
-
/** 本文にあるサイト内へのリンク先(`/` で始まる href、重複なし) */
|
|
21
|
-
export declare const linksOf: <M>(body: Body<M>) => string[];
|
|
22
|
-
/** 本文のリンク先として許可する形か(保存の検査とサイトの出力で共通) */
|
|
23
|
-
export declare const isSafeHref: (href: string) => boolean;
|
|
24
|
-
export { type Block, type Body, type ComponentBlock, type DeclaredComponent, type HeadingLevel, type Inline, type InlineComponent, type Link, type List, type ListItem, type Mark, type PropSchema, type PropType, type PropsSchema, type Rich, type StandardBlock, type Text, blockSchemaOf };
|
|
1
|
+
export * from './types/sdk/src/body.js';
|
package/dist/body.js
CHANGED
|
@@ -1,337 +1,5 @@
|
|
|
1
|
+
import { a as coreComponentOf, n as declaredPropsZod, r as CITE } from "./declared-9_jI3JXH.js";
|
|
1
2
|
import { z } from "zod";
|
|
2
|
-
// ../body/src/components.ts
|
|
3
|
-
/** 予約の名前(ブロック) */
|
|
4
|
-
const RESERVED_BLOCK_NAMES = /* @__PURE__ */ new Set(["block"]);
|
|
5
|
-
/** 予約の名前(インライン) */
|
|
6
|
-
const RESERVED_INLINE_NAMES = /* @__PURE__ */ new Set([
|
|
7
|
-
"mark",
|
|
8
|
-
"sup",
|
|
9
|
-
"sub",
|
|
10
|
-
"link"
|
|
11
|
-
]);
|
|
12
|
-
// ../body/src/library.ts
|
|
13
|
-
/** 注のコンポーネントの名前(本文からの算出 citesOf が参照) */
|
|
14
|
-
const CITE = "cite";
|
|
15
|
-
const https = z.string().regex(/^https:\/\//, "URL は https://");
|
|
16
|
-
const caption = z.string().min(1, "注記が未入力");
|
|
17
|
-
const datum = z.object({
|
|
18
|
-
label: z.string(),
|
|
19
|
-
value: z.number()
|
|
20
|
-
});
|
|
21
|
-
const color = z.union([
|
|
22
|
-
z.literal(1),
|
|
23
|
-
z.literal(2),
|
|
24
|
-
z.literal(3),
|
|
25
|
-
z.literal(4),
|
|
26
|
-
z.literal(5),
|
|
27
|
-
z.literal(6),
|
|
28
|
-
z.literal(7),
|
|
29
|
-
z.literal(8)
|
|
30
|
-
]);
|
|
31
|
-
const chart = z.union([
|
|
32
|
-
z.object({
|
|
33
|
-
chart: z.literal("bar"),
|
|
34
|
-
data: z.array(datum),
|
|
35
|
-
unit: z.string(),
|
|
36
|
-
color: color.optional(),
|
|
37
|
-
caption
|
|
38
|
-
}),
|
|
39
|
-
z.object({
|
|
40
|
-
chart: z.literal("line"),
|
|
41
|
-
labels: z.array(z.string()),
|
|
42
|
-
series: z.array(z.object({
|
|
43
|
-
name: z.string(),
|
|
44
|
-
values: z.array(z.number())
|
|
45
|
-
})),
|
|
46
|
-
unit: z.string(),
|
|
47
|
-
caption
|
|
48
|
-
}),
|
|
49
|
-
z.object({
|
|
50
|
-
chart: z.literal("pie"),
|
|
51
|
-
data: z.array(datum),
|
|
52
|
-
unit: z.string(),
|
|
53
|
-
caption
|
|
54
|
-
}),
|
|
55
|
-
z.object({
|
|
56
|
-
chart: z.literal("heat"),
|
|
57
|
-
cols: z.array(z.string()),
|
|
58
|
-
rows: z.array(z.object({
|
|
59
|
-
label: z.string(),
|
|
60
|
-
values: z.array(z.number())
|
|
61
|
-
})),
|
|
62
|
-
unit: z.string(),
|
|
63
|
-
color: color.optional(),
|
|
64
|
-
caption
|
|
65
|
-
})
|
|
66
|
-
]);
|
|
67
|
-
const optional = (attrs, keys) => Object.fromEntries(keys.filter((k) => attrs[k] !== void 0).map((k) => [k, attrs[k]]));
|
|
68
|
-
const plain = (rich) => rich.map((i) => typeof i === "string" ? i : "text" in i ? i.text ?? "" : "").join("");
|
|
69
|
-
/** 核のコンポーネント(chart の Markdown は既定の JSON) */
|
|
70
|
-
const CORE_COMPONENTS = [
|
|
71
|
-
{
|
|
72
|
-
name: CITE,
|
|
73
|
-
inline: true,
|
|
74
|
-
description: "注(出典の ID を参照、出典は記事に結び付けが必要)",
|
|
75
|
-
example: ":cite{#出典の ID}",
|
|
76
|
-
props: () => z.object({ id: z.string().min(1, "注の出典が未入力") })
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
name: "pending",
|
|
80
|
-
inline: true,
|
|
81
|
-
description: "未定の値(方針のページで値が決まっていない箇所)",
|
|
82
|
-
example: ":pending[未定]",
|
|
83
|
-
props: () => z.object({})
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
name: "speech",
|
|
87
|
-
description: "発言(会話の一言を大きく引く、1段落)",
|
|
88
|
-
example: ":::speech\n大きく引く一言\n:::",
|
|
89
|
-
markdown: {
|
|
90
|
-
to: (p) => ({ content: [{
|
|
91
|
-
type: "paragraph",
|
|
92
|
-
content: [p.text]
|
|
93
|
-
}] }),
|
|
94
|
-
from: (_, content) => ({ text: content[0]?.type === "paragraph" ? plain(content[0].content) : "" })
|
|
95
|
-
},
|
|
96
|
-
props: () => z.object({ text: z.string().min(1, "発言が未入力") })
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
name: "chart",
|
|
100
|
-
description: "グラフ(中は JSON、chart は bar・line・pie・heat、caption は必須)",
|
|
101
|
-
example: ":::chart\n```json\n{\"chart\": \"bar\", \"unit\": \"%\", \"data\": [{\"label\": \"A\", \"value\": 40}], \"caption\": \"説明\"}\n```\n:::",
|
|
102
|
-
props: () => chart
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
name: "diagram",
|
|
106
|
-
description: "図(中は Mermaid、alt は図の内容の説明、caption は必須)",
|
|
107
|
-
example: ":::diagram{alt=\"内容の説明\" caption=\"説明\"}\n```mermaid\nflowchart LR\n A --> B\n```\n:::",
|
|
108
|
-
markdown: {
|
|
109
|
-
to: (p) => ({
|
|
110
|
-
attributes: {
|
|
111
|
-
alt: p.alt,
|
|
112
|
-
caption: p.caption
|
|
113
|
-
},
|
|
114
|
-
content: [{
|
|
115
|
-
type: "code",
|
|
116
|
-
lang: "mermaid",
|
|
117
|
-
code: p.source
|
|
118
|
-
}]
|
|
119
|
-
}),
|
|
120
|
-
from: (attrs, content) => ({
|
|
121
|
-
source: content[0]?.type === "code" ? content[0].code : "",
|
|
122
|
-
alt: attrs.alt ?? "",
|
|
123
|
-
caption: attrs.caption ?? ""
|
|
124
|
-
})
|
|
125
|
-
},
|
|
126
|
-
props: () => z.object({
|
|
127
|
-
source: z.string().min(1, "図の記法が未入力"),
|
|
128
|
-
alt: z.string().min(1, "図の代替テキストが未入力"),
|
|
129
|
-
caption
|
|
130
|
-
})
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: "gallery",
|
|
134
|
-
description: "複数の画像を2列で配置(画像は2枚以上)",
|
|
135
|
-
example: ":::gallery\n\n\n\n:::",
|
|
136
|
-
markdown: {
|
|
137
|
-
to: (p) => ({ content: p.items.map((i) => ({
|
|
138
|
-
type: "image",
|
|
139
|
-
media: i.media,
|
|
140
|
-
...i.caption ? { caption: i.caption } : {}
|
|
141
|
-
})) }),
|
|
142
|
-
from: (_, content) => ({ items: content.flatMap((b) => b.type === "image" ? [{
|
|
143
|
-
media: b.media,
|
|
144
|
-
...b.caption ? { caption: b.caption } : {}
|
|
145
|
-
}] : []) })
|
|
146
|
-
},
|
|
147
|
-
props: (media) => z.object({ items: z.array(z.object({
|
|
148
|
-
media,
|
|
149
|
-
caption: z.string().optional()
|
|
150
|
-
})).min(2, "ギャラリーの画像は2枚以上") })
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
name: "link-card",
|
|
154
|
-
description: "外部リンクのカード(https のみ、site・desc・画像は任意)",
|
|
155
|
-
example: ":::link-card{href=\"https://…\" title=\"ページの題\" site=\"サイト名\" desc=\"説明\"}\n:::",
|
|
156
|
-
markdown: {
|
|
157
|
-
to: (p) => {
|
|
158
|
-
const { href, title, site, desc, image } = p;
|
|
159
|
-
return {
|
|
160
|
-
attributes: {
|
|
161
|
-
href,
|
|
162
|
-
title,
|
|
163
|
-
...site ? { site } : {},
|
|
164
|
-
...desc ? { desc } : {}
|
|
165
|
-
},
|
|
166
|
-
content: image ? [{
|
|
167
|
-
type: "image",
|
|
168
|
-
media: image
|
|
169
|
-
}] : []
|
|
170
|
-
};
|
|
171
|
-
},
|
|
172
|
-
from: (attrs, content) => ({
|
|
173
|
-
href: attrs.href,
|
|
174
|
-
title: attrs.title,
|
|
175
|
-
...optional(attrs, ["site", "desc"]),
|
|
176
|
-
...content[0]?.type === "image" ? { image: content[0].media } : {}
|
|
177
|
-
})
|
|
178
|
-
},
|
|
179
|
-
props: (media) => z.object({
|
|
180
|
-
href: https,
|
|
181
|
-
title: z.string().min(1, "リンクのタイトルが未入力"),
|
|
182
|
-
site: z.string().optional(),
|
|
183
|
-
desc: z.string().optional(),
|
|
184
|
-
image: media.optional()
|
|
185
|
-
})
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
name: "links",
|
|
189
|
-
description: "外部リンクの一覧(1件1行、リンクの title はサイト名、label は小見出しで既定は「参考」)",
|
|
190
|
-
example: ":::links{label=\"参考\"}\n- [ページの題](https://… \"サイト名\")\n:::",
|
|
191
|
-
markdown: {
|
|
192
|
-
to: (p) => {
|
|
193
|
-
const { label, items } = p;
|
|
194
|
-
const content = [{
|
|
195
|
-
type: "list",
|
|
196
|
-
items: items.map((i) => ({ content: [{
|
|
197
|
-
text: i.title,
|
|
198
|
-
link: {
|
|
199
|
-
href: i.href,
|
|
200
|
-
...i.site ? { title: i.site } : {}
|
|
201
|
-
}
|
|
202
|
-
}] }))
|
|
203
|
-
}];
|
|
204
|
-
return {
|
|
205
|
-
attributes: label ? { label } : void 0,
|
|
206
|
-
content
|
|
207
|
-
};
|
|
208
|
-
},
|
|
209
|
-
from: (attrs, content) => ({
|
|
210
|
-
...optional(attrs, ["label"]),
|
|
211
|
-
items: content[0]?.type === "list" ? content[0].items.flatMap((i) => i.content.flatMap((x) => typeof x !== "string" && "link" in x && x.link ? [{
|
|
212
|
-
href: x.link.href,
|
|
213
|
-
title: x.text,
|
|
214
|
-
...x.link.title ? { site: x.link.title } : {}
|
|
215
|
-
}] : [])) : []
|
|
216
|
-
})
|
|
217
|
-
},
|
|
218
|
-
props: () => z.object({
|
|
219
|
-
label: z.string().optional(),
|
|
220
|
-
items: z.array(z.object({
|
|
221
|
-
href: https,
|
|
222
|
-
title: z.string().min(1, "リンクのタイトルが未入力"),
|
|
223
|
-
site: z.string().optional()
|
|
224
|
-
}))
|
|
225
|
-
})
|
|
226
|
-
}
|
|
227
|
-
];
|
|
228
|
-
/** 名前から核のコンポーネント(なければ undefined) */
|
|
229
|
-
const coreComponentOf = (name) => CORE_COMPONENTS.find((c) => c.name === name);
|
|
230
|
-
// ../body/src/declared.ts
|
|
231
|
-
const NAME = /^[A-Za-z][A-Za-z0-9-]*$/;
|
|
232
|
-
const KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
233
|
-
const propSchema = z.lazy(() => z.object({
|
|
234
|
-
type: z.enum([
|
|
235
|
-
"string",
|
|
236
|
-
"number",
|
|
237
|
-
"integer",
|
|
238
|
-
"boolean",
|
|
239
|
-
"array",
|
|
240
|
-
"object"
|
|
241
|
-
]),
|
|
242
|
-
title: z.string().min(1).optional(),
|
|
243
|
-
description: z.string().optional(),
|
|
244
|
-
enum: z.array(z.string().min(1)).min(1).optional(),
|
|
245
|
-
items: propSchema.optional(),
|
|
246
|
-
properties: z.record(z.string().regex(KEY, "引数の名前は英字で始まる英数字"), propSchema).optional(),
|
|
247
|
-
required: z.array(z.string()).optional()
|
|
248
|
-
}).strict().superRefine((p, ctx) => {
|
|
249
|
-
if (p.enum && p.type !== "string") ctx.addIssue({
|
|
250
|
-
code: "custom",
|
|
251
|
-
message: "選択肢 enum は文字列の引数だけ",
|
|
252
|
-
path: ["enum"]
|
|
253
|
-
});
|
|
254
|
-
if (p.type === "array" !== (p.items !== void 0)) ctx.addIssue({
|
|
255
|
-
code: "custom",
|
|
256
|
-
message: "配列の引数は items が必要(ほかの型は不可)",
|
|
257
|
-
path: ["items"]
|
|
258
|
-
});
|
|
259
|
-
if ((p.properties || p.required) && p.type !== "object") ctx.addIssue({
|
|
260
|
-
code: "custom",
|
|
261
|
-
message: "properties・required はオブジェクトの引数だけ",
|
|
262
|
-
path: ["properties"]
|
|
263
|
-
});
|
|
264
|
-
for (const key of p.required ?? []) if (!p.properties?.[key]) ctx.addIssue({
|
|
265
|
-
code: "custom",
|
|
266
|
-
message: `必須の引数 ${key} が properties にない`,
|
|
267
|
-
path: ["required"]
|
|
268
|
-
});
|
|
269
|
-
}));
|
|
270
|
-
const declaredComponent = z.object({
|
|
271
|
-
name: z.string().regex(NAME, "部品の名前は英字で始まる英数字とハイフン"),
|
|
272
|
-
label: z.string().min(1, "部品の表示名が未入力"),
|
|
273
|
-
description: z.string().optional(),
|
|
274
|
-
inline: z.boolean().optional(),
|
|
275
|
-
props: z.object({
|
|
276
|
-
type: z.literal("object"),
|
|
277
|
-
properties: z.record(z.string().regex(KEY, "引数の名前は英字で始まる英数字"), propSchema),
|
|
278
|
-
required: z.array(z.string()).optional()
|
|
279
|
-
}).strict()
|
|
280
|
-
}).strict().superRefine((d, ctx) => {
|
|
281
|
-
if (coreComponentOf(d.name) || RESERVED_BLOCK_NAMES.has(d.name) || RESERVED_INLINE_NAMES.has(d.name)) ctx.addIssue({
|
|
282
|
-
code: "custom",
|
|
283
|
-
message: `部品の名前 ${d.name} はコアの部品・予約の名前と重複`,
|
|
284
|
-
path: ["name"]
|
|
285
|
-
});
|
|
286
|
-
for (const key of d.props.required ?? []) if (!d.props.properties[key]) ctx.addIssue({
|
|
287
|
-
code: "custom",
|
|
288
|
-
message: `必須の引数 ${key} が properties にない`,
|
|
289
|
-
path: ["props", "required"]
|
|
290
|
-
});
|
|
291
|
-
if (d.inline) {
|
|
292
|
-
for (const [key, p] of Object.entries(d.props.properties)) if (p.type !== "string") ctx.addIssue({
|
|
293
|
-
code: "custom",
|
|
294
|
-
message: `インラインの部品の引数は文字列だけ: ${key}`,
|
|
295
|
-
path: [
|
|
296
|
-
"props",
|
|
297
|
-
"properties",
|
|
298
|
-
key
|
|
299
|
-
]
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
z.array(declaredComponent).superRefine((list, ctx) => {
|
|
304
|
-
const seen = /* @__PURE__ */ new Set();
|
|
305
|
-
list.forEach((d, i) => {
|
|
306
|
-
if (seen.has(d.name)) ctx.addIssue({
|
|
307
|
-
code: "custom",
|
|
308
|
-
message: `部品の名前 ${d.name} が重複`,
|
|
309
|
-
path: [i, "name"]
|
|
310
|
-
});
|
|
311
|
-
seen.add(d.name);
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
/** 1つの引数の検査(label はメッセージの項目名) */
|
|
315
|
-
function propZod(p, label) {
|
|
316
|
-
const wrong = { error: (iss) => iss.input === void 0 ? `${label}が未入力` : `${label}の形が不正` };
|
|
317
|
-
switch (p.type) {
|
|
318
|
-
case "string": return p.enum ? z.enum(p.enum, wrong) : z.string(wrong);
|
|
319
|
-
case "number": return z.number(wrong);
|
|
320
|
-
case "integer": return z.number(wrong).int(`${label}は整数`);
|
|
321
|
-
case "boolean": return z.boolean(wrong);
|
|
322
|
-
case "array": return z.array(propZod(p.items, label), wrong);
|
|
323
|
-
case "object": return objectZod(p.properties ?? {}, p.required ?? [], wrong);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
/** オブジェクトの引数の検査(必須でない引数は省略可、宣言にない引数は除去) */
|
|
327
|
-
const objectZod = (properties, required, error) => z.object(Object.fromEntries(Object.entries(properties).map(([key, p]) => [key, required.includes(key) ? propZod(p, p.title ?? key) : propZod(p, p.title ?? key).optional()])), error);
|
|
328
|
-
const propsCache = /* @__PURE__ */ new WeakMap();
|
|
329
|
-
/** 宣言した部品の引数の検査(宣言ごとに作成を再利用) */
|
|
330
|
-
function declaredPropsZod(d) {
|
|
331
|
-
let schema = propsCache.get(d);
|
|
332
|
-
if (!schema) propsCache.set(d, schema = objectZod(d.props.properties, d.props.required ?? [], { error: () => `${d.label}の引数の形が不正` }));
|
|
333
|
-
return schema;
|
|
334
|
-
}
|
|
335
3
|
// ../body/src/description.ts
|
|
336
4
|
/** meta description の長さの上限(検索結果で省略されにくい字数の目安) */
|
|
337
5
|
const DESCRIPTION_MAX = 120;
|