@mirascript/help 0.1.80 → 0.1.82
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/package.json +2 -2
- package/scripts/{build.js → build.ts} +66 -52
- package/scripts/tsconfig.json +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirascript/help",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.82",
|
|
4
4
|
"author": "CloudPSS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Help documentation for Mirascript core language.",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"js-yaml": "^5.2.3"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
|
-
"build": "pnpm clean && node ./scripts/build.
|
|
31
|
+
"build": "pnpm clean && node ./scripts/build.ts",
|
|
32
32
|
"clean": "rimraf dist"
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -16,67 +16,90 @@ const distRoot = path.join(packageRoot, 'dist');
|
|
|
16
16
|
* ---
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
* @param {string} relativePath
|
|
22
|
-
* @returns {Promise<string>}
|
|
23
|
-
*/
|
|
24
|
-
async function readMarkdown(relativePath) {
|
|
19
|
+
/** Read a markdown file under `src/`. */
|
|
20
|
+
async function readMarkdown(relativePath: string): Promise<string> {
|
|
25
21
|
const fullPath = path.join(srcRoot, relativePath);
|
|
26
22
|
return await readFile(fullPath, 'utf8');
|
|
27
23
|
}
|
|
28
24
|
|
|
29
25
|
const FRONT_MATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n/;
|
|
30
26
|
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
/** Front-matter attributes of a markdown doc. */
|
|
28
|
+
interface FrontMatter {
|
|
29
|
+
/** The token(s) mapped to the doc body. */
|
|
30
|
+
token?: unknown;
|
|
31
|
+
/** Fallback token when `token` is missing. */
|
|
32
|
+
title?: unknown;
|
|
33
|
+
/** Whether the token is reserved and must be skipped. */
|
|
34
|
+
reserved?: unknown;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A doc item before the token is normalized to a string. */
|
|
38
|
+
interface RawDocItem {
|
|
39
|
+
/** The token, possibly an array of tokens. */
|
|
40
|
+
token: string | string[];
|
|
41
|
+
/** The markdown body. */
|
|
42
|
+
body: string;
|
|
43
|
+
/** Whether the token is reserved. */
|
|
44
|
+
reserved: boolean;
|
|
45
|
+
/** The source file relative path. */
|
|
46
|
+
file: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** A doc item with a normalized string token. */
|
|
50
|
+
interface DocItem {
|
|
51
|
+
/** The token. */
|
|
52
|
+
token: string;
|
|
53
|
+
/** The markdown body. */
|
|
54
|
+
body: string;
|
|
55
|
+
/** Whether the token is reserved. */
|
|
56
|
+
reserved: boolean;
|
|
57
|
+
/** The source file relative path. */
|
|
58
|
+
file: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Extract front-matter and strip it from markdown. */
|
|
62
|
+
function splitFrontMatter(markdown: string, relativePath: string): { attributes: FrontMatter; body: string } {
|
|
38
63
|
const m = FRONT_MATTER_RE.exec(markdown);
|
|
39
64
|
if (!m) {
|
|
40
65
|
throw new Error(`Missing front-matter in ${relativePath}. Add token/order mapping.`);
|
|
41
66
|
}
|
|
42
67
|
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
// The regex guarantees both groups exist when `m` is truthy.
|
|
69
|
+
const yaml = m[1];
|
|
70
|
+
const fullMatch = m[0];
|
|
71
|
+
if (yaml === undefined || fullMatch === undefined) {
|
|
72
|
+
throw new Error(`Missing front-matter in ${relativePath}. Add token/order mapping.`);
|
|
73
|
+
}
|
|
74
|
+
const attributes = load(yaml) as FrontMatter;
|
|
75
|
+
let body = markdown.slice(fullMatch.length);
|
|
45
76
|
// Trim leading newlines and tailing newlines
|
|
46
77
|
body = body.replace(/^\r?\n+/, '').replace(/\r?\n+$/, '') + '\n';
|
|
47
78
|
return { attributes, body };
|
|
48
79
|
}
|
|
49
80
|
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
* @param {string} folder
|
|
53
|
-
* @returns {Promise<Array<[string, string]>>}
|
|
54
|
-
*/
|
|
55
|
-
async function loadDocsFromFolder(folder) {
|
|
81
|
+
/** Load docs under a folder like `keyword` or `operator`. */
|
|
82
|
+
async function loadDocsFromFolder(folder: string): Promise<Array<[string, string]>> {
|
|
56
83
|
const dirPath = path.join(srcRoot, folder);
|
|
57
84
|
const dirents = await readdir(dirPath, { withFileTypes: true });
|
|
58
85
|
|
|
59
|
-
|
|
60
|
-
const items = [];
|
|
86
|
+
const items: DocItem[] = [];
|
|
61
87
|
|
|
62
|
-
/**
|
|
63
|
-
|
|
64
|
-
* @param {{ token: string | string[]; body: string; reserved: boolean; file: string }} item
|
|
65
|
-
*/
|
|
66
|
-
function putItem(item) {
|
|
88
|
+
/** Check and add an item. */
|
|
89
|
+
function putItem(item: RawDocItem): void {
|
|
67
90
|
if (Array.isArray(item.token)) {
|
|
68
91
|
for (const token of item.token) {
|
|
69
92
|
items.push({ token, body: item.body, reserved: item.reserved, file: item.file });
|
|
70
93
|
}
|
|
71
94
|
return;
|
|
72
95
|
}
|
|
73
|
-
if (
|
|
96
|
+
if (!item.token.length) {
|
|
74
97
|
throw new TypeError(`Invalid front-matter field 'token' in ${item.file}`);
|
|
75
98
|
}
|
|
76
99
|
if (item.reserved) {
|
|
77
100
|
return; // skip reserved tokens
|
|
78
101
|
}
|
|
79
|
-
items.push(item);
|
|
102
|
+
items.push({ token: item.token, body: item.body, reserved: item.reserved, file: item.file });
|
|
80
103
|
}
|
|
81
104
|
|
|
82
105
|
for (const dirent of dirents) {
|
|
@@ -86,13 +109,15 @@ async function loadDocsFromFolder(folder) {
|
|
|
86
109
|
const relativePath = path.posix.join(folder, dirent.name);
|
|
87
110
|
const markdown = await readMarkdown(relativePath);
|
|
88
111
|
const { attributes, body } = splitFrontMatter(markdown, relativePath);
|
|
89
|
-
const
|
|
90
|
-
|
|
112
|
+
const token = attributes.token ?? attributes.title;
|
|
113
|
+
if (typeof token !== 'string' && !Array.isArray(token)) {
|
|
114
|
+
throw new TypeError(`Invalid front-matter field 'token' in ${relativePath}`);
|
|
115
|
+
}
|
|
116
|
+
putItem({ token, body, reserved: Boolean(attributes.reserved), file: relativePath });
|
|
91
117
|
}
|
|
92
118
|
|
|
93
|
-
const seenToken = new Set();
|
|
94
|
-
|
|
95
|
-
const entries = [];
|
|
119
|
+
const seenToken = new Set<string>();
|
|
120
|
+
const entries: Array<[string, string]> = [];
|
|
96
121
|
for (const item of items) {
|
|
97
122
|
if (seenToken.has(item.token)) {
|
|
98
123
|
throw new Error(`Duplicate token '${item.token}' (found in ${item.file})`);
|
|
@@ -104,32 +129,21 @@ async function loadDocsFromFolder(folder) {
|
|
|
104
129
|
return entries;
|
|
105
130
|
}
|
|
106
131
|
|
|
107
|
-
/**
|
|
108
|
-
|
|
109
|
-
* @param {Array<[string, string]>} entries
|
|
110
|
-
* @returns {string}
|
|
111
|
-
*/
|
|
112
|
-
function renderObjectLiteral(entries) {
|
|
132
|
+
/** Render an object literal with string keys and raw markdown values. */
|
|
133
|
+
function renderObjectLiteral(entries: Array<[string, string]>): string {
|
|
113
134
|
const lines = entries.map(([k, v]) => ` ${JSON.stringify(k)}: ${JSON.stringify(v)},`);
|
|
114
135
|
lines.unshift(' __proto__: null,');
|
|
115
136
|
return `Object.freeze({\n${lines.join('\n')}\n})`;
|
|
116
137
|
}
|
|
117
138
|
|
|
118
|
-
/**
|
|
119
|
-
|
|
120
|
-
* @param {Array<[string, string]>} entries
|
|
121
|
-
* @returns {string}
|
|
122
|
-
*/
|
|
123
|
-
function renderDtsObjectType(entries) {
|
|
139
|
+
/** Render a `.d.ts` object type with explicit string-literal keys. */
|
|
140
|
+
function renderDtsObjectType(entries: Array<[string, string]>): string {
|
|
124
141
|
const lines = entries.map(([k]) => ` readonly ${JSON.stringify(k)}: string;`);
|
|
125
142
|
return `{\n${lines.join('\n')}\n}`;
|
|
126
143
|
}
|
|
127
144
|
|
|
128
|
-
/**
|
|
129
|
-
|
|
130
|
-
* @returns {Promise<void>}
|
|
131
|
-
*/
|
|
132
|
-
async function main() {
|
|
145
|
+
/** Build `dist/index.js` and `dist/index.d.ts`. */
|
|
146
|
+
async function main(): Promise<void> {
|
|
133
147
|
const keywordEntries = await loadDocsFromFolder('keyword');
|
|
134
148
|
const operatorEntries = await loadDocsFromFolder('operator');
|
|
135
149
|
|