@acdh-oeaw/content-lib 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,58 @@
1
+ import * as watcher from "@parcel/watcher";
2
+
3
+ //#region src/index.d.ts
4
+ type MaybePromise<T> = T | Promise<T>;
5
+ type NonEmptyReadonlyArray<T> = readonly [T, ...Array<T>];
6
+ type GlobString = string;
7
+ interface CollectionItem {
8
+ /** Unique identifier. */
9
+ id: string;
10
+ /** File path relative to colleciton directory. */
11
+ filePath: string;
12
+ /** File path relative to current working directory. */
13
+ absoluteFilePath: string;
14
+ /** File modification timestamp. */
15
+ timestamp: number;
16
+ }
17
+ interface TransformContext {
18
+ createImportDeclaration: (path: string) => ImportDeclaration;
19
+ createJavaScriptImport: (content: string) => JavaScriptImport;
20
+ createJsonImport: (content: string) => JsonImport;
21
+ }
22
+ interface CollectionConfig<TCollectionItemContent = any, TCollectionDocument = any> {
23
+ name: string;
24
+ directory: string;
25
+ include: NonEmptyReadonlyArray<GlobString>;
26
+ exclude?: ReadonlyArray<GlobString>;
27
+ read: (item: CollectionItem) => MaybePromise<TCollectionItemContent>;
28
+ transform: (content: TCollectionItemContent, item: CollectionItem, context: TransformContext) => MaybePromise<TCollectionDocument>;
29
+ }
30
+ declare function createCollection<TCollectionItemContent, TCollectionDocument>(config: CollectionConfig<TCollectionItemContent, TCollectionDocument>): CollectionConfig<TCollectionItemContent, TCollectionDocument>;
31
+ interface ContentConfig {
32
+ collections: Array<CollectionConfig>;
33
+ }
34
+ declare function createConfig<T extends ContentConfig>(config: T): T;
35
+ declare class ImportDeclaration {
36
+ path: string;
37
+ constructor(path: string);
38
+ }
39
+ declare class JavaScriptImport {
40
+ content: string;
41
+ constructor(content: string);
42
+ }
43
+ declare class JsonImport {
44
+ content: string;
45
+ constructor(content: string);
46
+ }
47
+ interface BuildStats {
48
+ collections: number;
49
+ documents: number;
50
+ }
51
+ interface ContentProcessor {
52
+ build: () => Promise<BuildStats>;
53
+ watch: () => Promise<Set<watcher.AsyncSubscription>>;
54
+ }
55
+ declare function createContentProcessor(config: ContentConfig): Promise<ContentProcessor>;
56
+ //#endregion
57
+ export { CollectionConfig, ContentConfig, ContentProcessor, createCollection, createConfig, createContentProcessor };
58
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,310 @@
1
+ import * as crypto from "node:crypto";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
4
+ import { debuglog } from "node:util";
5
+ import { addTrailingSlash, log } from "@acdh-oeaw/lib";
6
+ import * as watcher from "@parcel/watcher";
7
+
8
+ //#region src/index.ts
9
+ const debug = debuglog("content-lib");
10
+ function createContentHash(value) {
11
+ return crypto.createHash("sha256").update(value).digest("hex");
12
+ }
13
+ function createIdFromFilePath(filePath) {
14
+ const parsed = path.parse(filePath);
15
+ if (parsed.name.toLowerCase() === "index") return path.basename(parsed.dir);
16
+ return parsed.name;
17
+ }
18
+ function createCollection(config) {
19
+ return config;
20
+ }
21
+ function createConfig(config) {
22
+ return config;
23
+ }
24
+ var ImportDeclaration = class {
25
+ path;
26
+ constructor(path$1) {
27
+ this.path = path$1;
28
+ }
29
+ };
30
+ function createImportDeclaration(path$1) {
31
+ return new ImportDeclaration(path$1);
32
+ }
33
+ var JavaScriptImport = class {
34
+ content;
35
+ constructor(content) {
36
+ this.content = content;
37
+ }
38
+ };
39
+ function createJavaScriptImport(content) {
40
+ return new JavaScriptImport(content);
41
+ }
42
+ var JsonImport = class {
43
+ content;
44
+ constructor(content) {
45
+ this.content = content;
46
+ }
47
+ };
48
+ function createJsonImport(content) {
49
+ return new JsonImport(content);
50
+ }
51
+ const prefix = "__i__";
52
+ const re = new RegExp(`"(${prefix}\\d+)"`, "g");
53
+ function serialize(value) {
54
+ debug("Serializing...\n");
55
+ const imports = [];
56
+ function addImport(filePath, type = "js") {
57
+ const identifier = [prefix, imports.length].join("");
58
+ imports.push(`import ${identifier} from "${filePath}"${type !== "js" ? ` with { type: "${type}" }` : ""};`);
59
+ return identifier;
60
+ }
61
+ const files = /* @__PURE__ */ new Map();
62
+ function addFiles(filePath, content) {
63
+ files.set(filePath, content);
64
+ }
65
+ const json = JSON.stringify(Array.from(value), (_key, value$1) => {
66
+ if (value$1 instanceof ImportDeclaration) {
67
+ const filePath = value$1.path;
68
+ debug(`Adding import declaration for "${filePath}".`);
69
+ const identifier = addImport(filePath);
70
+ return identifier;
71
+ }
72
+ if (value$1 instanceof JavaScriptImport) {
73
+ const hash = createContentHash(value$1.content);
74
+ const filePath = `./${hash}.js`;
75
+ debug(`Adding javascript import for "${filePath}".`);
76
+ const identifier = addImport(filePath);
77
+ addFiles(filePath, value$1.content);
78
+ return identifier;
79
+ }
80
+ if (value$1 instanceof JsonImport) {
81
+ const hash = createContentHash(value$1.content);
82
+ const filePath = `./${hash}.json`;
83
+ debug(`Adding json import for "${filePath}".`);
84
+ const identifier = addImport(filePath, "json");
85
+ addFiles(filePath, value$1.content);
86
+ return identifier;
87
+ }
88
+ return value$1;
89
+ }, 2).replaceAll(re, "$1");
90
+ let result = "";
91
+ if (imports.length > 0) {
92
+ result += imports.join("\n");
93
+ result += "\n\n";
94
+ }
95
+ result += `const items = new Map(${json});\n\nexport default items;`;
96
+ return [result, files];
97
+ }
98
+ async function createContentProcessor(config) {
99
+ debug("Creating content processor...\n");
100
+ const outputDirectoryBasePath = path.join(process.cwd(), ".content", "generated");
101
+ debug("Clearing output directory...\n");
102
+ await fs.rm(outputDirectoryBasePath, {
103
+ force: true,
104
+ recursive: true
105
+ });
106
+ const collections = [];
107
+ const context = {
108
+ createImportDeclaration,
109
+ createJavaScriptImport,
110
+ createJsonImport
111
+ };
112
+ for (const collection of config.collections) {
113
+ const absoluteDirectoryPath = addTrailingSlash(path.resolve(collection.directory));
114
+ const outputDirectoryPath = path.join(outputDirectoryBasePath, collection.name);
115
+ await fs.mkdir(outputDirectoryPath, { recursive: true });
116
+ collections.push({
117
+ ...collection,
118
+ absoluteDirectoryPath,
119
+ data: /* @__PURE__ */ new Map(),
120
+ outputDirectoryPath
121
+ });
122
+ }
123
+ async function generate(signal) {
124
+ debug("Generating...\n");
125
+ for (const collection of collections) {
126
+ debug(`Reading collection "${collection.name}"...`);
127
+ for (const [id, { item }] of collection.data) {
128
+ if (signal?.aborted === true) {
129
+ debug("Aborted reeading collections...");
130
+ return;
131
+ }
132
+ const content = await collection.read(item);
133
+ collection.data.get(id).content = content;
134
+ debug(`- Read item "${id}"...`);
135
+ }
136
+ debug(`Done reading ${String(collection.data.size)} item(s) in collection "${collection.name}".\n`);
137
+ }
138
+ for (const collection of collections) {
139
+ debug(`Transforming collection "${collection.name}"...`);
140
+ for (const [id, { content, item }] of collection.data) {
141
+ if (signal?.aborted === true) {
142
+ debug("Aborted transforming collections...");
143
+ return;
144
+ }
145
+ const document = await collection.transform(content, item, context);
146
+ collection.data.get(id).document = document;
147
+ debug(`- Transformed item "${id}"...`);
148
+ }
149
+ debug(`Done transforming ${String(collection.data.size)} item(s) in collection "${collection.name}".\n`);
150
+ }
151
+ if (signal?.aborted === true) {
152
+ debug("Aborted writing collections...");
153
+ return;
154
+ }
155
+ for (const collection of collections) {
156
+ debug(`Writing collection "${collection.name}"...`);
157
+ const outputFilePath = path.join(collection.outputDirectoryPath, "index.js");
158
+ const [serialized, files] = serialize(collection.data);
159
+ await fs.writeFile(outputFilePath, serialized, { encoding: "utf-8" });
160
+ for (const [filePath, fileContent] of files) {
161
+ const outputFilePath$1 = path.join(collection.outputDirectoryPath, filePath);
162
+ await fs.writeFile(outputFilePath$1, fileContent, { encoding: "utf-8" });
163
+ }
164
+ }
165
+ }
166
+ async function build() {
167
+ debug("Building...\n");
168
+ for (const collection of collections) {
169
+ debug(`Building collection "${collection.name}"...`);
170
+ for await (const filePath of fs.glob(collection.include, {
171
+ cwd: collection.directory,
172
+ exclude: collection.exclude
173
+ })) {
174
+ const absoluteFilePath = path.join(collection.directory, filePath);
175
+ const id = createIdFromFilePath(filePath);
176
+ const stats = await fs.stat(absoluteFilePath).catch((error) => {
177
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
178
+ throw error;
179
+ });
180
+ if (stats == null) continue;
181
+ const { mtimeMs: timestamp } = stats;
182
+ const item = {
183
+ id,
184
+ filePath,
185
+ absoluteFilePath,
186
+ timestamp
187
+ };
188
+ collection.data.set(id, {
189
+ item,
190
+ content: null,
191
+ document: null
192
+ });
193
+ debug(`- Added item "${id}" (path: "${filePath}")...`);
194
+ }
195
+ debug(`Done adding ${String(collection.data.size)} item(s) to collection "${collection.name}".\n`);
196
+ }
197
+ await generate();
198
+ return {
199
+ collections: collections.length,
200
+ documents: collections.reduce((acc, collection) => {
201
+ return acc + collection.data.size;
202
+ }, 0)
203
+ };
204
+ }
205
+ async function watch() {
206
+ debug("Watching...\n");
207
+ const subscriptions = /* @__PURE__ */ new Set();
208
+ const debounceDelayMs = 150;
209
+ let timer = null;
210
+ let controller = null;
211
+ let batch = /* @__PURE__ */ new Map();
212
+ for (const collection of collections) {
213
+ debug(`Watching collection "${collection.name}"...`);
214
+ /**
215
+ * Ideally, we could just add `include` as a negative ignore pattern.
216
+ *
217
+ * This is currently not supported by `@parcel/watcher`. Simple patterns like "!*.md" do seem
218
+ * to work, but others like "!*\/index.md" do not.
219
+ *
220
+ * Therefore we need to filter out matching events in the javascript main thread
221
+ * (see `path.matchesGlob` below).
222
+ *
223
+ * @see https://github.com/parcel-bundler/watcher/issues/166
224
+ */
225
+ const ignore = collection.exclude ?? [];
226
+ const subscription = await watcher.subscribe(collection.directory, (error, events) => {
227
+ if (error != null) {
228
+ log.error(error);
229
+ return;
230
+ }
231
+ debug(`- ${String(events.length)} events in collection "${collection.name}"...`);
232
+ for (const event of events) {
233
+ const relativeFilePath = event.path.slice(collection.absoluteDirectoryPath.length);
234
+ if (collection.include.some((pattern) => {
235
+ return path.matchesGlob(relativeFilePath, pattern);
236
+ })) {
237
+ event.relativeFilePath = relativeFilePath;
238
+ batch.set(event.path, event);
239
+ debug(`- Added "${event.type}" event for "${relativeFilePath}" to queue.`);
240
+ } else debug(`- Discarded "${event.type}" event for "${relativeFilePath}".`);
241
+ }
242
+ if (timer != null) clearTimeout(timer);
243
+ timer = setTimeout(async () => {
244
+ if (controller != null) controller.abort();
245
+ controller = new AbortController();
246
+ const events$1 = batch;
247
+ batch = /* @__PURE__ */ new Map();
248
+ timer = null;
249
+ let isCollectionChanged = false;
250
+ for (const event of events$1.values()) {
251
+ const filePath = event.relativeFilePath;
252
+ const id = createIdFromFilePath(filePath);
253
+ debug(`Processing "${event.type}" event for "${id}".`);
254
+ switch (event.type) {
255
+ case "create":
256
+ case "update": {
257
+ isCollectionChanged ||= event.type === "create" || collection.data.has(id);
258
+ const absoluteFilePath = path.join(collection.directory, filePath);
259
+ const stats = await fs.stat(absoluteFilePath).catch((error$1) => {
260
+ if (error$1 instanceof Error && "code" in error$1 && error$1.code === "ENOENT") return null;
261
+ throw error$1;
262
+ });
263
+ if (stats == null) continue;
264
+ const { mtimeMs: timestamp } = stats;
265
+ const item = {
266
+ id,
267
+ filePath,
268
+ absoluteFilePath,
269
+ timestamp
270
+ };
271
+ collection.data.set(id, {
272
+ item,
273
+ content: null,
274
+ document: null
275
+ });
276
+ break;
277
+ }
278
+ case "delete":
279
+ isCollectionChanged ||= collection.data.has(id);
280
+ collection.data.delete(id);
281
+ break;
282
+ }
283
+ }
284
+ if (isCollectionChanged) await generate(controller.signal);
285
+ }, debounceDelayMs);
286
+ }, { ignore });
287
+ subscriptions.add(subscription);
288
+ }
289
+ async function unsubscribe() {
290
+ debug("Cleaning up.");
291
+ if (timer != null) clearTimeout(timer);
292
+ timer = null;
293
+ if (controller != null) controller.abort();
294
+ controller = null;
295
+ for (const subscription of subscriptions) await subscription.unsubscribe();
296
+ subscriptions.clear();
297
+ }
298
+ process.once("SIGINT", unsubscribe);
299
+ process.once("SIGTERM", unsubscribe);
300
+ return subscriptions;
301
+ }
302
+ return {
303
+ build,
304
+ watch
305
+ };
306
+ }
307
+
308
+ //#endregion
309
+ export { createCollection, createConfig, createContentProcessor };
310
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["value: string","filePath: string","config: CollectionConfig<TCollectionItemContent, TCollectionDocument>","config: T","path: string","path","content: string","value: Map<string, any>","imports: Array<string>","type: \"js\" | \"json\"","value","config: ContentConfig","collections: Array<Collection>","context: TransformContext","signal?: AbortSignal","outputFilePath","error: unknown","item: CollectionItem","timer: ReturnType<typeof setTimeout> | null","controller: AbortController | null","events","error"],"sources":["../src/index.ts"],"sourcesContent":["import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { debuglog } from \"node:util\";\n\nimport { addTrailingSlash, log } from \"@acdh-oeaw/lib\";\nimport * as watcher from \"@parcel/watcher\";\n\n//\n\nconst debug = debuglog(\"content-lib\");\n\n//\n\nfunction createContentHash(value: string): string {\n\treturn crypto.createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction createIdFromFilePath(filePath: string): string {\n\tconst parsed = path.parse(filePath);\n\n\tif (parsed.name.toLowerCase() === \"index\") {\n\t\treturn path.basename(parsed.dir);\n\t}\n\n\treturn parsed.name;\n}\n\n//\n\ntype MaybePromise<T> = T | Promise<T>;\n\ntype NonEmptyReadonlyArray<T> = readonly [T, ...Array<T>];\n\ntype GlobString = string;\n\ninterface CollectionItem {\n\t/** Unique identifier. */\n\tid: string;\n\t/** File path relative to colleciton directory. */\n\tfilePath: string;\n\t/** File path relative to current working directory. */\n\tabsoluteFilePath: string;\n\t/** File modification timestamp. */\n\ttimestamp: number;\n}\n\ninterface TransformContext {\n\tcreateImportDeclaration: (path: string) => ImportDeclaration;\n\tcreateJavaScriptImport: (content: string) => JavaScriptImport;\n\tcreateJsonImport: (content: string) => JsonImport;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface CollectionConfig<TCollectionItemContent = any, TCollectionDocument = any> {\n\tname: string;\n\tdirectory: string;\n\tinclude: NonEmptyReadonlyArray<GlobString>;\n\texclude?: ReadonlyArray<GlobString>;\n\tread: (item: CollectionItem) => MaybePromise<TCollectionItemContent>;\n\ttransform: (\n\t\tcontent: TCollectionItemContent,\n\t\titem: CollectionItem,\n\t\tcontext: TransformContext,\n\t) => MaybePromise<TCollectionDocument>;\n}\n\nexport function createCollection<TCollectionItemContent, TCollectionDocument>(\n\tconfig: CollectionConfig<TCollectionItemContent, TCollectionDocument>,\n): CollectionConfig<TCollectionItemContent, TCollectionDocument> {\n\treturn config;\n}\n\nexport interface ContentConfig {\n\tcollections: Array<CollectionConfig>;\n}\n\nexport function createConfig<T extends ContentConfig>(config: T): T {\n\treturn config;\n}\n\n//\n\n// function createItemCacheKey(item: CollectionItem): string {\n// \treturn String(item.timestamp);\n// }\n\n//\n\nclass ImportDeclaration {\n\tpath: string;\n\n\tconstructor(path: string) {\n\t\tthis.path = path;\n\t}\n}\n\nfunction createImportDeclaration(path: string): ImportDeclaration {\n\treturn new ImportDeclaration(path);\n}\n\nclass JavaScriptImport {\n\tcontent: string;\n\n\tconstructor(content: string) {\n\t\tthis.content = content;\n\t}\n}\n\nfunction createJavaScriptImport(content: string): JavaScriptImport {\n\treturn new JavaScriptImport(content);\n}\n\nclass JsonImport {\n\tcontent: string;\n\n\tconstructor(content: string) {\n\t\tthis.content = content;\n\t}\n}\n\nfunction createJsonImport(content: string): JsonImport {\n\treturn new JsonImport(content);\n}\n\n//\n\nconst prefix = \"__i__\";\nconst re = new RegExp(`\"(${prefix}\\\\d+)\"`, \"g\");\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction serialize(value: Map<string, any>): [string, Map<string, string>] {\n\tdebug(\"Serializing...\\n\");\n\n\tconst imports: Array<string> = [];\n\n\tfunction addImport(filePath: string, type: \"js\" | \"json\" = \"js\"): string {\n\t\tconst identifier = [prefix, imports.length].join(\"\");\n\t\timports.push(\n\t\t\t`import ${identifier} from \"${filePath}\"${type !== \"js\" ? ` with { type: \"${type}\" }` : \"\"};`,\n\t\t);\n\n\t\treturn identifier;\n\t}\n\n\tconst files = new Map<string, string>();\n\n\tfunction addFiles(filePath: string, content: string): void {\n\t\tfiles.set(filePath, content);\n\t}\n\n\tconst json = JSON.stringify(\n\t\tArray.from(value),\n\t\t// TODO: Should we support (multiple) named imports?\n\t\t(_key, value) => {\n\t\t\tif (value instanceof ImportDeclaration) {\n\t\t\t\tconst filePath = value.path;\n\n\t\t\t\tdebug(`Adding import declaration for \"${filePath}\".`);\n\t\t\t\tconst identifier = addImport(filePath);\n\n\t\t\t\treturn identifier;\n\t\t\t}\n\n\t\t\tif (value instanceof JavaScriptImport) {\n\t\t\t\tconst hash = createContentHash(value.content);\n\t\t\t\tconst filePath = `./${hash}.js`;\n\n\t\t\t\tdebug(`Adding javascript import for \"${filePath}\".`);\n\t\t\t\tconst identifier = addImport(filePath);\n\t\t\t\taddFiles(filePath, value.content);\n\n\t\t\t\treturn identifier;\n\t\t\t}\n\n\t\t\tif (value instanceof JsonImport) {\n\t\t\t\tconst hash = createContentHash(value.content);\n\t\t\t\tconst filePath = `./${hash}.json`;\n\n\t\t\t\tdebug(`Adding json import for \"${filePath}\".`);\n\t\t\t\tconst identifier = addImport(filePath, \"json\");\n\t\t\t\taddFiles(filePath, value.content);\n\n\t\t\t\treturn identifier;\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\treturn value;\n\t\t},\n\t\t2,\n\t)\n\t\t/** Remove quotes from import identifiers. */\n\t\t.replaceAll(re, \"$1\");\n\n\tlet result = \"\";\n\n\tif (imports.length > 0) {\n\t\tresult += imports.join(\"\\n\");\n\t\tresult += \"\\n\\n\";\n\t}\n\n\tresult += `const items = new Map(${json});\\n\\nexport default items;`;\n\n\treturn [result, files];\n}\n\n//\n\ninterface Collection extends CollectionConfig {\n\tabsoluteDirectoryPath: string;\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tdata: Map<CollectionItem[\"id\"], { item: CollectionItem; content: any; document: any }>; // TODO: revisit\n\toutputDirectoryPath: string;\n}\n\ninterface BuildStats {\n\tcollections: number;\n\tdocuments: number;\n}\n\nexport interface ContentProcessor {\n\tbuild: () => Promise<BuildStats>;\n\twatch: () => Promise<Set<watcher.AsyncSubscription>>;\n}\n\nexport async function createContentProcessor(config: ContentConfig): Promise<ContentProcessor> {\n\tdebug(\"Creating content processor...\\n\");\n\n\tconst outputDirectoryBasePath = path.join(process.cwd(), \".content\", \"generated\");\n\n\tdebug(\"Clearing output directory...\\n\");\n\tawait fs.rm(outputDirectoryBasePath, { force: true, recursive: true });\n\n\tconst collections: Array<Collection> = [];\n\n\tconst context: TransformContext = {\n\t\tcreateImportDeclaration,\n\t\tcreateJavaScriptImport,\n\t\tcreateJsonImport,\n\t};\n\n\tfor (const collection of config.collections) {\n\t\tconst absoluteDirectoryPath = addTrailingSlash(path.resolve(collection.directory));\n\n\t\tconst outputDirectoryPath = path.join(outputDirectoryBasePath, collection.name);\n\t\tawait fs.mkdir(outputDirectoryPath, { recursive: true });\n\n\t\tcollections.push({\n\t\t\t...collection,\n\t\t\tabsoluteDirectoryPath,\n\t\t\tdata: new Map(),\n\t\t\toutputDirectoryPath,\n\t\t});\n\t}\n\n\tasync function generate(signal?: AbortSignal): Promise<void> {\n\t\tdebug(\"Generating...\\n\");\n\n\t\tfor (const collection of collections) {\n\t\t\tdebug(`Reading collection \"${collection.name}\"...`);\n\n\t\t\tfor (const [id, { item }] of collection.data) {\n\t\t\t\tif (signal?.aborted === true) {\n\t\t\t\t\tdebug(\"Aborted reeading collections...\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// FIXME: race condition: what if file has been deleted in the meantime\n\t\t\t\t// TODO: skip item when `read()` returns `null`?\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tconst content = await collection.read(item);\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tcollection.data.get(id)!.content = content;\n\n\t\t\t\tdebug(`- Read item \"${id}\"...`);\n\t\t\t}\n\n\t\t\tdebug(\n\t\t\t\t`Done reading ${String(collection.data.size)} item(s) in collection \"${collection.name}\".\\n`,\n\t\t\t);\n\t\t}\n\n\t\tfor (const collection of collections) {\n\t\t\tdebug(`Transforming collection \"${collection.name}\"...`);\n\n\t\t\tfor (const [id, { content, item }] of collection.data) {\n\t\t\t\tif (signal?.aborted === true) {\n\t\t\t\t\tdebug(\"Aborted transforming collections...\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tconst document = await collection.transform(content, item, context);\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\tcollection.data.get(id)!.document = document;\n\n\t\t\t\tdebug(`- Transformed item \"${id}\"...`);\n\t\t\t}\n\n\t\t\tdebug(\n\t\t\t\t`Done transforming ${String(collection.data.size)} item(s) in collection \"${collection.name}\".\\n`,\n\t\t\t);\n\t\t}\n\n\t\tif (signal?.aborted === true) {\n\t\t\tdebug(\"Aborted writing collections...\");\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const collection of collections) {\n\t\t\tdebug(`Writing collection \"${collection.name}\"...`);\n\n\t\t\t// TODO: Consider combining serializing and writing to disk in one function.\n\t\t\tconst outputFilePath = path.join(collection.outputDirectoryPath, \"index.js\");\n\t\t\tconst [serialized, files] = serialize(collection.data);\n\t\t\tawait fs.writeFile(outputFilePath, serialized, { encoding: \"utf-8\" });\n\t\t\tfor (const [filePath, fileContent] of files) {\n\t\t\t\tconst outputFilePath = path.join(collection.outputDirectoryPath, filePath);\n\t\t\t\tawait fs.writeFile(outputFilePath, fileContent, { encoding: \"utf-8\" });\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function build(): Promise<BuildStats> {\n\t\tdebug(\"Building...\\n\");\n\n\t\tfor (const collection of collections) {\n\t\t\tdebug(`Building collection \"${collection.name}\"...`);\n\n\t\t\t// eslint-disable-next-line n/no-unsupported-features/node-builtins\n\t\t\tfor await (const filePath of fs.glob(collection.include, {\n\t\t\t\tcwd: collection.directory,\n\t\t\t\texclude: collection.exclude,\n\t\t\t})) {\n\t\t\t\tconst absoluteFilePath = path.join(collection.directory, filePath);\n\t\t\t\tconst id = createIdFromFilePath(filePath);\n\n\t\t\t\tconst stats = await fs.stat(absoluteFilePath).catch((error: unknown) => {\n\t\t\t\t\tif (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tthrow error;\n\t\t\t\t});\n\t\t\t\tif (stats == null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst { mtimeMs: timestamp } = stats;\n\n\t\t\t\tconst item: CollectionItem = { id, filePath, absoluteFilePath, timestamp };\n\n\t\t\t\tcollection.data.set(id, { item, content: null, document: null });\n\n\t\t\t\tdebug(`- Added item \"${id}\" (path: \"${filePath}\")...`);\n\t\t\t}\n\n\t\t\tdebug(\n\t\t\t\t`Done adding ${String(collection.data.size)} item(s) to collection \"${collection.name}\".\\n`,\n\t\t\t);\n\t\t}\n\n\t\tawait generate();\n\n\t\treturn {\n\t\t\tcollections: collections.length,\n\t\t\tdocuments: collections.reduce((acc, collection) => {\n\t\t\t\treturn acc + collection.data.size;\n\t\t\t}, 0),\n\t\t};\n\t}\n\n\tasync function watch(): Promise<Set<watcher.AsyncSubscription>> {\n\t\tdebug(\"Watching...\\n\");\n\n\t\tconst subscriptions = new Set<watcher.AsyncSubscription>();\n\n\t\tconst debounceDelayMs = 150;\n\t\tlet timer: ReturnType<typeof setTimeout> | null = null;\n\t\tlet controller: AbortController | null = null;\n\t\tlet batch = new Map<watcher.Event[\"path\"], watcher.Event & { relativeFilePath: string }>();\n\n\t\tfor (const collection of collections) {\n\t\t\tdebug(`Watching collection \"${collection.name}\"...`);\n\n\t\t\t/**\n\t\t\t * Ideally, we could just add `include` as a negative ignore pattern.\n\t\t\t *\n\t\t\t * This is currently not supported by `@parcel/watcher`. Simple patterns like \"!*.md\" do seem\n\t\t\t * to work, but others like \"!*\\/index.md\" do not.\n\t\t\t *\n\t\t\t * Therefore we need to filter out matching events in the javascript main thread\n\t\t\t * (see `path.matchesGlob` below).\n\t\t\t *\n\t\t\t * @see https://github.com/parcel-bundler/watcher/issues/166\n\t\t\t */\n\t\t\t// const ignore = [\n\t\t\t// \t...collection.include.map((glob) => {\n\t\t\t// \t\treturn `!${glob}`;\n\t\t\t// \t}),\n\t\t\t// \t...(collection.exclude ?? []),\n\t\t\t// ];\n\t\t\tconst ignore = (collection.exclude ?? []) as Array<string>;\n\n\t\t\tconst subscription = await watcher.subscribe(\n\t\t\t\tcollection.directory,\n\t\t\t\t(error, events) => {\n\t\t\t\t\tif (error != null) {\n\t\t\t\t\t\tlog.error(error);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tdebug(`- ${String(events.length)} events in collection \"${collection.name}\"...`);\n\n\t\t\t\t\tfor (const event of events) {\n\t\t\t\t\t\t// const relativeFilePath = path.relative(collection.directory, event.path);\n\t\t\t\t\t\tconst relativeFilePath = event.path.slice(collection.absoluteDirectoryPath.length);\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tcollection.include.some((pattern) => {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line n/no-unsupported-features/node-builtins\n\t\t\t\t\t\t\t\treturn path.matchesGlob(relativeFilePath, pattern);\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t(event as watcher.Event & { relativeFilePath: string }).relativeFilePath =\n\t\t\t\t\t\t\t\trelativeFilePath;\n\t\t\t\t\t\t\tbatch.set(event.path, event as watcher.Event & { relativeFilePath: string });\n\n\t\t\t\t\t\t\tdebug(`- Added \"${event.type}\" event for \"${relativeFilePath}\" to queue.`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdebug(`- Discarded \"${event.type}\" event for \"${relativeFilePath}\".`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (timer != null) {\n\t\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\t}\n\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\t\t\t\ttimer = setTimeout(async () => {\n\t\t\t\t\t\tif (controller != null) {\n\t\t\t\t\t\t\tcontroller.abort();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontroller = new AbortController();\n\n\t\t\t\t\t\tconst events = batch;\n\t\t\t\t\t\tbatch = new Map();\n\t\t\t\t\t\ttimer = null;\n\n\t\t\t\t\t\tlet isCollectionChanged = false;\n\n\t\t\t\t\t\tfor (const event of events.values()) {\n\t\t\t\t\t\t\tconst filePath = event.relativeFilePath;\n\t\t\t\t\t\t\tconst id = createIdFromFilePath(filePath);\n\n\t\t\t\t\t\t\tdebug(`Processing \"${event.type}\" event for \"${id}\".`);\n\n\t\t\t\t\t\t\tswitch (event.type) {\n\t\t\t\t\t\t\t\tcase \"create\":\n\t\t\t\t\t\t\t\tcase \"update\": {\n\t\t\t\t\t\t\t\t\tisCollectionChanged ||= event.type === \"create\" || collection.data.has(id);\n\n\t\t\t\t\t\t\t\t\tconst absoluteFilePath = path.join(collection.directory, filePath);\n\n\t\t\t\t\t\t\t\t\tconst stats = await fs.stat(absoluteFilePath).catch((error: unknown) => {\n\t\t\t\t\t\t\t\t\t\tif (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n\t\t\t\t\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\tif (stats == null) {\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tconst { mtimeMs: timestamp } = stats;\n\n\t\t\t\t\t\t\t\t\tconst item: CollectionItem = { id, filePath, absoluteFilePath, timestamp };\n\n\t\t\t\t\t\t\t\t\tcollection.data.set(id, { item, content: null, document: null });\n\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"delete\": {\n\t\t\t\t\t\t\t\t\tisCollectionChanged ||= collection.data.has(id);\n\n\t\t\t\t\t\t\t\t\tcollection.data.delete(id);\n\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (isCollectionChanged) {\n\t\t\t\t\t\t\tawait generate(controller.signal);\n\t\t\t\t\t\t}\n\t\t\t\t\t}, debounceDelayMs);\n\t\t\t\t},\n\t\t\t\t{ ignore },\n\t\t\t);\n\n\t\t\tsubscriptions.add(subscription);\n\t\t}\n\n\t\tasync function unsubscribe() {\n\t\t\tdebug(\"Cleaning up.\");\n\n\t\t\tif (timer != null) {\n\t\t\t\tclearTimeout(timer);\n\t\t\t}\n\t\t\ttimer = null;\n\n\t\t\tif (controller != null) {\n\t\t\t\tcontroller.abort();\n\t\t\t}\n\t\t\tcontroller = null;\n\n\t\t\tfor (const subscription of subscriptions) {\n\t\t\t\tawait subscription.unsubscribe();\n\t\t\t}\n\t\t\tsubscriptions.clear();\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\tprocess.once(\"SIGINT\", unsubscribe);\n\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\tprocess.once(\"SIGTERM\", unsubscribe);\n\n\t\treturn subscriptions;\n\t}\n\n\treturn {\n\t\tbuild,\n\t\twatch,\n\t};\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@acdh-oeaw/content-lib",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": "^22 || ^24"
8
+ },
9
+ "devEngines": {
10
+ "runtime": {
11
+ "name": "node",
12
+ "version": ">= 22.18 < 23",
13
+ "onFail": "download"
14
+ }
15
+ },
16
+ "sideEffects": false,
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "exports": {
21
+ ".": "./dist/index.js"
22
+ },
23
+ "dependencies": {
24
+ "@acdh-oeaw/lib": "0.3.4",
25
+ "@parcel/watcher": "^2.5.1"
26
+ },
27
+ "devDependencies": {
28
+ "@acdh-oeaw/eslint-config": "2.0.9",
29
+ "@acdh-oeaw/eslint-config-node": "2.0.9",
30
+ "@acdh-oeaw/prettier-config": "2.0.1",
31
+ "@acdh-oeaw/tsconfig": "^1.5.1",
32
+ "@acdh-oeaw/tsconfig-lib": "^1.3.0",
33
+ "@types/node": "^22.17.2",
34
+ "eslint": "9.33.0",
35
+ "eslint-config-flat-gitignore": "2.1.0",
36
+ "globals": "16.3.0",
37
+ "node": "^22.18.0",
38
+ "npm-run-all2": "8.0.4",
39
+ "prettier": "3.6.2",
40
+ "tsdown": "^0.14.1",
41
+ "typescript": "^5.9.2",
42
+ "typescript-eslint": "8.39.1"
43
+ },
44
+ "lint-staged": {
45
+ "*.@(js|ts)": [
46
+ "eslint --fix",
47
+ "prettier --cache --cache-location ./../../.prettiercache --write"
48
+ ],
49
+ "*.!(js|ts)": "prettier --cache --cache-location ./../../.prettiercache --ignore-unknown --write"
50
+ },
51
+ "prettier": "@acdh-oeaw/prettier-config",
52
+ "scripts": {
53
+ "build": "tsdown",
54
+ "format:check": "prettier . --cache --cache-location ./../../.prettiercache --check",
55
+ "format:fix": "prettier . --cache --cache-location ./../../.prettiercache --check --write",
56
+ "lint:check": "eslint .",
57
+ "lint:fix": "eslint . --fix",
58
+ "types:check": "tsc --noEmit",
59
+ "test": "exit 0"
60
+ }
61
+ }