@fedify/vocab 2.0.0-dev.241 → 2.0.0-dev.279
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/deno.json +9 -2
- package/dist/actor.test.js +2 -2
- package/dist/{deno-BcC99yBa.js → deno-y1THYur-.js} +8 -2
- package/dist/lookup.test.js +2 -2
- package/dist/mod.cjs +197 -191
- package/dist/mod.js +197 -191
- package/dist/type.test.js +1 -1
- package/dist/{vocab-BmxSLhXr.js → vocab-fPKUeh35.js} +189 -189
- package/dist/vocab.test.js +1 -1
- package/package.json +8 -6
- package/scripts/codegen.ts +147 -11
package/dist/vocab.test.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Temporal } from "@js-temporal/polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
|
|
5
|
-
import { Activity, Announce, Collection, Create, CryptographicKey, Follow, Hashtag, LanguageString, Link, Note, Object as Object$1, OrderedCollectionPage, Person, Place, Question, Source, decodeMultibase, mockDocumentLoader, test, vocab_exports } from "./vocab-
|
|
5
|
+
import { Activity, Announce, Collection, Create, CryptographicKey, Follow, Hashtag, LanguageString, Link, Note, Object as Object$1, OrderedCollectionPage, Person, Place, Question, Source, decodeMultibase, mockDocumentLoader, test, vocab_exports } from "./vocab-fPKUeh35.js";
|
|
6
6
|
import { assertInstanceOf } from "./utils-Dm0Onkcz.js";
|
|
7
7
|
import { deepStrictEqual, notDeepStrictEqual, ok, rejects, throws } from "node:assert/strict";
|
|
8
8
|
import { pascalCase } from "es-toolkit";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/vocab",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.279+ce1bdc22",
|
|
4
4
|
"homepage": "https://fedify.dev/",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"jsonld": "^9.0.0",
|
|
48
48
|
"multicodec": "^3.2.1",
|
|
49
49
|
"pkijs": "^3.3.3",
|
|
50
|
-
"@fedify/vocab-tools": "2.0.0-dev.
|
|
51
|
-
"@fedify/webfinger": "2.0.0-dev.
|
|
50
|
+
"@fedify/vocab-tools": "2.0.0-dev.279+ce1bdc22",
|
|
51
|
+
"@fedify/webfinger": "2.0.0-dev.279+ce1bdc22"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^22.17.0",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"tsdown": "^0.12.9",
|
|
58
58
|
"typescript": "^5.9.3",
|
|
59
59
|
"@fedify/fixture": "2.0.0",
|
|
60
|
-
"@fedify/vocab-runtime": "2.0.0-dev.
|
|
60
|
+
"@fedify/vocab-runtime": "2.0.0-dev.279+ce1bdc22"
|
|
61
61
|
},
|
|
62
62
|
"keywords": [
|
|
63
63
|
"Fedify",
|
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
"build:self": "deno task compile && tsdown",
|
|
75
75
|
"build": "pnpm --filter @fedify/vocab... run build:self",
|
|
76
76
|
"prepublish": "pnpm build",
|
|
77
|
-
"
|
|
78
|
-
"test
|
|
77
|
+
"pretest": "pnpm build",
|
|
78
|
+
"test": "cd dist/ && node --test",
|
|
79
|
+
"pretest:bun": "pnpm build",
|
|
80
|
+
"test:bun": "cd dist/ && bun test --timeout 60000"
|
|
79
81
|
}
|
|
80
82
|
}
|
package/scripts/codegen.ts
CHANGED
|
@@ -1,18 +1,154 @@
|
|
|
1
|
+
import $ from "@david/dax";
|
|
2
|
+
import type { Path } from "@david/dax";
|
|
1
3
|
import { generateVocab } from "@fedify/vocab-tools";
|
|
2
|
-
import { rename } from "node:fs/promises";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const LOCK_STALE_MS = 5 * 60 * 1000; // 5 minutes
|
|
6
|
+
const LOCK_RETRY_MS = 100;
|
|
7
|
+
const LOCK_TIMEOUT_MS = 60 * 1000; // 1 minute
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Get the latest mtime from all YAML files in the schema directory.
|
|
11
|
+
*/
|
|
12
|
+
async function getLatestSourceMtime(schemaDir: Path): Promise<number> {
|
|
13
|
+
let latestMtime = 0;
|
|
14
|
+
for await (const entry of schemaDir.readDir()) {
|
|
15
|
+
if (!entry.isFile) continue;
|
|
16
|
+
if (!entry.name.match(/\.ya?ml$/i)) continue;
|
|
17
|
+
if (entry.name === "schema.yaml") continue;
|
|
18
|
+
const fileStat = await schemaDir.join(entry.name).stat();
|
|
19
|
+
if (fileStat?.mtime && fileStat.mtime.getTime() > latestMtime) {
|
|
20
|
+
latestMtime = fileStat.mtime.getTime();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return latestMtime;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check if the generated file is up to date compared to source files.
|
|
28
|
+
*/
|
|
29
|
+
async function isUpToDate(
|
|
30
|
+
schemaDir: Path,
|
|
31
|
+
generatedPath: Path,
|
|
32
|
+
): Promise<boolean> {
|
|
33
|
+
try {
|
|
34
|
+
const [sourceMtime, generatedStat] = await Promise.all([
|
|
35
|
+
getLatestSourceMtime(schemaDir),
|
|
36
|
+
generatedPath.stat(),
|
|
37
|
+
]);
|
|
38
|
+
if (!generatedStat?.mtime) return false;
|
|
39
|
+
return generatedStat.mtime.getTime() >= sourceMtime;
|
|
40
|
+
} catch {
|
|
41
|
+
// If generated file doesn't exist, it's not up to date
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface Lock {
|
|
47
|
+
release(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Acquire a directory-based lock. mkdir is atomic on POSIX systems.
|
|
52
|
+
*/
|
|
53
|
+
async function acquireLock(lockPath: Path): Promise<Lock> {
|
|
54
|
+
const startTime = Date.now();
|
|
55
|
+
|
|
56
|
+
while (true) {
|
|
57
|
+
try {
|
|
58
|
+
// Use Deno.mkdir directly because dax's mkdir() is recursive by default
|
|
59
|
+
await Deno.mkdir(lockPath.toString());
|
|
60
|
+
// Write PID and timestamp for stale lock detection
|
|
61
|
+
const infoPath = lockPath.join("info");
|
|
62
|
+
await infoPath.writeJsonPretty({ pid: Deno.pid, timestamp: Date.now() });
|
|
63
|
+
return {
|
|
64
|
+
async release() {
|
|
65
|
+
try {
|
|
66
|
+
await lockPath.remove({ recursive: true });
|
|
67
|
+
} catch {
|
|
68
|
+
// Ignore errors during cleanup
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
} catch (e) {
|
|
73
|
+
if (!(e instanceof Deno.errors.AlreadyExists)) {
|
|
74
|
+
throw e;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check if lock is stale
|
|
78
|
+
try {
|
|
79
|
+
const infoPath = lockPath.join("info");
|
|
80
|
+
const infoStat = await infoPath.stat();
|
|
81
|
+
if (
|
|
82
|
+
infoStat?.mtime &&
|
|
83
|
+
Date.now() - infoStat.mtime.getTime() > LOCK_STALE_MS
|
|
84
|
+
) {
|
|
85
|
+
console.warn("Removing stale lock:", lockPath.toString());
|
|
86
|
+
await lockPath.remove({ recursive: true });
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
// If we can't read the info file, try to remove the lock
|
|
91
|
+
try {
|
|
92
|
+
await lockPath.remove({ recursive: true });
|
|
93
|
+
continue;
|
|
94
|
+
} catch {
|
|
95
|
+
// Ignore
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Check timeout
|
|
100
|
+
if (Date.now() - startTime > LOCK_TIMEOUT_MS) {
|
|
101
|
+
throw new Error(`Timeout waiting for lock: ${lockPath}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Wait and retry
|
|
105
|
+
await $.sleep(LOCK_RETRY_MS);
|
|
106
|
+
}
|
|
9
107
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function codegen() {
|
|
111
|
+
const scriptsDir = $.path(import.meta.dirname!);
|
|
112
|
+
const packageDir = scriptsDir.parent()!;
|
|
113
|
+
const schemaDir = packageDir.join("src");
|
|
114
|
+
const realPath = schemaDir.join("vocab.ts");
|
|
115
|
+
const lockPath = packageDir.join(".vocab-codegen.lock");
|
|
116
|
+
|
|
117
|
+
// Acquire lock to prevent concurrent codegen
|
|
118
|
+
const lock = await acquireLock(lockPath);
|
|
119
|
+
try {
|
|
120
|
+
// Check if regeneration is needed (after acquiring lock)
|
|
121
|
+
if (await isUpToDate(schemaDir, realPath)) {
|
|
122
|
+
$.log("vocab.ts is up to date, skipping codegen");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
13
125
|
|
|
14
|
-
|
|
15
|
-
|
|
126
|
+
$.logStep("Generating", "vocab.ts...");
|
|
127
|
+
|
|
128
|
+
// Generate to a temporary file first
|
|
129
|
+
const generatedPath = schemaDir.join(`vocab-${crypto.randomUUID()}.ts`);
|
|
130
|
+
try {
|
|
131
|
+
await generateVocab(schemaDir.toString(), generatedPath.toString());
|
|
132
|
+
await generatedPath.rename(realPath);
|
|
133
|
+
} catch (e) {
|
|
134
|
+
// Clean up temp file on error
|
|
135
|
+
await generatedPath.remove().catch(() => {});
|
|
136
|
+
throw e;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
$.logStep("Formatting", "vocab.ts...");
|
|
140
|
+
await $`deno fmt ${realPath}`;
|
|
141
|
+
|
|
142
|
+
$.logStep("Caching", "vocab.ts...");
|
|
143
|
+
await $`deno cache ${realPath}`;
|
|
144
|
+
|
|
145
|
+
$.logStep("Type checking", "vocab.ts...");
|
|
146
|
+
await $`deno check ${realPath}`;
|
|
147
|
+
|
|
148
|
+
$.logStep("Codegen", "completed successfully");
|
|
149
|
+
} finally {
|
|
150
|
+
await lock.release();
|
|
151
|
+
}
|
|
16
152
|
}
|
|
17
153
|
|
|
18
154
|
if (import.meta.main) {
|