@fedify/vocab-tools 2.0.0-dev.12 → 2.0.0-dev.158
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/LICENSE +1 -1
- package/deno.json +6 -1
- package/dist/__snapshots__/class.test.ts.deno.snap +81555 -0
- package/dist/__snapshots__/class.test.ts.node.snap +81553 -0
- package/dist/__snapshots__/class.test.ts.snap +81555 -0
- package/dist/class.test.d.ts +1 -0
- package/dist/class.test.js +1893 -0
- package/dist/fs-B12zeNxV.js +19 -0
- package/dist/fs.test.d.ts +1 -0
- package/dist/fs.test.js +28 -0
- package/dist/mod.cjs +3 -1
- package/dist/mod.js +3 -1
- package/dist/schema-s8NE7Bb_.js +96 -0
- package/dist/schema.test.d.ts +1 -0
- package/dist/schema.test.js +140 -0
- package/package.json +1 -1
- package/src/class.test.ts +3 -3
- package/tsdown.config.ts +52 -17
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { readdir } from "node:fs/promises";
|
|
3
|
+
|
|
4
|
+
//#region src/fs.ts
|
|
5
|
+
/**
|
|
6
|
+
* Recursively read a directory, yielding the paths of all files. File paths
|
|
7
|
+
* are relative to the directory, and directories are not yielded.
|
|
8
|
+
* @param dir The directory to read.
|
|
9
|
+
* @returns An async iterable of file paths.
|
|
10
|
+
*/
|
|
11
|
+
async function* readDirRecursive(dir) {
|
|
12
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) if (entry.isDirectory()) {
|
|
13
|
+
const path = join(dir, entry.name);
|
|
14
|
+
for await (const subentry of readDirRecursive(path)) yield join(entry.name, subentry);
|
|
15
|
+
} else yield entry.name;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
export { readDirRecursive };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/fs.test.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { readDirRecursive } from "./fs-B12zeNxV.js";
|
|
2
|
+
import { deepStrictEqual } from "node:assert";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { test } from "node:test";
|
|
5
|
+
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
|
|
8
|
+
//#region src/fs.test.ts
|
|
9
|
+
test("readDirRecursive()", async () => {
|
|
10
|
+
const dir = await mkdtemp(join(tmpdir(), "fedify-test-"));
|
|
11
|
+
await mkdir(join(dir, "a"));
|
|
12
|
+
await writeFile(join(dir, "a", "aa.txt"), "aa");
|
|
13
|
+
await writeFile(join(dir, "a", "ab.txt"), "aa");
|
|
14
|
+
await mkdir(join(dir, "a", "aa"));
|
|
15
|
+
await writeFile(join(dir, "a", "aa", "aaa.txt"), "aaa");
|
|
16
|
+
await mkdir(join(dir, "b"));
|
|
17
|
+
await writeFile(join(dir, "b", "ba.txt"), "ba");
|
|
18
|
+
await writeFile(join(dir, "b", "bb.txt"), "bb");
|
|
19
|
+
deepStrictEqual(new Set(await Array.fromAsync(readDirRecursive(dir))), new Set([
|
|
20
|
+
join("a", "aa", "aaa.txt"),
|
|
21
|
+
join("a", "aa.txt"),
|
|
22
|
+
join("a", "ab.txt"),
|
|
23
|
+
join("b", "ba.txt"),
|
|
24
|
+
join("b", "bb.txt")
|
|
25
|
+
]));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
//#endregion
|
package/dist/mod.cjs
CHANGED
|
@@ -31,7 +31,7 @@ const es_toolkit = __toESM(require("es-toolkit"));
|
|
|
31
31
|
|
|
32
32
|
//#region deno.json
|
|
33
33
|
var name = "@fedify/vocab-tools";
|
|
34
|
-
var version = "2.0.0-dev.
|
|
34
|
+
var version = "2.0.0-dev.158+628cd89e";
|
|
35
35
|
var license = "MIT";
|
|
36
36
|
var exports$1 = { ".": "./src/mod.ts" };
|
|
37
37
|
var author = {
|
|
@@ -48,6 +48,7 @@ var exclude = [
|
|
|
48
48
|
"node_modules",
|
|
49
49
|
"src/schema.yaml"
|
|
50
50
|
];
|
|
51
|
+
var publish = { "exclude": ["**/*.test.ts"] };
|
|
51
52
|
var tasks = {
|
|
52
53
|
"check": "deno fmt --check && deno lint && deno check src/*.ts",
|
|
53
54
|
"test": "deno test -A"
|
|
@@ -60,6 +61,7 @@ var deno_default = {
|
|
|
60
61
|
author,
|
|
61
62
|
imports,
|
|
62
63
|
exclude,
|
|
64
|
+
publish,
|
|
63
65
|
tasks
|
|
64
66
|
};
|
|
65
67
|
|
package/dist/mod.js
CHANGED
|
@@ -8,7 +8,7 @@ import { pascalCase } from "es-toolkit";
|
|
|
8
8
|
|
|
9
9
|
//#region deno.json
|
|
10
10
|
var name = "@fedify/vocab-tools";
|
|
11
|
-
var version = "2.0.0-dev.
|
|
11
|
+
var version = "2.0.0-dev.158+628cd89e";
|
|
12
12
|
var license = "MIT";
|
|
13
13
|
var exports = { ".": "./src/mod.ts" };
|
|
14
14
|
var author = {
|
|
@@ -25,6 +25,7 @@ var exclude = [
|
|
|
25
25
|
"node_modules",
|
|
26
26
|
"src/schema.yaml"
|
|
27
27
|
];
|
|
28
|
+
var publish = { "exclude": ["**/*.test.ts"] };
|
|
28
29
|
var tasks = {
|
|
29
30
|
"check": "deno fmt --check && deno lint && deno check src/*.ts",
|
|
30
31
|
"test": "deno test -A"
|
|
@@ -37,6 +38,7 @@ var deno_default = {
|
|
|
37
38
|
author,
|
|
38
39
|
imports,
|
|
39
40
|
exclude,
|
|
41
|
+
publish,
|
|
40
42
|
tasks
|
|
41
43
|
};
|
|
42
44
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readDirRecursive } from "./fs-B12zeNxV.js";
|
|
2
|
+
import { join, posix } from "node:path";
|
|
3
|
+
import { Validator } from "@cfworker/json-schema";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { parse } from "yaml";
|
|
7
|
+
|
|
8
|
+
//#region src/schema.ts
|
|
9
|
+
/**
|
|
10
|
+
* Type guard to check if a property is not functional (has pluralName).
|
|
11
|
+
*/
|
|
12
|
+
function isNonFunctionalProperty(property) {
|
|
13
|
+
return property.functional !== true;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Type guard to check if a property has singular accessor.
|
|
17
|
+
*/
|
|
18
|
+
function hasSingularAccessor(property) {
|
|
19
|
+
if (property.functional === true) return true;
|
|
20
|
+
return isNonFunctionalProperty(property) && property.singularAccessor === true;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* An error that occurred while loading a schema file.
|
|
24
|
+
*/
|
|
25
|
+
var SchemaError = class extends Error {
|
|
26
|
+
/**
|
|
27
|
+
* The path of the schema file.
|
|
28
|
+
*/
|
|
29
|
+
path;
|
|
30
|
+
/**
|
|
31
|
+
* Constructs a new `SchemaError`.
|
|
32
|
+
* @param path The path of the schema file.
|
|
33
|
+
* @param message The error message.
|
|
34
|
+
*/
|
|
35
|
+
constructor(path, message) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.path = path;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
async function loadSchemaValidator() {
|
|
41
|
+
const thisFile = import.meta.url;
|
|
42
|
+
const schemaFile = new URL(posix.join(posix.dirname(thisFile), "schema.yaml"));
|
|
43
|
+
let content;
|
|
44
|
+
if (schemaFile.protocol !== "file:") {
|
|
45
|
+
const response = await fetch(schemaFile);
|
|
46
|
+
content = await response.text();
|
|
47
|
+
} else content = await readFile(fileURLToPath(schemaFile), { encoding: "utf-8" });
|
|
48
|
+
const schemaObject = parse(content);
|
|
49
|
+
return new Validator(schemaObject);
|
|
50
|
+
}
|
|
51
|
+
let schemaValidator = void 0;
|
|
52
|
+
async function loadSchema(path) {
|
|
53
|
+
const content = await readFile(path, { encoding: "utf-8" });
|
|
54
|
+
const schema = parse(content);
|
|
55
|
+
if (schemaValidator == null) schemaValidator = await loadSchemaValidator();
|
|
56
|
+
const result = schemaValidator.validate(schema);
|
|
57
|
+
const errors = [];
|
|
58
|
+
if (result.valid) return schema;
|
|
59
|
+
for (const e of result.errors) errors.push(new SchemaError(path, `${path}:${e.instanceLocation}: ${e.error}`));
|
|
60
|
+
throw new AggregateError(errors);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Loads all schema files in the directory.
|
|
64
|
+
* @param dir The path of the directory to load schema files from.
|
|
65
|
+
* @returns A map from the qualified URI of a type to its {@link SchemaFile}.
|
|
66
|
+
* @throws {@link AggregateError} if any schema file is invalid. It contains
|
|
67
|
+
* all {@link SchemaError}s of the invalid schema files.
|
|
68
|
+
*/
|
|
69
|
+
async function loadSchemaFiles(dir) {
|
|
70
|
+
if (typeof dir !== "string") throw new TypeError("Expected a directory path in string");
|
|
71
|
+
const result = {};
|
|
72
|
+
const errors = [];
|
|
73
|
+
for await (const relPath of readDirRecursive(dir)) {
|
|
74
|
+
if (!relPath.match(/\.ya?ml$/i)) continue;
|
|
75
|
+
if (relPath.match(/(^|[/\\])schema.yaml$/i)) continue;
|
|
76
|
+
const path = join(dir, relPath);
|
|
77
|
+
let schema;
|
|
78
|
+
try {
|
|
79
|
+
schema = await loadSchema(path);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
if (e instanceof AggregateError && e.errors.length > 0 && e.errors[0] instanceof SchemaError) {
|
|
82
|
+
errors.push(...e.errors);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
throw e;
|
|
86
|
+
}
|
|
87
|
+
result[schema.uri] = schema;
|
|
88
|
+
}
|
|
89
|
+
if (errors.length > 0) throw new AggregateError(errors);
|
|
90
|
+
const entries = Object.entries(result);
|
|
91
|
+
entries.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
92
|
+
return Object.fromEntries(entries);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
export { hasSingularAccessor, isNonFunctionalProperty, loadSchemaFiles };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import "./fs-B12zeNxV.js";
|
|
2
|
+
import { hasSingularAccessor, isNonFunctionalProperty } from "./schema-s8NE7Bb_.js";
|
|
3
|
+
import { deepStrictEqual, ok } from "node:assert";
|
|
4
|
+
import { test } from "node:test";
|
|
5
|
+
|
|
6
|
+
//#region src/schema.test.ts
|
|
7
|
+
test("isNonFunctionalProperty: returns true for non-functional property", () => {
|
|
8
|
+
const property = {
|
|
9
|
+
singularName: "name",
|
|
10
|
+
pluralName: "names",
|
|
11
|
+
uri: "https://example.com/name",
|
|
12
|
+
description: "A name property",
|
|
13
|
+
range: ["https://example.com/Text"],
|
|
14
|
+
functional: false
|
|
15
|
+
};
|
|
16
|
+
ok(isNonFunctionalProperty(property));
|
|
17
|
+
if (isNonFunctionalProperty(property)) {
|
|
18
|
+
const _pluralName = property.pluralName;
|
|
19
|
+
const _singularAccessor = property.singularAccessor;
|
|
20
|
+
const _container = property.container;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
test("isNonFunctionalProperty: returns true for property without functional field", () => {
|
|
24
|
+
const property = {
|
|
25
|
+
singularName: "name",
|
|
26
|
+
pluralName: "names",
|
|
27
|
+
uri: "https://example.com/name",
|
|
28
|
+
description: "A name property",
|
|
29
|
+
range: ["https://example.com/Text"]
|
|
30
|
+
};
|
|
31
|
+
ok(isNonFunctionalProperty(property));
|
|
32
|
+
});
|
|
33
|
+
test("isNonFunctionalProperty: returns false for functional property", () => {
|
|
34
|
+
const property = {
|
|
35
|
+
singularName: "id",
|
|
36
|
+
uri: "https://example.com/id",
|
|
37
|
+
description: "An ID property",
|
|
38
|
+
range: ["https://example.com/ID"],
|
|
39
|
+
functional: true
|
|
40
|
+
};
|
|
41
|
+
ok(!isNonFunctionalProperty(property));
|
|
42
|
+
});
|
|
43
|
+
test("hasSingularAccessor: returns true for functional property", () => {
|
|
44
|
+
const property = {
|
|
45
|
+
singularName: "id",
|
|
46
|
+
uri: "https://example.com/id",
|
|
47
|
+
description: "An ID property",
|
|
48
|
+
range: ["https://example.com/ID"],
|
|
49
|
+
functional: true
|
|
50
|
+
};
|
|
51
|
+
ok(hasSingularAccessor(property));
|
|
52
|
+
});
|
|
53
|
+
test("hasSingularAccessor: returns true for non-functional property with singularAccessor", () => {
|
|
54
|
+
const property = {
|
|
55
|
+
singularName: "name",
|
|
56
|
+
pluralName: "names",
|
|
57
|
+
uri: "https://example.com/name",
|
|
58
|
+
description: "A name property",
|
|
59
|
+
range: ["https://example.com/Text"],
|
|
60
|
+
functional: false,
|
|
61
|
+
singularAccessor: true
|
|
62
|
+
};
|
|
63
|
+
ok(hasSingularAccessor(property));
|
|
64
|
+
});
|
|
65
|
+
test("hasSingularAccessor: returns false for non-functional property without singularAccessor", () => {
|
|
66
|
+
const property = {
|
|
67
|
+
singularName: "name",
|
|
68
|
+
pluralName: "names",
|
|
69
|
+
uri: "https://example.com/name",
|
|
70
|
+
description: "A name property",
|
|
71
|
+
range: ["https://example.com/Text"],
|
|
72
|
+
functional: false,
|
|
73
|
+
singularAccessor: false
|
|
74
|
+
};
|
|
75
|
+
ok(!hasSingularAccessor(property));
|
|
76
|
+
});
|
|
77
|
+
test("hasSingularAccessor: returns false for non-functional property with undefined singularAccessor", () => {
|
|
78
|
+
const property = {
|
|
79
|
+
singularName: "name",
|
|
80
|
+
pluralName: "names",
|
|
81
|
+
uri: "https://example.com/name",
|
|
82
|
+
description: "A name property",
|
|
83
|
+
range: ["https://example.com/Text"]
|
|
84
|
+
};
|
|
85
|
+
ok(!hasSingularAccessor(property));
|
|
86
|
+
});
|
|
87
|
+
test("Type guard combinations: functional property with redundantProperties", () => {
|
|
88
|
+
const property = {
|
|
89
|
+
singularName: "type",
|
|
90
|
+
uri: "https://www.w3.org/ns/activitystreams#type",
|
|
91
|
+
description: "The type of the object",
|
|
92
|
+
range: ["https://example.com/Type"],
|
|
93
|
+
functional: true,
|
|
94
|
+
redundantProperties: [{ uri: "https://www.w3.org/1999/02/22-rdf-syntax-ns#type" }]
|
|
95
|
+
};
|
|
96
|
+
ok(!isNonFunctionalProperty(property));
|
|
97
|
+
ok(hasSingularAccessor(property));
|
|
98
|
+
});
|
|
99
|
+
test("Type guard combinations: non-functional property with container", () => {
|
|
100
|
+
const property = {
|
|
101
|
+
singularName: "item",
|
|
102
|
+
pluralName: "items",
|
|
103
|
+
uri: "https://example.com/item",
|
|
104
|
+
description: "List of items",
|
|
105
|
+
range: ["https://example.com/Item"],
|
|
106
|
+
functional: false,
|
|
107
|
+
container: "list"
|
|
108
|
+
};
|
|
109
|
+
ok(isNonFunctionalProperty(property));
|
|
110
|
+
ok(!hasSingularAccessor(property));
|
|
111
|
+
if (isNonFunctionalProperty(property)) deepStrictEqual(property.container, "list");
|
|
112
|
+
});
|
|
113
|
+
test("Type guard combinations: non-functional property with graph container", () => {
|
|
114
|
+
const property = {
|
|
115
|
+
singularName: "member",
|
|
116
|
+
pluralName: "members",
|
|
117
|
+
uri: "https://example.com/member",
|
|
118
|
+
description: "Graph of members",
|
|
119
|
+
range: ["https://example.com/Member"],
|
|
120
|
+
functional: false,
|
|
121
|
+
container: "graph"
|
|
122
|
+
};
|
|
123
|
+
ok(isNonFunctionalProperty(property));
|
|
124
|
+
ok(!hasSingularAccessor(property));
|
|
125
|
+
if (isNonFunctionalProperty(property)) deepStrictEqual(property.container, "graph");
|
|
126
|
+
});
|
|
127
|
+
test("Type guard combinations: untyped property", () => {
|
|
128
|
+
const property = {
|
|
129
|
+
singularName: "value",
|
|
130
|
+
pluralName: "values",
|
|
131
|
+
uri: "https://example.com/value",
|
|
132
|
+
description: "Untyped values",
|
|
133
|
+
untyped: true,
|
|
134
|
+
range: ["https://example.com/Value"]
|
|
135
|
+
};
|
|
136
|
+
ok(isNonFunctionalProperty(property));
|
|
137
|
+
ok(!hasSingularAccessor(property));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
//#endregion
|
package/package.json
CHANGED
package/src/class.test.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { deepStrictEqual } from "node:assert";
|
|
2
|
-
import { basename, dirname, join } from "node:path";
|
|
2
|
+
import { basename, dirname, extname, join } from "node:path";
|
|
3
3
|
import { test } from "node:test";
|
|
4
4
|
import metadata from "../deno.json" with { type: "json" };
|
|
5
5
|
import { generateClasses, sortTopologically } from "./class.ts";
|
|
@@ -88,7 +88,7 @@ if ("Deno" in globalThis) {
|
|
|
88
88
|
|
|
89
89
|
async function getEntireCode() {
|
|
90
90
|
const packagesDir = dirname(dirname(import.meta.dirname!));
|
|
91
|
-
const schemaDir = join(packagesDir, "
|
|
91
|
+
const schemaDir = join(packagesDir, "vocab", "src");
|
|
92
92
|
const types = await loadSchemaFiles(schemaDir);
|
|
93
93
|
const entireCode = (await Array.fromAsync(generateClasses(types)))
|
|
94
94
|
.join("")
|
|
@@ -106,7 +106,7 @@ async function changeNodeSnapshotPath() {
|
|
|
106
106
|
return join(
|
|
107
107
|
dirname(path),
|
|
108
108
|
"__snapshots__",
|
|
109
|
-
basename(path) + ".node.snap",
|
|
109
|
+
basename(path.replace(extname(path), ".ts")) + ".node.snap",
|
|
110
110
|
);
|
|
111
111
|
},
|
|
112
112
|
);
|
package/tsdown.config.ts
CHANGED
|
@@ -1,20 +1,55 @@
|
|
|
1
|
-
import { cp } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
1
|
+
import { cp, glob } from "node:fs/promises";
|
|
2
|
+
import { join, sep } from "node:path";
|
|
3
3
|
import { defineConfig } from "tsdown";
|
|
4
4
|
|
|
5
|
-
export default
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
5
|
+
export default [
|
|
6
|
+
defineConfig({
|
|
7
|
+
entry: ["src/mod.ts"],
|
|
8
|
+
dts: true,
|
|
9
|
+
format: ["esm", "cjs"],
|
|
10
|
+
platform: "neutral",
|
|
11
|
+
external: [/^node:/],
|
|
12
|
+
hooks: {
|
|
13
|
+
"build:done": async (ctx) => {
|
|
14
|
+
await cp(
|
|
15
|
+
join("src", "schema.yaml"),
|
|
16
|
+
join(ctx.options.outDir, "schema.yaml"),
|
|
17
|
+
{ force: true },
|
|
18
|
+
);
|
|
19
|
+
},
|
|
18
20
|
},
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
+
}),
|
|
22
|
+
defineConfig({
|
|
23
|
+
entry: (await Array.fromAsync(glob(`src/**/*.test.ts`)))
|
|
24
|
+
.map((f) => f.replace(sep, "/")),
|
|
25
|
+
format: ["esm"],
|
|
26
|
+
platform: "node",
|
|
27
|
+
external: [
|
|
28
|
+
/^node:/,
|
|
29
|
+
/^bun:/,
|
|
30
|
+
],
|
|
31
|
+
inputOptions: {
|
|
32
|
+
onwarn(warning, defaultHandler) {
|
|
33
|
+
if (
|
|
34
|
+
warning.code === "UNRESOLVED_IMPORT" &&
|
|
35
|
+
warning.id?.endsWith(".test.ts") &&
|
|
36
|
+
warning.exporter &&
|
|
37
|
+
["bun:test", "@std/testing/snapshot"].includes(warning.exporter)
|
|
38
|
+
) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
defaultHandler(warning);
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
hooks: {
|
|
45
|
+
"build:done": async (ctx) => {
|
|
46
|
+
await cp(
|
|
47
|
+
join("src", "__snapshots__"),
|
|
48
|
+
join(ctx.options.outDir, "__snapshots__"),
|
|
49
|
+
{ recursive: true },
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
];
|
|
55
|
+
// cSpell: ignore onwarn
|