tsondb 0.2.0 → 0.4.0
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 +385 -0
- package/README.md +173 -1
- package/lib/bin/tsondb.d.ts +8 -0
- package/lib/bin/tsondb.js +83 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +1 -1
- package/lib/{Schema.d.ts → node/Schema.d.ts} +2 -2
- package/lib/{Schema.js → node/Schema.js} +1 -1
- package/lib/node/index.d.ts +8 -0
- package/lib/node/index.js +62 -0
- package/lib/{renderers → node/renderers}/Output.d.ts +1 -1
- package/lib/node/renderers/jsonschema/index.d.ts +6 -0
- package/lib/node/renderers/jsonschema/index.js +35 -0
- package/lib/node/renderers/jsonschema/render.d.ts +9 -0
- package/lib/{renderers → node/renderers}/jsonschema/render.js +42 -23
- package/lib/node/renderers/ts/index.d.ts +6 -0
- package/lib/node/renderers/ts/index.js +42 -0
- package/lib/{renderers → node/renderers}/ts/render.d.ts +3 -1
- package/lib/node/renderers/ts/render.js +136 -0
- package/lib/{schema → node/schema}/Node.d.ts +5 -4
- package/lib/{schema → node/schema}/Node.js +11 -6
- package/lib/{schema/parameters → node/schema}/TypeParameter.d.ts +3 -2
- package/lib/{schema/parameters → node/schema}/TypeParameter.js +2 -2
- package/lib/{schema → node/schema}/declarations/Declaration.d.ts +11 -10
- package/lib/{schema → node/schema}/declarations/Declaration.js +10 -4
- package/lib/{schema → node/schema}/declarations/EntityDecl.d.ts +13 -9
- package/lib/{schema → node/schema}/declarations/EntityDecl.js +2 -2
- package/lib/{schema → node/schema}/declarations/EnumDecl.d.ts +11 -26
- package/lib/node/schema/declarations/EnumDecl.js +52 -0
- package/lib/{schema → node/schema}/declarations/TypeAliasDecl.d.ts +8 -7
- package/lib/{schema → node/schema}/declarations/TypeAliasDecl.js +3 -3
- package/lib/{schema → node/schema}/index.d.ts +4 -3
- package/lib/{schema → node/schema}/index.js +3 -3
- package/lib/node/schema/types/Type.d.ts +48 -0
- package/lib/{schema → node/schema}/types/Type.js +90 -28
- package/lib/{schema → node/schema}/types/generic/ArrayType.d.ts +6 -4
- package/lib/{schema → node/schema}/types/generic/ArrayType.js +5 -4
- package/lib/node/schema/types/generic/EnumType.d.ts +39 -0
- package/lib/node/schema/types/generic/EnumType.js +98 -0
- package/lib/{schema → node/schema}/types/generic/ObjectType.d.ts +9 -7
- package/lib/{schema → node/schema}/types/generic/ObjectType.js +11 -3
- package/lib/{schema → node/schema}/types/primitives/BooleanType.d.ts +5 -3
- package/lib/{schema → node/schema}/types/primitives/BooleanType.js +1 -0
- package/lib/{schema → node/schema}/types/primitives/DateType.d.ts +6 -4
- package/lib/{schema → node/schema}/types/primitives/DateType.js +2 -1
- package/lib/{schema → node/schema}/types/primitives/FloatType.d.ts +6 -4
- package/lib/{schema → node/schema}/types/primitives/FloatType.js +2 -1
- package/lib/{schema → node/schema}/types/primitives/IntegerType.d.ts +6 -4
- package/lib/{schema → node/schema}/types/primitives/IntegerType.js +2 -1
- package/lib/{schema → node/schema}/types/primitives/NumericType.d.ts +2 -2
- package/lib/node/schema/types/primitives/PrimitiveType.d.ts +6 -0
- package/lib/{schema → node/schema}/types/primitives/StringType.d.ts +6 -4
- package/lib/{schema → node/schema}/types/primitives/StringType.js +2 -1
- package/lib/{schema → node/schema}/types/references/IncludeIdentifierType.d.ts +11 -8
- package/lib/{schema → node/schema}/types/references/IncludeIdentifierType.js +15 -2
- package/lib/{schema → node/schema}/types/references/NestedEntityMapType.d.ts +11 -9
- package/lib/{schema → node/schema}/types/references/NestedEntityMapType.js +6 -2
- package/lib/{schema → node/schema}/types/references/ReferenceIdentifierType.d.ts +8 -6
- package/lib/{schema → node/schema}/types/references/ReferenceIdentifierType.js +1 -0
- package/lib/node/schema/types/references/TypeArgumentType.d.ts +23 -0
- package/lib/node/schema/types/references/TypeArgumentType.js +19 -0
- package/lib/node/schema/validation/type.d.ts +4 -0
- package/lib/node/server/api/declarations.d.ts +1 -0
- package/lib/node/server/api/declarations.js +154 -0
- package/lib/node/server/api/git.d.ts +1 -0
- package/lib/node/server/api/git.js +178 -0
- package/lib/node/server/api/index.d.ts +1 -0
- package/lib/node/server/api/index.js +8 -0
- package/lib/node/server/api/instanceOperations.d.ts +6 -0
- package/lib/node/server/api/instanceOperations.js +91 -0
- package/lib/node/server/api/instances.d.ts +1 -0
- package/lib/node/server/api/instances.js +27 -0
- package/lib/node/server/index.d.ts +28 -0
- package/lib/node/server/index.js +53 -0
- package/lib/node/server/init.d.ts +5 -0
- package/lib/node/server/init.js +56 -0
- package/lib/{utils → node/utils}/error.js +4 -1
- package/lib/node/utils/git.d.ts +3 -0
- package/lib/node/utils/git.js +12 -0
- package/lib/node/utils/instances.d.ts +5 -0
- package/lib/node/utils/instances.js +21 -0
- package/lib/node/utils/path.d.ts +1 -0
- package/lib/node/utils/path.js +2 -0
- package/lib/node/utils/references.d.ts +7 -0
- package/lib/node/utils/references.js +40 -0
- package/lib/node/utils/render.d.ts +9 -0
- package/lib/node/utils/render.js +34 -0
- package/lib/shared/api.d.ts +19 -2
- package/lib/shared/utils/array.d.ts +19 -0
- package/lib/shared/utils/array.js +30 -0
- package/lib/shared/utils/displayName.d.ts +1 -1
- package/lib/shared/utils/displayName.js +4 -2
- package/lib/shared/utils/git.d.ts +12 -0
- package/lib/shared/utils/git.js +98 -0
- package/lib/shared/utils/instances.d.ts +10 -0
- package/lib/shared/utils/instances.js +8 -1
- package/lib/{utils → shared/utils}/lazy.js +1 -1
- package/lib/shared/utils/markdown.d.ts +14 -0
- package/lib/shared/utils/markdown.js +42 -0
- package/lib/shared/utils/object.d.ts +4 -0
- package/lib/shared/utils/object.js +5 -0
- package/lib/{utils → shared/utils}/result.js +2 -2
- package/lib/shared/utils/string.d.ts +1 -0
- package/lib/shared/utils/string.js +16 -4
- package/lib/shared/utils/validation.js +3 -2
- package/lib/shared/validation/number.js +3 -3
- package/lib/shared/validation/object.js +4 -3
- package/lib/shared/validation/string.js +12 -7
- package/lib/web/api.d.ts +24 -0
- package/lib/web/api.js +204 -0
- package/lib/web/components/Git.d.ts +2 -0
- package/lib/web/components/Git.js +160 -0
- package/lib/{client → web}/components/Layout.d.ts +1 -1
- package/lib/{client → web}/components/Layout.js +2 -1
- package/lib/web/components/Select.d.ts +3 -0
- package/lib/web/components/Select.js +5 -0
- package/lib/web/components/typeInputs/ArrayTypeInput.d.ts +13 -0
- package/lib/{client → web}/components/typeInputs/ArrayTypeInput.js +8 -1
- package/lib/{client → web}/components/typeInputs/BooleanTypeInput.d.ts +2 -2
- package/lib/{client → web}/components/typeInputs/DateTypeInput.d.ts +2 -2
- package/lib/web/components/typeInputs/EnumTypeInput.d.ts +13 -0
- package/lib/{client/components/typeInputs/utils/EnumDeclField.js → web/components/typeInputs/EnumTypeInput.js} +11 -11
- package/lib/{client → web}/components/typeInputs/FloatTypeInput.d.ts +2 -2
- package/lib/web/components/typeInputs/GenericTypeArgumentIdentifierTypeInput.d.ts +7 -0
- package/lib/{client → web}/components/typeInputs/GenericTypeArgumentIdentifierTypeInput.js +1 -1
- package/lib/web/components/typeInputs/IncludeIdentifierTypeInput.d.ts +13 -0
- package/lib/web/components/typeInputs/IncludeIdentifierTypeInput.js +9 -0
- package/lib/{client → web}/components/typeInputs/IntegerTypeInput.d.ts +2 -2
- package/lib/web/components/typeInputs/NestedEntityMapTypeInput.d.ts +13 -0
- package/lib/{client → web}/components/typeInputs/NestedEntityMapTypeInput.js +7 -2
- package/lib/{client → web}/components/typeInputs/ObjectTypeInput.d.ts +4 -4
- package/lib/{client → web}/components/typeInputs/ObjectTypeInput.js +4 -1
- package/lib/{client → web}/components/typeInputs/ReferenceIdentifierTypeInput.d.ts +3 -3
- package/lib/web/components/typeInputs/ReferenceIdentifierTypeInput.js +11 -0
- package/lib/{client → web}/components/typeInputs/StringTypeInput.d.ts +2 -2
- package/lib/web/components/typeInputs/TypeInput.d.ts +13 -0
- package/lib/{client → web}/components/typeInputs/TypeInput.js +6 -3
- package/lib/{client → web}/components/typeInputs/utils/Markdown.d.ts +1 -1
- package/lib/web/components/typeInputs/utils/Markdown.js +26 -0
- package/lib/{client → web}/components/typeInputs/utils/MismatchingTypeError.d.ts +1 -1
- package/lib/{client → web}/components/typeInputs/utils/ValidationErrors.d.ts +1 -1
- package/lib/web/hooks/useAPIResource.d.ts +1 -0
- package/lib/web/hooks/useAPIResource.js +2 -0
- package/lib/{client → web}/hooks/useEntityFromRoute.d.ts +1 -1
- package/lib/{client → web}/hooks/useEntityFromRoute.js +1 -1
- package/lib/{client → web}/hooks/useInstanceNamesByEntity.d.ts +1 -1
- package/lib/{client → web}/hooks/useInstanceNamesByEntity.js +8 -6
- package/lib/web/hooks/useMappedAPIResource.d.ts +1 -0
- package/lib/web/hooks/useMappedAPIResource.js +17 -0
- package/lib/{client → web}/hooks/useSecondaryDeclarations.d.ts +1 -1
- package/lib/{client → web}/hooks/useSecondaryDeclarations.js +4 -2
- package/lib/{client → web}/routes/CreateInstance.d.ts +1 -1
- package/lib/{client → web}/routes/CreateInstance.js +4 -2
- package/lib/web/routes/Entity.d.ts +2 -0
- package/lib/web/routes/Entity.js +43 -0
- package/lib/web/routes/Home.d.ts +2 -0
- package/lib/web/routes/Home.js +9 -0
- package/lib/{client → web}/routes/Instance.d.ts +1 -1
- package/lib/{client → web}/routes/Instance.js +14 -8
- package/lib/{client → web}/routes/NotFound.d.ts +1 -1
- package/lib/web/utils/typeSkeleton.d.ts +3 -0
- package/lib/{client → web}/utils/typeSkeleton.js +14 -17
- package/package.json +35 -15
- package/public/css/styles.css +200 -1
- package/lib/ModelContainer.d.ts +0 -17
- package/lib/ModelContainer.js +0 -63
- package/lib/client/api.d.ts +0 -11
- package/lib/client/api.js +0 -83
- package/lib/client/components/Select.d.ts +0 -3
- package/lib/client/components/Select.js +0 -2
- package/lib/client/components/typeInputs/ArrayTypeInput.d.ts +0 -13
- package/lib/client/components/typeInputs/GenericTypeArgumentIdentifierTypeInput.d.ts +0 -7
- package/lib/client/components/typeInputs/IncludeIdentifierTypeInput.d.ts +0 -13
- package/lib/client/components/typeInputs/IncludeIdentifierTypeInput.js +0 -18
- package/lib/client/components/typeInputs/NestedEntityMapTypeInput.d.ts +0 -13
- package/lib/client/components/typeInputs/ReferenceIdentifierTypeInput.js +0 -9
- package/lib/client/components/typeInputs/TypeInput.d.ts +0 -13
- package/lib/client/components/typeInputs/utils/EnumDeclField.d.ts +0 -13
- package/lib/client/components/typeInputs/utils/Markdown.js +0 -57
- package/lib/client/routes/Entity.d.ts +0 -2
- package/lib/client/routes/Entity.js +0 -47
- package/lib/client/routes/Home.d.ts +0 -2
- package/lib/client/routes/Home.js +0 -18
- package/lib/client/utils/typeSkeleton.d.ts +0 -3
- package/lib/renderers/jsonschema/index.d.ts +0 -6
- package/lib/renderers/jsonschema/index.js +0 -12
- package/lib/renderers/jsonschema/render.d.ts +0 -5
- package/lib/renderers/ts/index.d.ts +0 -6
- package/lib/renderers/ts/index.js +0 -11
- package/lib/renderers/ts/render.js +0 -112
- package/lib/schema/declarations/EnumDecl.js +0 -115
- package/lib/schema/types/Type.d.ts +0 -42
- package/lib/schema/types/primitives/PrimitiveType.d.ts +0 -6
- package/lib/schema/types/references/GenericArgumentIdentifierType.d.ts +0 -21
- package/lib/schema/types/references/GenericArgumentIdentifierType.js +0 -18
- package/lib/schema/validation/type.d.ts +0 -4
- package/lib/server/index.d.ts +0 -8
- package/lib/server/index.js +0 -207
- package/lib/server/instanceOperations.d.ts +0 -7
- package/lib/server/instanceOperations.js +0 -67
- package/lib/tsconfig.tsbuildinfo +0 -1
- package/lib/utils/instances.d.ts +0 -4
- package/lib/utils/instances.js +0 -12
- package/lib/utils/object.d.ts +0 -3
- package/lib/utils/object.js +0 -1
- package/lib/utils/render.d.ts +0 -4
- package/lib/utils/render.js +0 -8
- /package/lib/{renderers → node/renderers}/Output.js +0 -0
- /package/lib/{schema → node/schema}/types/primitives/NumericType.js +0 -0
- /package/lib/{schema → node/schema}/types/primitives/PrimitiveType.js +0 -0
- /package/lib/{schema → node/schema}/validation/options.d.ts +0 -0
- /package/lib/{schema → node/schema}/validation/options.js +0 -0
- /package/lib/{schema → node/schema}/validation/type.js +0 -0
- /package/lib/{utils → node/utils}/error.d.ts +0 -0
- /package/lib/{utils → shared/utils}/enum.d.ts +0 -0
- /package/lib/{utils → shared/utils}/enum.js +0 -0
- /package/lib/{utils → shared/utils}/lazy.d.ts +0 -0
- /package/lib/{utils → shared/utils}/result.d.ts +0 -0
- /package/lib/{client → web}/components/typeInputs/BooleanTypeInput.js +0 -0
- /package/lib/{client → web}/components/typeInputs/DateTypeInput.js +0 -0
- /package/lib/{client → web}/components/typeInputs/FloatTypeInput.js +0 -0
- /package/lib/{client → web}/components/typeInputs/IntegerTypeInput.js +0 -0
- /package/lib/{client → web}/components/typeInputs/StringTypeInput.js +0 -0
- /package/lib/{client → web}/components/typeInputs/utils/MismatchingTypeError.js +0 -0
- /package/lib/{client → web}/components/typeInputs/utils/ValidationErrors.js +0 -0
- /package/lib/{client → web}/index.d.ts +0 -0
- /package/lib/{client → web}/index.js +0 -0
- /package/lib/{client → web}/routes/NotFound.js +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Output } from "./renderers/Output.ts";
|
|
2
|
+
import type { Schema } from "./Schema.ts";
|
|
3
|
+
import type { ServerOptions } from "./server/index.ts";
|
|
4
|
+
export declare const generateOutputs: (schema: Schema, outputs: Output[]) => Promise<void>;
|
|
5
|
+
export declare const validate: (schema: Schema, dataRootPath: string) => Promise<void>;
|
|
6
|
+
export declare const generateAndValidate: (schema: Schema, outputs: Output[], dataRootPath: string) => Promise<void>;
|
|
7
|
+
export declare const serve: (schema: Schema, dataRootPath: string, serverOptions?: Partial<ServerOptions>) => Promise<void>;
|
|
8
|
+
export declare const generateValidateAndServe: (schema: Schema, outputs: Output[], dataRootPath: string, serverOptions?: Partial<ServerOptions>) => Promise<void>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import Debug from "debug";
|
|
2
|
+
import { mkdir } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { parallelizeErrors } from "../shared/utils/validation.js";
|
|
5
|
+
import { getEntities } from "./Schema.js";
|
|
6
|
+
import { createValidators, validateEntityDecl } from "./schema/index.js";
|
|
7
|
+
import { createServer } from "./server/index.js";
|
|
8
|
+
import { getErrorMessageForDisplay, wrapErrorsIfAny } from "./utils/error.js";
|
|
9
|
+
import { getInstancesByEntityName } from "./utils/instances.js";
|
|
10
|
+
const debug = Debug("tsondb:schema");
|
|
11
|
+
const prepareFolders = async (dataRootPath, entities) => {
|
|
12
|
+
await mkdir(dataRootPath, { recursive: true });
|
|
13
|
+
for (const entity of entities) {
|
|
14
|
+
const entityDir = join(dataRootPath, entity.name);
|
|
15
|
+
await mkdir(entityDir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export const generateOutputs = async (schema, outputs) => {
|
|
19
|
+
for (const output of outputs) {
|
|
20
|
+
await output.run(schema);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const _validate = (entities, instancesByEntityName) => {
|
|
24
|
+
const errors = entities.flatMap(entity => parallelizeErrors(instancesByEntityName[entity.name]?.map(instance => wrapErrorsIfAny(`in file "${entity.name}/${instance.fileName}"`, validateEntityDecl(createValidators(instancesByEntityName), entity, instance.content))) ?? []));
|
|
25
|
+
if (errors.length === 0) {
|
|
26
|
+
debug("All entities are valid");
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
debug("Errors:\n");
|
|
30
|
+
for (const error of errors) {
|
|
31
|
+
debug(getErrorMessageForDisplay(error) + "\n");
|
|
32
|
+
}
|
|
33
|
+
throw new Error("Validation failed");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
export const validate = async (schema, dataRootPath) => {
|
|
37
|
+
const entities = getEntities(schema);
|
|
38
|
+
await prepareFolders(dataRootPath, entities);
|
|
39
|
+
const instancesByEntityName = await getInstancesByEntityName(dataRootPath, entities);
|
|
40
|
+
_validate(entities, instancesByEntityName);
|
|
41
|
+
};
|
|
42
|
+
export const generateAndValidate = async (schema, outputs, dataRootPath) => {
|
|
43
|
+
await generateOutputs(schema, outputs);
|
|
44
|
+
const entities = getEntities(schema);
|
|
45
|
+
await prepareFolders(dataRootPath, entities);
|
|
46
|
+
const instancesByEntityName = await getInstancesByEntityName(dataRootPath, entities);
|
|
47
|
+
_validate(entities, instancesByEntityName);
|
|
48
|
+
};
|
|
49
|
+
export const serve = async (schema, dataRootPath, serverOptions) => {
|
|
50
|
+
const entities = getEntities(schema);
|
|
51
|
+
await prepareFolders(dataRootPath, entities);
|
|
52
|
+
const instancesByEntityName = await getInstancesByEntityName(dataRootPath, entities);
|
|
53
|
+
await createServer(schema, dataRootPath, instancesByEntityName, serverOptions);
|
|
54
|
+
};
|
|
55
|
+
export const generateValidateAndServe = async (schema, outputs, dataRootPath, serverOptions) => {
|
|
56
|
+
await generateOutputs(schema, outputs);
|
|
57
|
+
const entities = getEntities(schema);
|
|
58
|
+
await prepareFolders(dataRootPath, entities);
|
|
59
|
+
const instancesByEntityName = await getInstancesByEntityName(dataRootPath, entities);
|
|
60
|
+
_validate(entities, instancesByEntityName);
|
|
61
|
+
await createServer(schema, dataRootPath, instancesByEntityName, serverOptions);
|
|
62
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, extname, join, relative } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { commonPrefix } from "../../../shared/utils/string.js";
|
|
5
|
+
import { groupDeclarationsBySourceUrl, resolveTypeArgumentsInDecls } from "../../schema/index.js";
|
|
6
|
+
import { render } from "./render.js";
|
|
7
|
+
const extension = ".schema.json";
|
|
8
|
+
export const JsonSchemaOutput = (options) => ({
|
|
9
|
+
run: async (schema) => {
|
|
10
|
+
if (options.rendererOptions?.preserveFiles === true) {
|
|
11
|
+
await rm(options.targetPath, { recursive: true, force: true });
|
|
12
|
+
await mkdir(options.targetPath, { recursive: true });
|
|
13
|
+
const declarationsBySourceUrl = groupDeclarationsBySourceUrl(resolveTypeArgumentsInDecls(schema.declarations));
|
|
14
|
+
const sourceRootPath = fileURLToPath(commonPrefix(...Object.keys(declarationsBySourceUrl)));
|
|
15
|
+
if (sourceRootPath) {
|
|
16
|
+
for (const [sourceUrl, decls] of Object.entries(declarationsBySourceUrl)) {
|
|
17
|
+
const sourcePath = fileURLToPath(sourceUrl);
|
|
18
|
+
const relativePath = dirname(relative(sourceRootPath, sourcePath));
|
|
19
|
+
const newDir = join(options.targetPath, relativePath);
|
|
20
|
+
const newPath = join(newDir, basename(sourcePath, extname(sourcePath)) + extension);
|
|
21
|
+
await mkdir(newDir, { recursive: true });
|
|
22
|
+
await writeFile(newPath, render(options.rendererOptions, decls ?? []), {
|
|
23
|
+
encoding: "utf-8",
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
await mkdir(dirname(options.targetPath), { recursive: true });
|
|
30
|
+
await writeFile(options.targetPath, render(options.rendererOptions, resolveTypeArgumentsInDecls(schema.declarations)), {
|
|
31
|
+
encoding: "utf-8",
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Decl } from "../../schema/declarations/Declaration.js";
|
|
2
|
+
export type JsonSchemaRendererOptions = {
|
|
3
|
+
format: "minified" | "tabs" | {
|
|
4
|
+
kind: "spaces";
|
|
5
|
+
indentation?: number;
|
|
6
|
+
};
|
|
7
|
+
preserveFiles: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare const render: (options: Partial<JsonSchemaRendererOptions> | undefined, declarations: readonly Decl[]) => string;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import { dirname, relative } from "node:path";
|
|
2
|
+
import { discriminatorKey } from "../../../shared/enum.js";
|
|
3
|
+
import { assertExhaustive } from "../../../shared/utils/typeSafety.js";
|
|
1
4
|
import { addEphemeralUUIDToType, createEntityIdentifierTypeAsDecl, isEntityDecl, } from "../../schema/declarations/EntityDecl.js";
|
|
2
5
|
import { TypeAliasDecl } from "../../schema/declarations/TypeAliasDecl.js";
|
|
3
6
|
import { flatMapAuxiliaryDecls, NodeKind } from "../../schema/Node.js";
|
|
4
|
-
import { isNestedEntityMapType
|
|
7
|
+
import { isNestedEntityMapType } from "../../schema/types/references/NestedEntityMapType.js";
|
|
5
8
|
import { getParentDecl } from "../../schema/types/Type.js";
|
|
6
|
-
import {
|
|
7
|
-
|
|
9
|
+
import { ensureSpecialDirStart } from "../../utils/path.js";
|
|
10
|
+
const defaultIndentation = 2;
|
|
8
11
|
const defaultOptions = {
|
|
9
|
-
|
|
12
|
+
format: { kind: "spaces" },
|
|
13
|
+
preserveFiles: false,
|
|
10
14
|
};
|
|
11
15
|
const renderArrayType = (options, type) => ({
|
|
12
16
|
type: "array",
|
|
@@ -63,21 +67,40 @@ const renderStringType = (_options, type) => ({
|
|
|
63
67
|
maxLength: type.maxLength,
|
|
64
68
|
pattern: type.pattern?.source,
|
|
65
69
|
});
|
|
66
|
-
const
|
|
67
|
-
throw new TypeError("
|
|
70
|
+
const renderTypeArgumentType = (_options, _type) => {
|
|
71
|
+
throw new TypeError("TypeArgumentType is not supported in JSON Schema.");
|
|
68
72
|
};
|
|
69
73
|
const renderReferenceIdentifierType = (_options, type) => ({
|
|
70
74
|
$ref: `#/$defs/${type.entity.name}_ID`,
|
|
71
75
|
});
|
|
72
|
-
const renderIncludeIdentifierType = (
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
const renderIncludeIdentifierType = (options, type) => {
|
|
77
|
+
const sourceUrl = getParentDecl(type)?.sourceUrl ?? "";
|
|
78
|
+
const filePath = options.preserveFiles && sourceUrl !== type.reference.sourceUrl
|
|
79
|
+
? ensureSpecialDirStart(relative(dirname(sourceUrl), type.reference.sourceUrl))
|
|
80
|
+
: "";
|
|
81
|
+
return {
|
|
82
|
+
$ref: `${filePath}#/$defs/${type.reference.name}`,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
75
85
|
const renderNestedEntityMapType = (_options, type) => ({
|
|
76
86
|
type: "object",
|
|
77
87
|
additionalProperties: {
|
|
78
88
|
$ref: `#/$defs/${type.name}`,
|
|
79
89
|
},
|
|
80
90
|
});
|
|
91
|
+
const renderEnumType = (options, type) => ({
|
|
92
|
+
oneOf: Object.entries(type.values).map(([caseName, caseDef]) => ({
|
|
93
|
+
type: "object",
|
|
94
|
+
deprecated: caseDef.isDeprecated,
|
|
95
|
+
properties: {
|
|
96
|
+
[discriminatorKey]: {
|
|
97
|
+
const: caseName,
|
|
98
|
+
},
|
|
99
|
+
...(caseDef.type === null ? {} : { [caseName]: renderType(options, caseDef.type) }),
|
|
100
|
+
},
|
|
101
|
+
required: [discriminatorKey, ...(caseDef.type === null ? [] : [caseName])],
|
|
102
|
+
})),
|
|
103
|
+
});
|
|
81
104
|
const renderType = (options, type) => {
|
|
82
105
|
switch (type.kind) {
|
|
83
106
|
case NodeKind.ArrayType:
|
|
@@ -94,14 +117,16 @@ const renderType = (options, type) => {
|
|
|
94
117
|
return renderIntegerType(options, type);
|
|
95
118
|
case NodeKind.StringType:
|
|
96
119
|
return renderStringType(options, type);
|
|
97
|
-
case NodeKind.
|
|
98
|
-
return
|
|
120
|
+
case NodeKind.TypeArgumentType:
|
|
121
|
+
return renderTypeArgumentType(options, type);
|
|
99
122
|
case NodeKind.ReferenceIdentifierType:
|
|
100
123
|
return renderReferenceIdentifierType(options, type);
|
|
101
124
|
case NodeKind.IncludeIdentifierType:
|
|
102
125
|
return renderIncludeIdentifierType(options, type);
|
|
103
126
|
case NodeKind.NestedEntityMapType:
|
|
104
127
|
return renderNestedEntityMapType(options, type);
|
|
128
|
+
case NodeKind.EnumType:
|
|
129
|
+
return renderEnumType(options, type);
|
|
105
130
|
default:
|
|
106
131
|
return assertExhaustive(type, "Unknown type");
|
|
107
132
|
}
|
|
@@ -114,17 +139,7 @@ const renderEntityDecl = (options, decl) => ({
|
|
|
114
139
|
const renderEnumDecl = (options, decl) => ({
|
|
115
140
|
description: decl.comment,
|
|
116
141
|
deprecated: decl.isDeprecated,
|
|
117
|
-
|
|
118
|
-
type: "object",
|
|
119
|
-
deprecated: caseDef.isDeprecated,
|
|
120
|
-
properties: {
|
|
121
|
-
[discriminatorKey]: {
|
|
122
|
-
const: caseName,
|
|
123
|
-
},
|
|
124
|
-
...(caseDef.type === null ? {} : { [caseName]: renderType(options, caseDef.type) }),
|
|
125
|
-
},
|
|
126
|
-
required: [discriminatorKey, ...(caseDef === null ? [] : [caseName])],
|
|
127
|
-
})),
|
|
142
|
+
...renderEnumType(options, decl.type.value),
|
|
128
143
|
});
|
|
129
144
|
const renderTypeAliasDecl = (options, decl) => ({
|
|
130
145
|
description: decl.comment,
|
|
@@ -160,5 +175,9 @@ export const render = (options = defaultOptions, declarations) => {
|
|
|
160
175
|
}
|
|
161
176
|
return undefined;
|
|
162
177
|
}, declarations)),
|
|
163
|
-
}, undefined, finalOptions.
|
|
178
|
+
}, undefined, finalOptions.format === "minified"
|
|
179
|
+
? undefined
|
|
180
|
+
: finalOptions.format === "tabs"
|
|
181
|
+
? "\t"
|
|
182
|
+
: (finalOptions.format.indentation ?? defaultIndentation));
|
|
164
183
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Debug from "debug";
|
|
2
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, extname, join, relative } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { commonPrefix } from "../../../shared/utils/string.js";
|
|
6
|
+
import { groupDeclarationsBySourceUrl } from "../../schema/declarations/Declaration.js";
|
|
7
|
+
import { render } from "./render.js";
|
|
8
|
+
const debug = Debug("tsondb:renderer:ts");
|
|
9
|
+
const extension = ".d.ts";
|
|
10
|
+
export const TypeScriptOutput = (options) => ({
|
|
11
|
+
run: async (schema) => {
|
|
12
|
+
if (options.rendererOptions?.preserveFiles === true) {
|
|
13
|
+
debug("emitting declarations to multiple files...");
|
|
14
|
+
await rm(options.targetPath, { recursive: true, force: true });
|
|
15
|
+
await mkdir(options.targetPath, { recursive: true });
|
|
16
|
+
const declarationsBySourceUrl = groupDeclarationsBySourceUrl(schema.declarations);
|
|
17
|
+
const sourceRootPath = fileURLToPath(commonPrefix(...Object.keys(declarationsBySourceUrl)));
|
|
18
|
+
debug("common source root path: %s", sourceRootPath);
|
|
19
|
+
if (sourceRootPath) {
|
|
20
|
+
for (const [sourceUrl, decls] of Object.entries(declarationsBySourceUrl)) {
|
|
21
|
+
const sourcePath = fileURLToPath(sourceUrl);
|
|
22
|
+
const relativePath = dirname(relative(sourceRootPath, sourcePath));
|
|
23
|
+
const newDir = join(options.targetPath, relativePath);
|
|
24
|
+
const newPath = join(newDir, basename(sourcePath, extname(sourcePath)) + extension);
|
|
25
|
+
await mkdir(newDir, { recursive: true });
|
|
26
|
+
await writeFile(newPath, render(options.rendererOptions, decls ?? []), {
|
|
27
|
+
encoding: "utf-8",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
debug("emitted declaration files to %s", options.targetPath);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
debug("emitting declarations to single file...");
|
|
35
|
+
await mkdir(dirname(options.targetPath), { recursive: true });
|
|
36
|
+
await writeFile(options.targetPath, render(options.rendererOptions, schema.declarations), {
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
});
|
|
39
|
+
debug("emitted declarations to %s", options.targetPath);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { Decl } from "../../schema/declarations/Declaration.js";
|
|
1
|
+
import type { Decl } from "../../schema/declarations/Declaration.js";
|
|
2
2
|
export type TypeScriptRendererOptions = {
|
|
3
3
|
indentation: number;
|
|
4
|
+
objectTypeKeyword: "interface" | "type";
|
|
5
|
+
preserveFiles: boolean;
|
|
4
6
|
};
|
|
5
7
|
export declare const render: (options: Partial<TypeScriptRendererOptions> | undefined, declarations: readonly Decl[]) => string;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { EOL } from "node:os";
|
|
2
|
+
import { dirname, relative } from "node:path";
|
|
3
|
+
import { discriminatorKey } from "../../../shared/enum.js";
|
|
4
|
+
import { toCamelCase } from "../../../shared/utils/string.js";
|
|
5
|
+
import { assertExhaustive } from "../../../shared/utils/typeSafety.js";
|
|
6
|
+
import { addEphemeralUUIDToType, createEntityIdentifierTypeAsDecl, isEntityDecl, } from "../../schema/declarations/EntityDecl.js";
|
|
7
|
+
import { TypeAliasDecl } from "../../schema/declarations/TypeAliasDecl.js";
|
|
8
|
+
import { flatMapAuxiliaryDecls, NodeKind } from "../../schema/Node.js";
|
|
9
|
+
import { isObjectType } from "../../schema/types/generic/ObjectType.js";
|
|
10
|
+
import { isNestedEntityMapType } from "../../schema/types/references/NestedEntityMapType.js";
|
|
11
|
+
import { getParentDecl } from "../../schema/types/Type.js";
|
|
12
|
+
import { ensureSpecialDirStart } from "../../utils/path.js";
|
|
13
|
+
import { combineSyntaxes, indent, prefixLines, syntax } from "../../utils/render.js";
|
|
14
|
+
const defaultOptions = {
|
|
15
|
+
indentation: 2,
|
|
16
|
+
objectTypeKeyword: "interface",
|
|
17
|
+
preserveFiles: false,
|
|
18
|
+
};
|
|
19
|
+
const renderDocumentation = (comment, isDeprecated) => syntax `${comment === undefined
|
|
20
|
+
? ""
|
|
21
|
+
: syntax `/**
|
|
22
|
+
${prefixLines(" * ", comment, true)}${isDeprecated
|
|
23
|
+
? syntax `
|
|
24
|
+
* @deprecated`
|
|
25
|
+
: ""}
|
|
26
|
+
*/
|
|
27
|
+
`}`;
|
|
28
|
+
const renderTypeParameters = (options, params) => syntax `${params.length === 0
|
|
29
|
+
? ""
|
|
30
|
+
: syntax `<${combineSyntaxes(params.map(param => param.constraint === undefined
|
|
31
|
+
? param.name
|
|
32
|
+
: syntax `${param.name} extends ${renderType(options, param.constraint)}`), ", ")}>`}`;
|
|
33
|
+
const renderArrayType = (options, type) => syntax `${renderType(options, type.items)}[]`;
|
|
34
|
+
const wrapAsObject = (options, str) => syntax `{${EOL}${indent(options.indentation, 1, str)}${EOL}}`;
|
|
35
|
+
const renderObjectType = (options, type) => {
|
|
36
|
+
return wrapAsObject(options, combineSyntaxes(Object.entries(type.properties).map(([name, config]) => syntax `${renderDocumentation(config.comment, config.isDeprecated)}${name}${config.isRequired ? "" : "?"}: ${renderType(options, config.type)}`), Object.values(type.properties).some(prop => prop.comment !== undefined) ? EOL + EOL : EOL));
|
|
37
|
+
};
|
|
38
|
+
const renderBooleanType = (_options, _type) => syntax `boolean`;
|
|
39
|
+
const renderDateType = (_options, _type) => syntax `Date`;
|
|
40
|
+
const renderNumericType = (_options, _type) => syntax `number`;
|
|
41
|
+
const renderStringType = (_options, _type) => syntax `string`;
|
|
42
|
+
const renderTypeArgumentType = (_options, type) => syntax `${type.argument.name}`;
|
|
43
|
+
const renderReferenceIdentifierType = (_options, type) => [
|
|
44
|
+
{ [type.entity.sourceUrl]: [type.entity.name + "_ID"] },
|
|
45
|
+
type.entity.name + "_ID",
|
|
46
|
+
];
|
|
47
|
+
const renderIncludeIdentifierType = (options, type) => combineSyntaxes([
|
|
48
|
+
[{ [type.reference.sourceUrl]: [type.reference.name] }, type.reference.name],
|
|
49
|
+
type.args.length === 0
|
|
50
|
+
? ""
|
|
51
|
+
: syntax `<${combineSyntaxes(type.args.map(arg => renderType(options, arg)), ", ")}>`,
|
|
52
|
+
]);
|
|
53
|
+
const renderNestedEntityMapType = (options, type) => wrapAsObject(options, syntax `[${toCamelCase(type.secondaryEntity.name)}Id: string]: ${type.name}`);
|
|
54
|
+
const renderEnumType = (options, type) => combineSyntaxes(Object.entries(type.values).map(([caseName, caseDef]) => indent(options.indentation, 1, syntax `${EOL}| {${EOL}${indent(options.indentation, 1, syntax `${discriminatorKey}: "${caseName}"${caseDef.type === null
|
|
55
|
+
? ""
|
|
56
|
+
: syntax `${EOL}${caseName}: ${renderType(options, caseDef.type)}`}`)}${EOL}}`)));
|
|
57
|
+
const renderType = (options, type) => {
|
|
58
|
+
switch (type.kind) {
|
|
59
|
+
case NodeKind.ArrayType:
|
|
60
|
+
return renderArrayType(options, type);
|
|
61
|
+
case NodeKind.ObjectType:
|
|
62
|
+
return renderObjectType(options, type);
|
|
63
|
+
case NodeKind.BooleanType:
|
|
64
|
+
return renderBooleanType(options, type);
|
|
65
|
+
case NodeKind.DateType:
|
|
66
|
+
return renderDateType(options, type);
|
|
67
|
+
case NodeKind.FloatType:
|
|
68
|
+
return renderNumericType(options, type);
|
|
69
|
+
case NodeKind.IntegerType:
|
|
70
|
+
return renderNumericType(options, type);
|
|
71
|
+
case NodeKind.StringType:
|
|
72
|
+
return renderStringType(options, type);
|
|
73
|
+
case NodeKind.TypeArgumentType:
|
|
74
|
+
return renderTypeArgumentType(options, type);
|
|
75
|
+
case NodeKind.ReferenceIdentifierType:
|
|
76
|
+
return renderReferenceIdentifierType(options, type);
|
|
77
|
+
case NodeKind.IncludeIdentifierType:
|
|
78
|
+
return renderIncludeIdentifierType(options, type);
|
|
79
|
+
case NodeKind.NestedEntityMapType:
|
|
80
|
+
return renderNestedEntityMapType(options, type);
|
|
81
|
+
case NodeKind.EnumType:
|
|
82
|
+
return renderEnumType(options, type);
|
|
83
|
+
default:
|
|
84
|
+
return assertExhaustive(type, "Unknown type");
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const renderEntityDecl = (options, decl) => syntax `${renderDocumentation(decl.comment, decl.isDeprecated)}export ${options.objectTypeKeyword} ${decl.name} ${options.objectTypeKeyword === "type" ? "= " : ""}${renderType(options, addEphemeralUUIDToType(decl))}`;
|
|
88
|
+
const renderEnumDecl = (options, decl) => syntax `${renderDocumentation(decl.comment, decl.isDeprecated)}export type ${decl.name}${renderTypeParameters(options, decl.parameters)} =${renderEnumType(options, decl.type.value)}`;
|
|
89
|
+
const renderTypeAliasDecl = (options, decl) => isObjectType(decl.type.value)
|
|
90
|
+
? syntax `${renderDocumentation(decl.comment, decl.isDeprecated)}export ${options.objectTypeKeyword} ${decl.name}${renderTypeParameters(options, decl.parameters)} ${options.objectTypeKeyword === "type" ? "= " : ""}${renderType(options, decl.type.value)}`
|
|
91
|
+
: syntax `${renderDocumentation(decl.comment, decl.isDeprecated)}export type ${decl.name}${renderTypeParameters(options, decl.parameters)} = ${renderType(options, decl.type.value)}`;
|
|
92
|
+
const renderDecl = (options, decl) => {
|
|
93
|
+
switch (decl.kind) {
|
|
94
|
+
case NodeKind.EntityDecl:
|
|
95
|
+
return renderEntityDecl(options, decl);
|
|
96
|
+
case NodeKind.EnumDecl:
|
|
97
|
+
return renderEnumDecl(options, decl);
|
|
98
|
+
case NodeKind.TypeAliasDecl:
|
|
99
|
+
return renderTypeAliasDecl(options, decl);
|
|
100
|
+
default:
|
|
101
|
+
return assertExhaustive(decl, "Unknown declaration");
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const renderDeclarations = (options, declarations) => combineSyntaxes(declarations.map(decl => renderDecl(options, decl)), EOL + EOL);
|
|
105
|
+
const renderImports = (currentUrl, imports) => {
|
|
106
|
+
const importsSyntax = Object.entries(imports)
|
|
107
|
+
.filter(([sourceUrl]) => sourceUrl !== currentUrl)
|
|
108
|
+
.map(([sourceUrl, names]) => [
|
|
109
|
+
ensureSpecialDirStart(relative(dirname(currentUrl), sourceUrl)),
|
|
110
|
+
names,
|
|
111
|
+
])
|
|
112
|
+
.toSorted(([sourceUrlA], [sourceUrlB]) => sourceUrlA.localeCompare(sourceUrlB))
|
|
113
|
+
.map(([sourceUrl, names]) => `import { ${names.toSorted((a, b) => a.localeCompare(b)).join(", ")} } from "${sourceUrl}"`)
|
|
114
|
+
.join(EOL);
|
|
115
|
+
return importsSyntax.length > 0 ? importsSyntax + EOL + EOL : "";
|
|
116
|
+
};
|
|
117
|
+
export const render = (options = defaultOptions, declarations) => {
|
|
118
|
+
const finalOptions = { ...defaultOptions, ...options };
|
|
119
|
+
const [imports, content] = renderDeclarations(finalOptions, flatMapAuxiliaryDecls(node => {
|
|
120
|
+
if (isNestedEntityMapType(node)) {
|
|
121
|
+
return TypeAliasDecl(getParentDecl(node)?.sourceUrl ?? "", {
|
|
122
|
+
name: node.name,
|
|
123
|
+
comment: node.comment,
|
|
124
|
+
type: () => node.type.value,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
else if (isEntityDecl(node)) {
|
|
128
|
+
return createEntityIdentifierTypeAsDecl(node);
|
|
129
|
+
}
|
|
130
|
+
return undefined;
|
|
131
|
+
}, declarations));
|
|
132
|
+
return finalOptions.preserveFiles
|
|
133
|
+
? (declarations[0] === undefined ? "" : renderImports(declarations[0].sourceUrl, imports)) +
|
|
134
|
+
content
|
|
135
|
+
: content;
|
|
136
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { InstancesByEntityName } from "
|
|
2
|
-
import { Decl } from "./declarations/Declaration.js";
|
|
3
|
-
import { Type } from "./types/Type.js";
|
|
1
|
+
import type { InstancesByEntityName } from "../../shared/utils/instances.js";
|
|
2
|
+
import type { Decl } from "./declarations/Declaration.js";
|
|
3
|
+
import type { Type } from "./types/Type.js";
|
|
4
4
|
export interface NodeKind {
|
|
5
5
|
EntityDecl: "EntityDecl";
|
|
6
6
|
EnumDecl: "EnumDecl";
|
|
@@ -14,11 +14,12 @@ export interface NodeKind {
|
|
|
14
14
|
IntegerType: "IntegerType";
|
|
15
15
|
StringType: "StringType";
|
|
16
16
|
DateType: "DateType";
|
|
17
|
-
|
|
17
|
+
TypeArgumentType: "TypeArgumentType";
|
|
18
18
|
GenericParameter: "GenericParameter";
|
|
19
19
|
ReferenceIdentifierType: "ReferenceIdentifierType";
|
|
20
20
|
IncludeIdentifierType: "IncludeIdentifierType";
|
|
21
21
|
NestedEntityMapType: "NestedEntityMapType";
|
|
22
|
+
EnumType: "EnumType";
|
|
22
23
|
}
|
|
23
24
|
export declare const NodeKind: NodeKind;
|
|
24
25
|
export interface BaseNode {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { enumOfObject } from "../../shared/utils/enum.js";
|
|
2
|
+
import { assertExhaustive } from "../../shared/utils/typeSafety.js";
|
|
3
3
|
export const NodeKind = enumOfObject({
|
|
4
4
|
EntityDecl: null,
|
|
5
5
|
EnumDecl: null,
|
|
@@ -13,11 +13,12 @@ export const NodeKind = enumOfObject({
|
|
|
13
13
|
IntegerType: null,
|
|
14
14
|
StringType: null,
|
|
15
15
|
DateType: null,
|
|
16
|
-
|
|
16
|
+
TypeArgumentType: null,
|
|
17
17
|
GenericParameter: null,
|
|
18
18
|
ReferenceIdentifierType: null,
|
|
19
19
|
IncludeIdentifierType: null,
|
|
20
20
|
NestedEntityMapType: null,
|
|
21
|
+
EnumType: null,
|
|
21
22
|
});
|
|
22
23
|
export const flatMapAuxiliaryDecls = (callbackFn, declarations) => {
|
|
23
24
|
const mapNodeTree = (callbackFn, node, decls) => {
|
|
@@ -28,7 +29,7 @@ export const flatMapAuxiliaryDecls = (callbackFn, declarations) => {
|
|
|
28
29
|
}
|
|
29
30
|
case NodeKind.EnumDecl: {
|
|
30
31
|
const newDecls = callbackFn(node, decls);
|
|
31
|
-
return
|
|
32
|
+
return mapNodeTree(callbackFn, node.type.value, newDecls);
|
|
32
33
|
}
|
|
33
34
|
case NodeKind.TypeAliasDecl: {
|
|
34
35
|
const newDecls = callbackFn(node, decls);
|
|
@@ -47,11 +48,15 @@ export const flatMapAuxiliaryDecls = (callbackFn, declarations) => {
|
|
|
47
48
|
case NodeKind.FloatType:
|
|
48
49
|
case NodeKind.IntegerType:
|
|
49
50
|
case NodeKind.StringType:
|
|
50
|
-
case NodeKind.
|
|
51
|
+
case NodeKind.TypeArgumentType:
|
|
51
52
|
case NodeKind.ReferenceIdentifierType:
|
|
52
53
|
case NodeKind.IncludeIdentifierType:
|
|
53
54
|
case NodeKind.NestedEntityMapType:
|
|
54
55
|
return callbackFn(node, decls);
|
|
56
|
+
case NodeKind.EnumType: {
|
|
57
|
+
const newDecls = callbackFn(node, decls);
|
|
58
|
+
return Object.values(node.values).reduce((newDeclsAcc, caseDef) => caseDef.type === null ? newDecls : mapNodeTree(callbackFn, caseDef.type, newDeclsAcc), newDecls);
|
|
59
|
+
}
|
|
55
60
|
default:
|
|
56
61
|
return assertExhaustive(node);
|
|
57
62
|
}
|
|
@@ -69,7 +74,7 @@ export const flatMapAuxiliaryDecls = (callbackFn, declarations) => {
|
|
|
69
74
|
return declarations.reduce((decls, node) => mapNodeTree(reducer, node, [...decls, node]), []);
|
|
70
75
|
};
|
|
71
76
|
export const createValidators = (instancesByEntityName) => ({
|
|
72
|
-
checkReferentialIntegrity: ({ name, value }) => instancesByEntityName[name]
|
|
77
|
+
checkReferentialIntegrity: ({ name, value }) => instancesByEntityName[name]?.some(instance => typeof instance.content === "object" &&
|
|
73
78
|
instance.content !== null &&
|
|
74
79
|
!Array.isArray(instance.content) &&
|
|
75
80
|
instance.id === value)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { Serializer } from "./Node.js";
|
|
2
|
+
import { NodeKind } from "./Node.js";
|
|
3
|
+
import type { SerializedBaseType, SerializedType, Type } from "./types/Type.js";
|
|
3
4
|
export interface TypeParameter<N extends string = string, T extends Type = Type> {
|
|
4
5
|
kind: NodeKind["GenericParameter"];
|
|
5
6
|
name: N;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { NodeKind } from "
|
|
2
|
-
import { removeParentKey, serializeType
|
|
1
|
+
import { NodeKind } from "./Node.js";
|
|
2
|
+
import { removeParentKey, serializeType } from "./types/Type.js";
|
|
3
3
|
export const Param = (name, constraint) => ({
|
|
4
4
|
kind: NodeKind.GenericParameter,
|
|
5
5
|
name,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { BaseNode, GetReferences, Node, Serializer } from "../Node.js";
|
|
2
|
-
import { SerializedTypeParameter, TypeParameter } from "../
|
|
3
|
-
import {
|
|
4
|
-
import { SerializedType, Type } from "../types/Type.js";
|
|
5
|
-
import { ValidatorHelpers } from "../validation/type.js";
|
|
6
|
-
import { EntityDecl, SerializedEntityDecl } from "./EntityDecl.js";
|
|
7
|
-
import {
|
|
8
|
-
import { SerializedTypeAliasDecl, TypeAliasDecl } from "./TypeAliasDecl.js";
|
|
1
|
+
import type { BaseNode, GetReferences, Node, Serializer } from "../Node.js";
|
|
2
|
+
import type { SerializedTypeParameter, TypeParameter } from "../TypeParameter.js";
|
|
3
|
+
import type { EnumCaseDecl, SerializedEnumCaseDecl } from "../types/generic/EnumType.js";
|
|
4
|
+
import type { SerializedType, Type } from "../types/Type.js";
|
|
5
|
+
import type { ValidatorHelpers } from "../validation/type.js";
|
|
6
|
+
import type { EntityDecl, SerializedEntityDecl } from "./EntityDecl.js";
|
|
7
|
+
import type { EnumDecl, SerializedEnumDecl } from "./EnumDecl.js";
|
|
8
|
+
import type { SerializedTypeAliasDecl, TypeAliasDecl } from "./TypeAliasDecl.js";
|
|
9
9
|
export type TypeArguments<Params extends TypeParameter[]> = {
|
|
10
10
|
[K in keyof Params]: Params[K] extends TypeParameter<string, infer T> ? T : Type;
|
|
11
11
|
};
|
|
@@ -16,8 +16,8 @@ export declare const getParameterNames: (decl: Decl) => string[];
|
|
|
16
16
|
export declare const getTypeArgumentsRecord: <Params extends TypeParameter[]>(decl: DeclP<Params>, args: TypeArguments<Params>) => Record<string, Type>;
|
|
17
17
|
export type Decl = EntityDecl | EnumDecl | TypeAliasDecl;
|
|
18
18
|
export type SerializedDecl = SerializedEntityDecl | SerializedEnumDecl | SerializedTypeAliasDecl;
|
|
19
|
-
export type DeclP<Params extends TypeParameter[] = TypeParameter[]> = EntityDecl
|
|
20
|
-
export type SerializedDeclP<Params extends SerializedTypeParameter[] = SerializedTypeParameter[]> = SerializedEntityDecl
|
|
19
|
+
export type DeclP<Params extends TypeParameter[] = TypeParameter[]> = EntityDecl | EnumDecl<string, Record<string, EnumCaseDecl>, Params> | TypeAliasDecl<string, Type, Params>;
|
|
20
|
+
export type SerializedDeclP<Params extends SerializedTypeParameter[] = SerializedTypeParameter[]> = SerializedEntityDecl | SerializedEnumDecl<string, Record<string, SerializedEnumCaseDecl>, Params> | SerializedTypeAliasDecl<string, SerializedType, Params>;
|
|
21
21
|
export type SecondaryDecl = EnumDecl | TypeAliasDecl;
|
|
22
22
|
export type SerializedSecondaryDecl = SerializedEnumDecl | SerializedTypeAliasDecl;
|
|
23
23
|
export declare const getNestedDeclarations: GetNestedDeclarations;
|
|
@@ -42,3 +42,4 @@ export declare const isDeclWithoutTypeParameters: (decl: Decl) => decl is DeclP<
|
|
|
42
42
|
export declare const resolveTypeArgumentsInDecls: (decls: readonly Decl[]) => DeclP<[]>[];
|
|
43
43
|
export declare const serializeDecl: Serializer<Decl, SerializedDecl>;
|
|
44
44
|
export declare const getReferencesForDecl: GetReferences<Decl>;
|
|
45
|
+
export declare const groupDeclarationsBySourceUrl: (decls: readonly Decl[]) => Partial<Record<string, Decl[]>>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { assertExhaustive } from "
|
|
1
|
+
import { assertExhaustive } from "../../../shared/utils/typeSafety.js";
|
|
2
2
|
import { NodeKind } from "../Node.js";
|
|
3
3
|
import { getNestedDeclarationsInArrayType } from "../types/generic/ArrayType.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getNestedDeclarationsInEnumType } from "../types/generic/EnumType.js";
|
|
5
|
+
import { getNestedDeclarationsInObjectType } from "../types/generic/ObjectType.js";
|
|
5
6
|
import { getNestedDeclarationsInIncludeIdentifierType } from "../types/references/IncludeIdentifierType.js";
|
|
6
7
|
import { getNestedDeclarationsInNestedEntityMapType } from "../types/references/NestedEntityMapType.js";
|
|
7
8
|
import { getNestedDeclarationsInReferenceIdentifierType } from "../types/references/ReferenceIdentifierType.js";
|
|
@@ -9,7 +10,9 @@ import { getNestedDeclarationsInEntityDecl, getReferencesForEntityDecl, isEntity
|
|
|
9
10
|
import { getNestedDeclarationsInEnumDecl, getReferencesForEnumDecl, isEnumDecl, resolveTypeArgumentsInEnumDecl, serializeEnumDecl, validateEnumDecl, } from "./EnumDecl.js";
|
|
10
11
|
import { getNestedDeclarationsInTypeAliasDecl, getReferencesForTypeAliasDecl, isTypeAliasDecl, resolveTypeArgumentsInTypeAliasDecl, serializeTypeAliasDecl, validateTypeAliasDecl, } from "./TypeAliasDecl.js";
|
|
11
12
|
export const getParameterNames = (decl) => decl.parameters.map(param => param.name);
|
|
12
|
-
export const getTypeArgumentsRecord = (decl, args) => Object.fromEntries(
|
|
13
|
+
export const getTypeArgumentsRecord = (decl, args) => Object.fromEntries(
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15
|
+
args.slice(0, decl.parameters.length).map((arg, i) => [decl.parameters[i].name, arg]));
|
|
13
16
|
export const getNestedDeclarations = (addedDecls, node) => {
|
|
14
17
|
switch (node.kind) {
|
|
15
18
|
case NodeKind.EntityDecl:
|
|
@@ -27,7 +30,7 @@ export const getNestedDeclarations = (addedDecls, node) => {
|
|
|
27
30
|
case NodeKind.FloatType:
|
|
28
31
|
case NodeKind.IntegerType:
|
|
29
32
|
case NodeKind.StringType:
|
|
30
|
-
case NodeKind.
|
|
33
|
+
case NodeKind.TypeArgumentType:
|
|
31
34
|
return addedDecls;
|
|
32
35
|
case NodeKind.ReferenceIdentifierType:
|
|
33
36
|
return getNestedDeclarationsInReferenceIdentifierType(addedDecls, node);
|
|
@@ -35,6 +38,8 @@ export const getNestedDeclarations = (addedDecls, node) => {
|
|
|
35
38
|
return getNestedDeclarationsInIncludeIdentifierType(addedDecls, node);
|
|
36
39
|
case NodeKind.NestedEntityMapType:
|
|
37
40
|
return getNestedDeclarationsInNestedEntityMapType(addedDecls, node);
|
|
41
|
+
case NodeKind.EnumType:
|
|
42
|
+
return getNestedDeclarationsInEnumType(addedDecls, node);
|
|
38
43
|
default:
|
|
39
44
|
return assertExhaustive(node);
|
|
40
45
|
}
|
|
@@ -96,3 +101,4 @@ export const getReferencesForDecl = (decl, value) => {
|
|
|
96
101
|
return assertExhaustive(decl);
|
|
97
102
|
}
|
|
98
103
|
};
|
|
104
|
+
export const groupDeclarationsBySourceUrl = (decls) => Object.groupBy(decls, decl => decl.sourceUrl);
|