fuma-content 0.0.0 → 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.
- package/dist/index.js +3 -4
- package/dist/internal.d.ts +9 -4
- package/dist/internal.js +378 -8
- package/package.json +2 -3
- package/dist/chunk-UDFHC2Y3.js +0 -347
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -55
package/dist/index.js
CHANGED
|
@@ -38,10 +38,9 @@ function json(entryPoint, options) {
|
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
function createError(file, err) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
);
|
|
41
|
+
const message = `${file}:
|
|
42
|
+
${Object.entries(err.flatten().fieldErrors).map(([k, v]) => `${k}: ${v?.join(", ")}`).join("\n")}`;
|
|
43
|
+
return new Error(message);
|
|
45
44
|
}
|
|
46
45
|
function read(entryPoint, format, include) {
|
|
47
46
|
const cast = entryPoint;
|
package/dist/internal.d.ts
CHANGED
|
@@ -19,14 +19,20 @@ interface Options extends ProcessorOptions {
|
|
|
19
19
|
*/
|
|
20
20
|
lastModifiedTime?: "git" | "none";
|
|
21
21
|
/**
|
|
22
|
-
* @defaultValue `['frontmatter']`
|
|
22
|
+
* @defaultValue `['frontmatter', 'lastModified']`
|
|
23
23
|
*/
|
|
24
24
|
remarkExports?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Convert relative imports into absolute imports
|
|
27
|
+
*
|
|
28
|
+
* @defaultValue true
|
|
29
|
+
*/
|
|
30
|
+
enableAbsoluteImport?: boolean;
|
|
25
31
|
}
|
|
26
32
|
/**
|
|
27
33
|
* Load MDX/markdown files
|
|
28
34
|
*/
|
|
29
|
-
declare const loadMDX: ({ lastModifiedTime, format: forceFormat, remarkExports, ...rest }?: Options) => Transformer;
|
|
35
|
+
declare const loadMDX: ({ lastModifiedTime, format: forceFormat, remarkExports, enableAbsoluteImport, ...rest }?: Options) => Transformer;
|
|
30
36
|
|
|
31
37
|
interface OutputEntry extends Output {
|
|
32
38
|
/**
|
|
@@ -98,6 +104,5 @@ type CreateCompilerOptions = Pick<Partial<CompilerOptions>, keyof typeof default
|
|
|
98
104
|
declare function createCompiler(options: CreateCompilerOptions): Promise<Compiler>;
|
|
99
105
|
|
|
100
106
|
declare const defaultConfig: CreateCompilerOptions;
|
|
101
|
-
declare const defaultConfigPath = "./fc.config.js";
|
|
102
107
|
|
|
103
|
-
export { type CreateCompilerOptions, type EntryPointOptions, type Options, createCompiler, defaultConfig,
|
|
108
|
+
export { type CreateCompilerOptions, type EntryPointOptions, type Options, createCompiler, defaultConfig, loadEntryPoint, loadMDX };
|
package/dist/internal.js
CHANGED
|
@@ -1,14 +1,384 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var defaultConfig = {
|
|
3
|
+
files: ["./content/**/*"]
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
// src/utils/path.ts
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import FastGlob from "fast-glob";
|
|
9
|
+
function getAbsolutePath(cwd, relativePath) {
|
|
10
|
+
return path.join(cwd, relativePath);
|
|
11
|
+
}
|
|
12
|
+
function getRelativePath(cwd, absolutePath) {
|
|
13
|
+
return slash(
|
|
14
|
+
path.join(
|
|
15
|
+
path.relative(cwd, path.dirname(absolutePath)),
|
|
16
|
+
path.basename(absolutePath)
|
|
17
|
+
)
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function getImportPath(absolutePath) {
|
|
21
|
+
return slash(absolutePath);
|
|
22
|
+
}
|
|
23
|
+
function slash(anyPath) {
|
|
24
|
+
const isExtendedLengthPath = anyPath.startsWith("\\\\?\\");
|
|
25
|
+
if (isExtendedLengthPath) {
|
|
26
|
+
return anyPath;
|
|
27
|
+
}
|
|
28
|
+
return anyPath.replaceAll("\\", "/");
|
|
29
|
+
}
|
|
30
|
+
async function globFiles({
|
|
31
|
+
cwd,
|
|
32
|
+
globOptions,
|
|
33
|
+
files
|
|
34
|
+
}) {
|
|
35
|
+
return FastGlob.glob(files, {
|
|
36
|
+
cwd,
|
|
37
|
+
...globOptions
|
|
38
|
+
}).then((result) => result.map((file) => getAbsolutePath(cwd, file)));
|
|
39
|
+
}
|
|
40
|
+
function getOutputPath({ options }, entry) {
|
|
41
|
+
return path.join(
|
|
42
|
+
options.cwd,
|
|
43
|
+
options.outputDir,
|
|
44
|
+
path.relative(options.cwd, path.dirname(entry.file)),
|
|
45
|
+
`${path.basename(entry.file, path.extname(entry.file))}${options.outputExt}`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/loader/mdx.ts
|
|
50
|
+
import { createProcessor } from "@mdx-js/mdx";
|
|
51
|
+
import grayMatter from "gray-matter";
|
|
52
|
+
|
|
53
|
+
// src/utils/git-timpstamp.ts
|
|
54
|
+
import path2 from "node:path";
|
|
55
|
+
import fs from "node:fs";
|
|
56
|
+
import { spawn } from "cross-spawn";
|
|
57
|
+
var cache = /* @__PURE__ */ new Map();
|
|
58
|
+
function getGitTimestamp(file) {
|
|
59
|
+
const cachedTimestamp = cache.get(file);
|
|
60
|
+
if (cachedTimestamp)
|
|
61
|
+
return Promise.resolve(cachedTimestamp);
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const cwd = path2.dirname(file);
|
|
64
|
+
if (!fs.existsSync(cwd)) {
|
|
65
|
+
resolve(void 0);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const fileName = path2.basename(file);
|
|
69
|
+
const child = spawn("git", ["log", "-1", '--pretty="%ai"', fileName], {
|
|
70
|
+
cwd
|
|
71
|
+
});
|
|
72
|
+
let output;
|
|
73
|
+
child.stdout.on("data", (d) => output = new Date(String(d)));
|
|
74
|
+
child.on("close", () => {
|
|
75
|
+
if (output)
|
|
76
|
+
cache.set(file, output);
|
|
77
|
+
resolve(output);
|
|
78
|
+
});
|
|
79
|
+
child.on("error", reject);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/remark-plugins/utils.ts
|
|
84
|
+
import { valueToEstree } from "estree-util-value-to-estree";
|
|
85
|
+
function getMdastExport(name, value) {
|
|
86
|
+
return {
|
|
87
|
+
type: "mdxjsEsm",
|
|
88
|
+
value: "",
|
|
89
|
+
data: {
|
|
90
|
+
estree: {
|
|
91
|
+
type: "Program",
|
|
92
|
+
sourceType: "module",
|
|
93
|
+
body: [
|
|
94
|
+
{
|
|
95
|
+
type: "ExportNamedDeclaration",
|
|
96
|
+
specifiers: [],
|
|
97
|
+
source: null,
|
|
98
|
+
declaration: {
|
|
99
|
+
type: "VariableDeclaration",
|
|
100
|
+
kind: "const",
|
|
101
|
+
declarations: [
|
|
102
|
+
{
|
|
103
|
+
type: "VariableDeclarator",
|
|
104
|
+
id: {
|
|
105
|
+
type: "Identifier",
|
|
106
|
+
name
|
|
107
|
+
},
|
|
108
|
+
init: valueToEstree(value)
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/remark-plugins/remark-exports.ts
|
|
120
|
+
function remarkMdxExport({ values }) {
|
|
121
|
+
return (tree, vfile) => {
|
|
122
|
+
for (const name of values) {
|
|
123
|
+
if (!(name in vfile.data))
|
|
124
|
+
return;
|
|
125
|
+
tree.children.unshift(getMdastExport(name, vfile.data[name]));
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/remark-plugins/remark-absolute-import.ts
|
|
131
|
+
import * as path3 from "node:path";
|
|
132
|
+
import { visit } from "unist-util-visit";
|
|
133
|
+
function remarkAbsoluteImport({ enabled }) {
|
|
134
|
+
return (tree, vfile) => {
|
|
135
|
+
if (!enabled)
|
|
136
|
+
return;
|
|
137
|
+
visit(tree, ["mdxjsEsm"], (node) => {
|
|
138
|
+
if (node.type !== "mdxjsEsm")
|
|
139
|
+
return;
|
|
140
|
+
const body = node.data?.estree?.body ?? [];
|
|
141
|
+
body.forEach((statement) => {
|
|
142
|
+
if (statement.type === "ImportDeclaration" && typeof statement.source.value === "string") {
|
|
143
|
+
const value = statement.source.value;
|
|
144
|
+
if (value.startsWith("./") || value.startsWith("../")) {
|
|
145
|
+
const replace = getImportPath(
|
|
146
|
+
path3.join(path3.dirname(vfile.path), value)
|
|
147
|
+
);
|
|
148
|
+
statement.source.value = replace;
|
|
149
|
+
statement.source.raw = JSON.stringify(replace);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/loader/mdx.ts
|
|
158
|
+
var cache2 = /* @__PURE__ */ new Map();
|
|
159
|
+
var loadMDX = ({
|
|
160
|
+
lastModifiedTime,
|
|
161
|
+
format: forceFormat,
|
|
162
|
+
remarkExports = ["frontmatter", "lastModified"],
|
|
163
|
+
enableAbsoluteImport = true,
|
|
164
|
+
...rest
|
|
165
|
+
} = {}) => {
|
|
166
|
+
return async (file, source) => {
|
|
167
|
+
const { content, data: frontmatter } = grayMatter(source);
|
|
168
|
+
const detectedFormat = file.endsWith(".mdx") ? "mdx" : "md";
|
|
169
|
+
const format = forceFormat ?? detectedFormat;
|
|
170
|
+
let timestamp;
|
|
171
|
+
let processor = cache2.get(format);
|
|
172
|
+
if (processor === void 0) {
|
|
173
|
+
processor = createProcessor({
|
|
174
|
+
format,
|
|
175
|
+
development: process.env.NODE_ENV === "development",
|
|
176
|
+
...rest,
|
|
177
|
+
remarkPlugins: [
|
|
178
|
+
...rest.remarkPlugins ?? [],
|
|
179
|
+
[remarkAbsoluteImport, { enabled: enableAbsoluteImport }],
|
|
180
|
+
[remarkMdxExport, { values: remarkExports }]
|
|
181
|
+
]
|
|
182
|
+
});
|
|
183
|
+
cache2.set(format, processor);
|
|
184
|
+
}
|
|
185
|
+
if (lastModifiedTime === "git")
|
|
186
|
+
timestamp = (await getGitTimestamp(file))?.getTime();
|
|
187
|
+
const vfile = await processor.process({
|
|
188
|
+
value: content,
|
|
189
|
+
path: file,
|
|
190
|
+
data: {
|
|
191
|
+
lastModified: timestamp,
|
|
192
|
+
frontmatter
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
content: String(vfile),
|
|
197
|
+
_mdx: {
|
|
198
|
+
vfile
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// src/loader/json.ts
|
|
205
|
+
var loadJson = () => {
|
|
206
|
+
return (_file, source) => {
|
|
207
|
+
const parsed = JSON.parse(source);
|
|
208
|
+
return {
|
|
209
|
+
content: `export default ${JSON.stringify(parsed)}`
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// src/compiler/emit.ts
|
|
215
|
+
import * as path4 from "node:path";
|
|
216
|
+
import * as fs2 from "node:fs/promises";
|
|
217
|
+
async function emit() {
|
|
218
|
+
const entires = await this.compile();
|
|
219
|
+
const emits = entires.map(async (entry) => this.emitEntry(entry));
|
|
220
|
+
this._emit = await Promise.all(emits);
|
|
221
|
+
}
|
|
222
|
+
async function emitEntry(entry) {
|
|
223
|
+
const outputPath = getOutputPath(this, entry);
|
|
224
|
+
await fs2.mkdir(path4.dirname(outputPath), { recursive: true });
|
|
225
|
+
await fs2.writeFile(outputPath, entry.content);
|
|
226
|
+
return {
|
|
227
|
+
...entry,
|
|
228
|
+
outputPath
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/compiler/compile.ts
|
|
233
|
+
import * as fs3 from "node:fs/promises";
|
|
234
|
+
import * as path5 from "node:path";
|
|
235
|
+
|
|
236
|
+
// src/loader/entry-point.ts
|
|
237
|
+
function loadEntryPoint(entries) {
|
|
238
|
+
const { mode = "import" } = this.options.entryPoint ?? {};
|
|
239
|
+
let content;
|
|
240
|
+
switch (mode) {
|
|
241
|
+
case "import":
|
|
242
|
+
content = generateImport(this, entries);
|
|
243
|
+
break;
|
|
244
|
+
default:
|
|
245
|
+
content = generateLazy(this, entries);
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
format: "js",
|
|
250
|
+
file: getAbsolutePath(this.options.cwd, "./index.js"),
|
|
251
|
+
content,
|
|
252
|
+
_entryPoint: {}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function generateImport(compiler, output) {
|
|
256
|
+
const { fullPath = false } = compiler.options.entryPoint ?? {};
|
|
257
|
+
const formats = /* @__PURE__ */ new Map();
|
|
258
|
+
output.forEach((entry, i) => {
|
|
259
|
+
const b = formats.get(entry.format) ?? { imports: [], entries: [] };
|
|
260
|
+
formats.set(entry.format, b);
|
|
261
|
+
const importPath = getImportPath(getOutputPath(compiler, entry));
|
|
262
|
+
const file = fullPath ? entry.file : getRelativePath(compiler.options.cwd, entry.file);
|
|
263
|
+
const name = `p_${i}`;
|
|
264
|
+
b.imports.push(`import * as ${name} from ${JSON.stringify(importPath)};`);
|
|
265
|
+
b.entries.push(`{
|
|
266
|
+
...${name},
|
|
267
|
+
format: ${JSON.stringify(entry.format)},
|
|
268
|
+
file: ${JSON.stringify(file)},
|
|
269
|
+
}`);
|
|
270
|
+
});
|
|
271
|
+
const imports = Array.from(formats.values()).flatMap((f) => f.imports).join("\n");
|
|
272
|
+
const entires = Array.from(formats.entries()).map(([k, v]) => `${k}: [${v.entries.join(",")}]`).join(",");
|
|
273
|
+
return `${imports}
|
|
274
|
+
export default {${entires}};`;
|
|
275
|
+
}
|
|
276
|
+
function generateLazy(compiler, output) {
|
|
277
|
+
const entries = [];
|
|
278
|
+
for (const entry of output) {
|
|
279
|
+
const fronmatter = entry._mdx ? entry._mdx.vfile.data.frontmatter : {};
|
|
280
|
+
const importPath = getImportPath(getOutputPath(compiler, entry));
|
|
281
|
+
const line = `{
|
|
282
|
+
file: ${JSON.stringify(entry.file)},
|
|
283
|
+
info: ${JSON.stringify(fronmatter)},
|
|
284
|
+
load: () => import(${JSON.stringify(importPath)})
|
|
285
|
+
}`;
|
|
286
|
+
entries.push(line);
|
|
287
|
+
}
|
|
288
|
+
return `export default [${entries.join(",\n")}]`;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/compiler/compile.ts
|
|
292
|
+
async function compile() {
|
|
293
|
+
this._output = await Promise.all(
|
|
294
|
+
this.files.map((file) => this.compileFile(file))
|
|
295
|
+
);
|
|
296
|
+
this._output.push(loadEntryPoint.call(this, this._output));
|
|
297
|
+
return this._output;
|
|
298
|
+
}
|
|
299
|
+
async function compileFile(file) {
|
|
300
|
+
const cache3 = this._cache.get(file);
|
|
301
|
+
if (cache3)
|
|
302
|
+
return cache3;
|
|
303
|
+
const format = path5.extname(file).slice(1);
|
|
304
|
+
const content = (await fs3.readFile(file)).toString();
|
|
305
|
+
const loader = this.loaders[format];
|
|
306
|
+
const output = await loader?.call(this, file, content);
|
|
307
|
+
if (!output) {
|
|
308
|
+
throw new Error(`Unknown format: ${format}`);
|
|
309
|
+
}
|
|
310
|
+
const entry = {
|
|
311
|
+
file,
|
|
312
|
+
format,
|
|
313
|
+
...output
|
|
314
|
+
};
|
|
315
|
+
this._cache.set(file, entry);
|
|
316
|
+
return entry;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/compiler/watch.ts
|
|
320
|
+
import { watch as watchFn } from "chokidar";
|
|
321
|
+
function watch() {
|
|
322
|
+
void this.emit();
|
|
323
|
+
const watcher = watchFn(this.options.files, { cwd: this.options.cwd });
|
|
324
|
+
watcher.on("all", (eventName, relativePath) => {
|
|
325
|
+
const absolutePath = getAbsolutePath(this.options.cwd, relativePath);
|
|
326
|
+
if (eventName === "add" && !this.files.includes(absolutePath)) {
|
|
327
|
+
this.files.push(absolutePath);
|
|
328
|
+
void this.emit();
|
|
329
|
+
}
|
|
330
|
+
if (eventName === "unlink") {
|
|
331
|
+
this.files = this.files.filter((file) => file !== absolutePath);
|
|
332
|
+
this._cache.delete(absolutePath);
|
|
333
|
+
void this.emit();
|
|
334
|
+
}
|
|
335
|
+
if (eventName === "change") {
|
|
336
|
+
console.log("update", relativePath);
|
|
337
|
+
this._cache.delete(absolutePath);
|
|
338
|
+
void this.compileFile(absolutePath).then(async (entry) => {
|
|
339
|
+
await this.emitEntry(entry);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
return watcher;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/compiler/index.ts
|
|
347
|
+
var defaultOptions = {
|
|
348
|
+
cwd: process.cwd(),
|
|
349
|
+
outputDir: "./dist",
|
|
350
|
+
outputExt: ".js"
|
|
351
|
+
};
|
|
352
|
+
async function createCompiler(options) {
|
|
353
|
+
const compilerOptions = {
|
|
354
|
+
...defaultOptions,
|
|
355
|
+
...options
|
|
356
|
+
};
|
|
357
|
+
const files = await globFiles(compilerOptions);
|
|
358
|
+
return {
|
|
359
|
+
files,
|
|
360
|
+
options: compilerOptions,
|
|
361
|
+
compile,
|
|
362
|
+
emitEntry,
|
|
363
|
+
watch,
|
|
364
|
+
emit,
|
|
365
|
+
compileFile,
|
|
366
|
+
loaders: createLoaders(compilerOptions),
|
|
367
|
+
_cache: /* @__PURE__ */ new Map()
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function createLoaders(options) {
|
|
371
|
+
const mdx = loadMDX(options.mdxOptions);
|
|
372
|
+
return {
|
|
373
|
+
mdx,
|
|
374
|
+
md: mdx,
|
|
375
|
+
json: loadJson(),
|
|
376
|
+
...options.loaders
|
|
377
|
+
};
|
|
378
|
+
}
|
|
8
379
|
export {
|
|
9
380
|
createCompiler,
|
|
10
381
|
defaultConfig,
|
|
11
|
-
defaultConfigPath,
|
|
12
382
|
loadEntryPoint,
|
|
13
383
|
loadMDX
|
|
14
384
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fuma-content",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.1",
|
|
4
4
|
"description": "Write content for web apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Content",
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"repository": "github:fuma-nama/fuma-content",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"type": "module",
|
|
12
|
-
"bin": "./dist/cli/index.js",
|
|
13
12
|
"author": "Fuma Nama",
|
|
14
13
|
"files": [
|
|
15
14
|
"dist/*"
|
|
@@ -36,12 +35,12 @@
|
|
|
36
35
|
"dependencies": {
|
|
37
36
|
"@mdx-js/mdx": "^3.0.0",
|
|
38
37
|
"chokidar": "^3.5.3",
|
|
39
|
-
"clipanion": "4.0.0-rc.3",
|
|
40
38
|
"cross-spawn": "^7.0.3",
|
|
41
39
|
"estree-util-value-to-estree": "^3.0.1",
|
|
42
40
|
"fast-glob": "^3.3.2",
|
|
43
41
|
"gray-matter": "^4.0.3",
|
|
44
42
|
"micromatch": "^4.0.5",
|
|
43
|
+
"unist-util-visit": "^5.0.0",
|
|
45
44
|
"zod": "^3.22.4"
|
|
46
45
|
},
|
|
47
46
|
"devDependencies": {
|
package/dist/chunk-UDFHC2Y3.js
DELETED
|
@@ -1,347 +0,0 @@
|
|
|
1
|
-
// src/constants.ts
|
|
2
|
-
var defaultConfig = {
|
|
3
|
-
files: ["./content/**/*"]
|
|
4
|
-
};
|
|
5
|
-
var defaultConfigPath = "./fc.config.js";
|
|
6
|
-
|
|
7
|
-
// src/loader/mdx.ts
|
|
8
|
-
import { createProcessor } from "@mdx-js/mdx";
|
|
9
|
-
import grayMatter from "gray-matter";
|
|
10
|
-
|
|
11
|
-
// src/utils/git-timpstamp.ts
|
|
12
|
-
import path from "node:path";
|
|
13
|
-
import fs from "node:fs";
|
|
14
|
-
import { spawn } from "cross-spawn";
|
|
15
|
-
var cache = /* @__PURE__ */ new Map();
|
|
16
|
-
function getGitTimestamp(file) {
|
|
17
|
-
const cachedTimestamp = cache.get(file);
|
|
18
|
-
if (cachedTimestamp)
|
|
19
|
-
return Promise.resolve(cachedTimestamp);
|
|
20
|
-
return new Promise((resolve, reject) => {
|
|
21
|
-
const cwd = path.dirname(file);
|
|
22
|
-
if (!fs.existsSync(cwd)) {
|
|
23
|
-
resolve(void 0);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const fileName = path.basename(file);
|
|
27
|
-
const child = spawn("git", ["log", "-1", '--pretty="%ai"', fileName], {
|
|
28
|
-
cwd
|
|
29
|
-
});
|
|
30
|
-
let output;
|
|
31
|
-
child.stdout.on("data", (d) => output = new Date(String(d)));
|
|
32
|
-
child.on("close", () => {
|
|
33
|
-
if (output)
|
|
34
|
-
cache.set(file, output);
|
|
35
|
-
resolve(output);
|
|
36
|
-
});
|
|
37
|
-
child.on("error", reject);
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// src/remark-plugins/utils.ts
|
|
42
|
-
import { valueToEstree } from "estree-util-value-to-estree";
|
|
43
|
-
function getMdastExport(name, value) {
|
|
44
|
-
return {
|
|
45
|
-
type: "mdxjsEsm",
|
|
46
|
-
value: "",
|
|
47
|
-
data: {
|
|
48
|
-
estree: {
|
|
49
|
-
type: "Program",
|
|
50
|
-
sourceType: "module",
|
|
51
|
-
body: [
|
|
52
|
-
{
|
|
53
|
-
type: "ExportNamedDeclaration",
|
|
54
|
-
specifiers: [],
|
|
55
|
-
source: null,
|
|
56
|
-
declaration: {
|
|
57
|
-
type: "VariableDeclaration",
|
|
58
|
-
kind: "const",
|
|
59
|
-
declarations: [
|
|
60
|
-
{
|
|
61
|
-
type: "VariableDeclarator",
|
|
62
|
-
id: {
|
|
63
|
-
type: "Identifier",
|
|
64
|
-
name
|
|
65
|
-
},
|
|
66
|
-
init: valueToEstree(value)
|
|
67
|
-
}
|
|
68
|
-
]
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
]
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// src/remark-plugins/remark-exports.ts
|
|
78
|
-
function remarkMdxExport({ values }) {
|
|
79
|
-
return (tree, vfile) => {
|
|
80
|
-
for (const name of values) {
|
|
81
|
-
if (!(name in vfile.data))
|
|
82
|
-
return;
|
|
83
|
-
tree.children.unshift(getMdastExport(name, vfile.data[name]));
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// src/loader/mdx.ts
|
|
89
|
-
var cache2 = /* @__PURE__ */ new Map();
|
|
90
|
-
var loadMDX = ({
|
|
91
|
-
lastModifiedTime,
|
|
92
|
-
format: forceFormat,
|
|
93
|
-
remarkExports = ["frontmatter"],
|
|
94
|
-
...rest
|
|
95
|
-
} = {}) => {
|
|
96
|
-
return async (filePath, source) => {
|
|
97
|
-
const { content, data: frontmatter } = grayMatter(source);
|
|
98
|
-
const detectedFormat = filePath.endsWith(".mdx") ? "mdx" : "md";
|
|
99
|
-
const format = forceFormat ?? detectedFormat;
|
|
100
|
-
let timestamp;
|
|
101
|
-
let processor = cache2.get(format);
|
|
102
|
-
if (processor === void 0) {
|
|
103
|
-
processor = createProcessor({
|
|
104
|
-
format,
|
|
105
|
-
development: process.env.NODE_ENV === "development",
|
|
106
|
-
...rest,
|
|
107
|
-
remarkPlugins: [
|
|
108
|
-
...rest.remarkPlugins ?? [],
|
|
109
|
-
[remarkMdxExport, { values: remarkExports }]
|
|
110
|
-
]
|
|
111
|
-
});
|
|
112
|
-
cache2.set(format, processor);
|
|
113
|
-
}
|
|
114
|
-
if (lastModifiedTime === "git")
|
|
115
|
-
timestamp = (await getGitTimestamp(filePath))?.getTime();
|
|
116
|
-
const file = await processor.process({
|
|
117
|
-
value: content,
|
|
118
|
-
path: filePath,
|
|
119
|
-
data: {
|
|
120
|
-
lastModified: timestamp,
|
|
121
|
-
frontmatter
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
return {
|
|
125
|
-
content: String(file),
|
|
126
|
-
_mdx: {
|
|
127
|
-
vfile: file
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
};
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
// src/loader/entry-point.ts
|
|
134
|
-
import { pathToFileURL } from "node:url";
|
|
135
|
-
|
|
136
|
-
// src/utils/path.ts
|
|
137
|
-
import * as path2 from "node:path";
|
|
138
|
-
import FastGlob from "fast-glob";
|
|
139
|
-
function getAbsolutePath(cwd, relativePath) {
|
|
140
|
-
return FastGlob.escapePath(path2.join(cwd, relativePath));
|
|
141
|
-
}
|
|
142
|
-
function getRelativePath(cwd, absolutePath) {
|
|
143
|
-
return path2.join(
|
|
144
|
-
path2.relative(cwd, path2.dirname(absolutePath)),
|
|
145
|
-
path2.basename(absolutePath)
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
async function globFiles({
|
|
149
|
-
cwd,
|
|
150
|
-
globOptions,
|
|
151
|
-
files
|
|
152
|
-
}) {
|
|
153
|
-
return FastGlob.glob(files, {
|
|
154
|
-
cwd,
|
|
155
|
-
...globOptions
|
|
156
|
-
}).then((result) => result.map((file) => getAbsolutePath(cwd, file)));
|
|
157
|
-
}
|
|
158
|
-
function getOutputPath({ options }, entry) {
|
|
159
|
-
return path2.join(
|
|
160
|
-
options.cwd,
|
|
161
|
-
options.outputDir,
|
|
162
|
-
path2.relative(options.cwd, path2.dirname(entry.file)),
|
|
163
|
-
`${path2.basename(entry.file, path2.extname(entry.file))}${options.outputExt}`
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// src/loader/entry-point.ts
|
|
168
|
-
function loadEntryPoint(entries) {
|
|
169
|
-
const { mode = "import" } = this.options.entryPoint ?? {};
|
|
170
|
-
let content;
|
|
171
|
-
switch (mode) {
|
|
172
|
-
case "import":
|
|
173
|
-
content = generateImport(this, entries);
|
|
174
|
-
break;
|
|
175
|
-
default:
|
|
176
|
-
content = generateLazy(this, entries);
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
return {
|
|
180
|
-
format: "js",
|
|
181
|
-
file: getAbsolutePath(this.options.cwd, "./index.js"),
|
|
182
|
-
content,
|
|
183
|
-
_entryPoint: {}
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
function generateImport(compiler, output) {
|
|
187
|
-
const { fullPath = false } = compiler.options.entryPoint ?? {};
|
|
188
|
-
const formats = /* @__PURE__ */ new Map();
|
|
189
|
-
output.forEach((entry, i) => {
|
|
190
|
-
const b = formats.get(entry.format) ?? { imports: [], entries: [] };
|
|
191
|
-
formats.set(entry.format, b);
|
|
192
|
-
const importPath = pathToFileURL(getOutputPath(compiler, entry));
|
|
193
|
-
const file = fullPath ? entry.file : getRelativePath(compiler.options.cwd, entry.file);
|
|
194
|
-
const name = `p_${i}`;
|
|
195
|
-
b.imports.push(`import * as ${name} from ${JSON.stringify(importPath)};`);
|
|
196
|
-
b.entries.push(`{
|
|
197
|
-
...${name},
|
|
198
|
-
format: ${JSON.stringify(entry.format)},
|
|
199
|
-
file: ${JSON.stringify(file)},
|
|
200
|
-
}`);
|
|
201
|
-
});
|
|
202
|
-
const imports = Array.from(formats.values()).flatMap((f) => f.imports).join("\n");
|
|
203
|
-
const entires = Array.from(formats.entries()).map(([k, v]) => `${k}: [${v.entries.join(",")}]`).join(",");
|
|
204
|
-
return `${imports}
|
|
205
|
-
export default {${entires}};`;
|
|
206
|
-
}
|
|
207
|
-
function generateLazy(compiler, output) {
|
|
208
|
-
const entries = [];
|
|
209
|
-
for (const entry of output) {
|
|
210
|
-
const fronmatter = entry._mdx ? entry._mdx.vfile.data.frontmatter : {};
|
|
211
|
-
const importPath = pathToFileURL(getOutputPath(compiler, entry));
|
|
212
|
-
const line = `{
|
|
213
|
-
file: ${JSON.stringify(entry.file)},
|
|
214
|
-
info: ${JSON.stringify(fronmatter)},
|
|
215
|
-
load: () => import(${JSON.stringify(importPath)})
|
|
216
|
-
}`;
|
|
217
|
-
entries.push(line);
|
|
218
|
-
}
|
|
219
|
-
return `export default [${entries.join(",\n")}]`;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// src/loader/json.ts
|
|
223
|
-
var loadJson = () => {
|
|
224
|
-
return (_file, source) => {
|
|
225
|
-
const parsed = JSON.parse(source);
|
|
226
|
-
return {
|
|
227
|
-
content: `export default ${JSON.stringify(parsed)}`
|
|
228
|
-
};
|
|
229
|
-
};
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
// src/compiler/emit.ts
|
|
233
|
-
import * as path3 from "node:path";
|
|
234
|
-
import * as fs2 from "node:fs/promises";
|
|
235
|
-
async function emit() {
|
|
236
|
-
const entires = await this.compile();
|
|
237
|
-
const emits = entires.map(async (entry) => this.emitEntry(entry));
|
|
238
|
-
this._emit = await Promise.all(emits);
|
|
239
|
-
}
|
|
240
|
-
async function emitEntry(entry) {
|
|
241
|
-
const outputPath = getOutputPath(this, entry);
|
|
242
|
-
await fs2.mkdir(path3.dirname(outputPath), { recursive: true });
|
|
243
|
-
await fs2.writeFile(outputPath, entry.content);
|
|
244
|
-
return {
|
|
245
|
-
...entry,
|
|
246
|
-
outputPath
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// src/compiler/compile.ts
|
|
251
|
-
import * as fs3 from "node:fs/promises";
|
|
252
|
-
import * as path4 from "node:path";
|
|
253
|
-
async function compile() {
|
|
254
|
-
this._output = await Promise.all(
|
|
255
|
-
this.files.map((file) => this.compileFile(file))
|
|
256
|
-
);
|
|
257
|
-
this._output.push(loadEntryPoint.call(this, this._output));
|
|
258
|
-
return this._output;
|
|
259
|
-
}
|
|
260
|
-
async function compileFile(file) {
|
|
261
|
-
const cache3 = this._cache.get(file);
|
|
262
|
-
if (cache3)
|
|
263
|
-
return cache3;
|
|
264
|
-
const format = path4.extname(file).slice(1);
|
|
265
|
-
const content = (await fs3.readFile(file)).toString();
|
|
266
|
-
const loader = this.loaders[format];
|
|
267
|
-
const output = await loader?.call(this, file, content);
|
|
268
|
-
if (!output) {
|
|
269
|
-
throw new Error(`Unknown format: ${format}`);
|
|
270
|
-
}
|
|
271
|
-
const entry = {
|
|
272
|
-
file,
|
|
273
|
-
format,
|
|
274
|
-
...output
|
|
275
|
-
};
|
|
276
|
-
this._cache.set(file, entry);
|
|
277
|
-
return entry;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// src/compiler/watch.ts
|
|
281
|
-
import { watch as watchFn } from "chokidar";
|
|
282
|
-
function watch() {
|
|
283
|
-
void this.emit();
|
|
284
|
-
const watcher = watchFn(this.options.files, { cwd: this.options.cwd });
|
|
285
|
-
watcher.on("all", (eventName, path5) => {
|
|
286
|
-
const absolutePath = getAbsolutePath(this.options.cwd, path5);
|
|
287
|
-
if (eventName === "add" && !this.files.includes(absolutePath)) {
|
|
288
|
-
this.files.push(absolutePath);
|
|
289
|
-
void this.emit();
|
|
290
|
-
}
|
|
291
|
-
if (eventName === "unlink") {
|
|
292
|
-
this.files = this.files.filter((file) => file !== absolutePath);
|
|
293
|
-
this._cache.delete(absolutePath);
|
|
294
|
-
void this.emit();
|
|
295
|
-
}
|
|
296
|
-
if (eventName === "change") {
|
|
297
|
-
console.log("update", path5);
|
|
298
|
-
this._cache.delete(absolutePath);
|
|
299
|
-
void this.compileFile(absolutePath).then(async (entry) => {
|
|
300
|
-
await this.emitEntry(entry);
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
return watcher;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// src/compiler/index.ts
|
|
308
|
-
var defaultOptions = {
|
|
309
|
-
cwd: process.cwd(),
|
|
310
|
-
outputDir: "./dist",
|
|
311
|
-
outputExt: ".js"
|
|
312
|
-
};
|
|
313
|
-
async function createCompiler(options) {
|
|
314
|
-
const compilerOptions = {
|
|
315
|
-
...defaultOptions,
|
|
316
|
-
...options
|
|
317
|
-
};
|
|
318
|
-
const files = await globFiles(compilerOptions);
|
|
319
|
-
return {
|
|
320
|
-
files,
|
|
321
|
-
options: compilerOptions,
|
|
322
|
-
compile,
|
|
323
|
-
emitEntry,
|
|
324
|
-
watch,
|
|
325
|
-
emit,
|
|
326
|
-
compileFile,
|
|
327
|
-
loaders: createLoaders(compilerOptions),
|
|
328
|
-
_cache: /* @__PURE__ */ new Map()
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
function createLoaders(options) {
|
|
332
|
-
const mdx = loadMDX(options.mdxOptions);
|
|
333
|
-
return {
|
|
334
|
-
mdx,
|
|
335
|
-
md: mdx,
|
|
336
|
-
json: loadJson(),
|
|
337
|
-
...options.loaders
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
export {
|
|
342
|
-
defaultConfig,
|
|
343
|
-
defaultConfigPath,
|
|
344
|
-
loadMDX,
|
|
345
|
-
loadEntryPoint,
|
|
346
|
-
createCompiler
|
|
347
|
-
};
|
package/dist/cli/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
package/dist/cli/index.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
createCompiler,
|
|
4
|
-
defaultConfig,
|
|
5
|
-
defaultConfigPath
|
|
6
|
-
} from "../chunk-UDFHC2Y3.js";
|
|
7
|
-
|
|
8
|
-
// src/cli/index.ts
|
|
9
|
-
import { Cli, Command, Option } from "clipanion";
|
|
10
|
-
|
|
11
|
-
// src/utils/load-config.ts
|
|
12
|
-
import * as path from "node:path";
|
|
13
|
-
import { pathToFileURL } from "node:url";
|
|
14
|
-
import * as fs from "node:fs";
|
|
15
|
-
async function loadConfig(configFile = defaultConfigPath) {
|
|
16
|
-
const configPath = path.resolve(configFile);
|
|
17
|
-
if (!fs.existsSync(configPath))
|
|
18
|
-
return defaultConfig;
|
|
19
|
-
const importPath = pathToFileURL(configPath).href;
|
|
20
|
-
const result = await import(`${importPath}?x=${Date.now()}`);
|
|
21
|
-
return "default" in result ? result.default : result;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// src/cli/index.ts
|
|
25
|
-
var BuildCommand = class extends Command {
|
|
26
|
-
static paths = [[`build`]];
|
|
27
|
-
config = Option.String({ required: false });
|
|
28
|
-
async execute() {
|
|
29
|
-
const config = await loadConfig(this.config);
|
|
30
|
-
const compiler = await createCompiler(config);
|
|
31
|
-
await compiler.emit();
|
|
32
|
-
this.context.stdout.write(`Build successful
|
|
33
|
-
`);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
var WatchCommand = class extends Command {
|
|
37
|
-
static paths = [[`watch`]];
|
|
38
|
-
config = Option.String({ required: false });
|
|
39
|
-
async execute() {
|
|
40
|
-
const config = await loadConfig(this.config);
|
|
41
|
-
const compiler = await createCompiler(config);
|
|
42
|
-
this.context.stdout.write(`Started server
|
|
43
|
-
`);
|
|
44
|
-
compiler.watch();
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
var [node, app, ...args] = process.argv;
|
|
48
|
-
var cli = new Cli({
|
|
49
|
-
binaryLabel: `fuma-content-cli`,
|
|
50
|
-
binaryName: `${node} ${app}`,
|
|
51
|
-
binaryVersion: `1.0.0`
|
|
52
|
-
});
|
|
53
|
-
cli.register(BuildCommand);
|
|
54
|
-
cli.register(WatchCommand);
|
|
55
|
-
void cli.runExit(args);
|