@things-factory/figure-library 10.1.121
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/bootstrap.d.ts +1 -0
- package/dist-client/bootstrap.js +2 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/pages/figure-library-page.d.ts +78 -0
- package/dist-client/pages/figure-library-page.js +781 -0
- package/dist-client/pages/figure-library-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +8 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-server/index.d.ts +2 -0
- package/dist-server/index.js +6 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/routers/figure-library-file-router.d.ts +5 -0
- package/dist-server/routers/figure-library-file-router.js +43 -0
- package/dist-server/routers/figure-library-file-router.js.map +1 -0
- package/dist-server/routes.d.ts +1 -0
- package/dist-server/routes.js +16 -0
- package/dist-server/routes.js.map +1 -0
- package/dist-server/service/figure-library-release/figure-library-release.d.ts +54 -0
- package/dist-server/service/figure-library-release/figure-library-release.js +206 -0
- package/dist-server/service/figure-library-release/figure-library-release.js.map +1 -0
- package/dist-server/service/figure-library-resolver.d.ts +20 -0
- package/dist-server/service/figure-library-resolver.js +196 -0
- package/dist-server/service/figure-library-resolver.js.map +1 -0
- package/dist-server/service/figure-library-types.d.ts +23 -0
- package/dist-server/service/figure-library-types.js +85 -0
- package/dist-server/service/figure-library-types.js.map +1 -0
- package/dist-server/service/figure-type-map/figure-type-map-entry.d.ts +23 -0
- package/dist-server/service/figure-type-map/figure-type-map-entry.js +98 -0
- package/dist-server/service/figure-type-map/figure-type-map-entry.js.map +1 -0
- package/dist-server/service/figure-type-map/figure-type-map.d.ts +34 -0
- package/dist-server/service/figure-type-map/figure-type-map.js +120 -0
- package/dist-server/service/figure-type-map/figure-type-map.js.map +1 -0
- package/dist-server/service/index.d.ts +20 -0
- package/dist-server/service/index.js +28 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/library/blueprints.d.ts +28 -0
- package/dist-server/service/library/blueprints.js +53 -0
- package/dist-server/service/library/blueprints.js.map +1 -0
- package/dist-server/service/library/board-walk.d.ts +1 -0
- package/dist-server/service/library/board-walk.js +31 -0
- package/dist-server/service/library/board-walk.js.map +1 -0
- package/dist-server/service/library/derived.d.ts +16 -0
- package/dist-server/service/library/derived.js +45 -0
- package/dist-server/service/library/derived.js.map +1 -0
- package/dist-server/service/library/import.d.ts +30 -0
- package/dist-server/service/library/import.js +116 -0
- package/dist-server/service/library/import.js.map +1 -0
- package/dist-server/service/library/inspection.d.ts +63 -0
- package/dist-server/service/library/inspection.js +144 -0
- package/dist-server/service/library/inspection.js.map +1 -0
- package/dist-server/service/library/library-files.d.ts +32 -0
- package/dist-server/service/library/library-files.js +58 -0
- package/dist-server/service/library/library-files.js.map +1 -0
- package/dist-server/service/library/type-map.d.ts +35 -0
- package/dist-server/service/library/type-map.js +133 -0
- package/dist-server/service/library/type-map.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +51 -0
- package/things-factory.config.js +13 -0
- package/translations/en.json +98 -0
- package/translations/ko.json +98 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fullNameOf = void 0;
|
|
4
|
+
exports.mapOfState = mapOfState;
|
|
5
|
+
exports.entriesOf = entriesOf;
|
|
6
|
+
exports.candidateOf = candidateOf;
|
|
7
|
+
exports.assertLines = assertLines;
|
|
8
|
+
exports.saveCandidate = saveCandidate;
|
|
9
|
+
exports.putIntoCandidate = putIntoCandidate;
|
|
10
|
+
exports.activate = activate;
|
|
11
|
+
const typeorm_1 = require("typeorm");
|
|
12
|
+
const figure_model_1 = require("@hatiolab/figure-model");
|
|
13
|
+
const shell_1 = require("@things-factory/shell");
|
|
14
|
+
const figure_library_release_1 = require("../figure-library-release/figure-library-release");
|
|
15
|
+
const figure_type_map_1 = require("../figure-type-map/figure-type-map");
|
|
16
|
+
const figure_type_map_entry_1 = require("../figure-type-map/figure-type-map-entry");
|
|
17
|
+
/** The full name a release is the release of. */
|
|
18
|
+
const fullNameOf = (release) => (0, figure_model_1.formatFigureName)({ namespace: release.namespace, type: release.type });
|
|
19
|
+
exports.fullNameOf = fullNameOf;
|
|
20
|
+
function mapOfState(tx, domain, state) {
|
|
21
|
+
return tx.getRepository(figure_type_map_1.FigureTypeMap).findOne({ where: { domain: { id: domain.id }, state } });
|
|
22
|
+
}
|
|
23
|
+
function entriesOf(tx, map) {
|
|
24
|
+
return tx.getRepository(figure_type_map_entry_1.FigureTypeMapEntry).find({ where: { typeMap: { id: map.id } }, relations: { release: true }, order: { name: 'ASC' } });
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The domain's candidate. With `create`, a domain without one gets a new release numbered after the last, holding the
|
|
28
|
+
* active map's lines (ADR-0114 결정 6: editing starts from what draws now).
|
|
29
|
+
*/
|
|
30
|
+
async function candidateOf(tx, domain, user, create) {
|
|
31
|
+
const found = await mapOfState(tx, domain, figure_type_map_1.FigureTypeMapState.CANDIDATE);
|
|
32
|
+
if (found || !create)
|
|
33
|
+
return found;
|
|
34
|
+
const last = await tx
|
|
35
|
+
.getRepository(figure_type_map_1.FigureTypeMap)
|
|
36
|
+
.createQueryBuilder('map')
|
|
37
|
+
.withDeleted()
|
|
38
|
+
.where('map.domain_id = :domain', { domain: domain.id })
|
|
39
|
+
.orderBy('map.version', 'DESC')
|
|
40
|
+
.getOne();
|
|
41
|
+
const version = (last?.version ?? 0) + 1;
|
|
42
|
+
const candidate = await tx.getRepository(figure_type_map_1.FigureTypeMap).save({
|
|
43
|
+
domain,
|
|
44
|
+
name: `R${version}`,
|
|
45
|
+
version,
|
|
46
|
+
revision: 1,
|
|
47
|
+
state: figure_type_map_1.FigureTypeMapState.CANDIDATE,
|
|
48
|
+
creator: user,
|
|
49
|
+
updater: user
|
|
50
|
+
});
|
|
51
|
+
const active = await mapOfState(tx, domain, figure_type_map_1.FigureTypeMapState.ACTIVE);
|
|
52
|
+
if (active) {
|
|
53
|
+
const lines = await entriesOf(tx, active);
|
|
54
|
+
await tx.getRepository(figure_type_map_entry_1.FigureTypeMapEntry).save(lines.map(line => ({ domain, typeMap: candidate, name: line.name, release: { id: line.releaseId }, creator: user, updater: user })));
|
|
55
|
+
}
|
|
56
|
+
return candidate;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Checks lines against the library (ADR-0114 결정 15): one line per name, a release of this domain's library, and the
|
|
60
|
+
* release of that very name. Refused whole by the first fault, named.
|
|
61
|
+
*/
|
|
62
|
+
async function assertLines(tx, domain, lines) {
|
|
63
|
+
const seen = new Set();
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
if (seen.has(line.name)) {
|
|
66
|
+
throw new shell_1.Refusal('figure-type-map-duplicate', { name: line.name }, '{name} appears more than once in the type map.');
|
|
67
|
+
}
|
|
68
|
+
seen.add(line.name);
|
|
69
|
+
}
|
|
70
|
+
const ids = [...new Set(lines.map(line => line.releaseId))];
|
|
71
|
+
const releases = ids.length ? await tx.getRepository(figure_library_release_1.FigureLibraryRelease).find({ where: { id: (0, typeorm_1.In)(ids) } }) : [];
|
|
72
|
+
const byId = new Map(releases.map(release => [release.id, release]));
|
|
73
|
+
for (const line of lines) {
|
|
74
|
+
const release = byId.get(line.releaseId);
|
|
75
|
+
if (!release) {
|
|
76
|
+
throw new shell_1.Refusal('figure-type-map-missing-release', { name: line.name }, 'the release chosen for {name} is not in the library.');
|
|
77
|
+
}
|
|
78
|
+
if (release.domainId !== domain.id) {
|
|
79
|
+
throw new shell_1.Refusal('figure-type-map-foreign-release', { name: line.name }, 'the release chosen for {name} belongs to another domain.');
|
|
80
|
+
}
|
|
81
|
+
if ((0, exports.fullNameOf)(release) !== line.name) {
|
|
82
|
+
throw new shell_1.Refusal('figure-type-map-name-mismatch', { name: line.name, ref: release.ref }, '{ref} is not a release of {name}.');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return byId;
|
|
86
|
+
}
|
|
87
|
+
/** Replaces the candidate's lines; each save raises the revision an open preview compares (결정 12). */
|
|
88
|
+
async function saveCandidate(tx, domain, user, lines, description) {
|
|
89
|
+
await assertLines(tx, domain, lines);
|
|
90
|
+
const candidate = (await candidateOf(tx, domain, user, true));
|
|
91
|
+
await tx.getRepository(figure_type_map_entry_1.FigureTypeMapEntry).delete({ typeMap: { id: candidate.id } });
|
|
92
|
+
await tx.getRepository(figure_type_map_entry_1.FigureTypeMapEntry).save(lines.map(line => ({ domain, typeMap: candidate, name: line.name, release: { id: line.releaseId }, creator: user, updater: user })));
|
|
93
|
+
return await bumpRevision(tx, candidate, user, description);
|
|
94
|
+
}
|
|
95
|
+
/** Puts an imported release into the candidate: a new line, or its figure's line moved to it (결정 7). */
|
|
96
|
+
async function putIntoCandidate(tx, domain, user, release) {
|
|
97
|
+
const candidate = (await candidateOf(tx, domain, user, true));
|
|
98
|
+
const name = (0, exports.fullNameOf)(release);
|
|
99
|
+
const repository = tx.getRepository(figure_type_map_entry_1.FigureTypeMapEntry);
|
|
100
|
+
const line = await repository.findOne({ where: { typeMap: { id: candidate.id }, name } });
|
|
101
|
+
if (line)
|
|
102
|
+
await repository.update({ id: line.id }, { release: { id: release.id }, updater: user });
|
|
103
|
+
else
|
|
104
|
+
await repository.save({ domain, typeMap: candidate, name, release: { id: release.id }, creator: user, updater: user });
|
|
105
|
+
await bumpRevision(tx, candidate, user);
|
|
106
|
+
}
|
|
107
|
+
async function bumpRevision(tx, map, user, description) {
|
|
108
|
+
await tx
|
|
109
|
+
.getRepository(figure_type_map_1.FigureTypeMap)
|
|
110
|
+
.update({ id: map.id }, { revision: (map.revision ?? 0) + 1, updater: user, ...(description !== undefined ? { description } : {}) });
|
|
111
|
+
return await tx.getRepository(figure_type_map_1.FigureTypeMap).findOneOrFail({ where: { id: map.id } });
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Makes a release ACTIVE in one transaction: the candidate after a check, or an ARCHIVED one to roll back. The active
|
|
115
|
+
* one before becomes ARCHIVED; a candidate left aside by a roll back stays a candidate (ADR-0114 결정 6).
|
|
116
|
+
*/
|
|
117
|
+
async function activate(tx, domain, user, version) {
|
|
118
|
+
const repository = tx.getRepository(figure_type_map_1.FigureTypeMap);
|
|
119
|
+
const map = await repository.findOne({ where: { domain: { id: domain.id }, version } });
|
|
120
|
+
if (!map)
|
|
121
|
+
throw new shell_1.Refusal('figure-type-map-not-found', { version }, 'there is no type map R{version}.');
|
|
122
|
+
if (map.state === figure_type_map_1.FigureTypeMapState.ACTIVE)
|
|
123
|
+
return map;
|
|
124
|
+
const active = await mapOfState(tx, domain, figure_type_map_1.FigureTypeMapState.ACTIVE);
|
|
125
|
+
if (active)
|
|
126
|
+
await repository.update({ id: active.id }, { state: figure_type_map_1.FigureTypeMapState.ARCHIVED, updater: user });
|
|
127
|
+
await repository.update({ id: map.id }, { state: figure_type_map_1.FigureTypeMapState.ACTIVE, activatedAt: new Date(), activator: user, updater: user });
|
|
128
|
+
const actives = await repository.count({ where: { domain: { id: domain.id }, state: figure_type_map_1.FigureTypeMapState.ACTIVE } });
|
|
129
|
+
if (actives !== 1)
|
|
130
|
+
throw new shell_1.Refusal('figure-type-map-raced', { version }, 'another activation ran at the same time. try again.');
|
|
131
|
+
return await repository.findOneOrFail({ where: { id: map.id } });
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=type-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-map.js","sourceRoot":"","sources":["../../../server/service/library/type-map.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager, In } from 'typeorm'\n\nimport { formatFigureName } from '@hatiolab/figure-model'\nimport { Refusal } from '@things-factory/shell'\n\nimport { FigureLibraryRelease } from '../figure-library-release/figure-library-release'\nimport { FigureTypeMap, FigureTypeMapState } from '../figure-type-map/figure-type-map'\nimport { FigureTypeMapEntry } from '../figure-type-map/figure-type-map-entry'\n\ntype Domain = { id: string }\n\n/** The full name a release is the release of. */\nexport const fullNameOf = (release: Pick<FigureLibraryRelease, 'namespace' | 'type'>) =>\n formatFigureName({ namespace: release.namespace, type: release.type })\n\nexport function mapOfState(tx: EntityManager, domain: Domain, state: FigureTypeMapState): Promise<FigureTypeMap | null> {\n return tx.getRepository(FigureTypeMap).findOne({ where: { domain: { id: domain.id }, state } })\n}\n\nexport function entriesOf(tx: EntityManager, map: FigureTypeMap): Promise<FigureTypeMapEntry[]> {\n return tx.getRepository(FigureTypeMapEntry).find({ where: { typeMap: { id: map.id } }, relations: { release: true }, order: { name: 'ASC' } })\n}\n\n/**\n * The domain's candidate. With `create`, a domain without one gets a new release numbered after the last, holding the\n * active map's lines (ADR-0114 결정 6: editing starts from what draws now).\n */\nexport async function candidateOf(tx: EntityManager, domain: Domain, user: unknown, create: boolean): Promise<FigureTypeMap | null> {\n const found = await mapOfState(tx, domain, FigureTypeMapState.CANDIDATE)\n if (found || !create) return found\n\n const last = await tx\n .getRepository(FigureTypeMap)\n .createQueryBuilder('map')\n .withDeleted()\n .where('map.domain_id = :domain', { domain: domain.id })\n .orderBy('map.version', 'DESC')\n .getOne()\n const version = (last?.version ?? 0) + 1\n const candidate = await tx.getRepository(FigureTypeMap).save({\n domain,\n name: `R${version}`,\n version,\n revision: 1,\n state: FigureTypeMapState.CANDIDATE,\n creator: user,\n updater: user\n } as Partial<FigureTypeMap>)\n\n const active = await mapOfState(tx, domain, FigureTypeMapState.ACTIVE)\n if (active) {\n const lines = await entriesOf(tx, active)\n await tx.getRepository(FigureTypeMapEntry).save(\n lines.map(line => ({ domain, typeMap: candidate, name: line.name, release: { id: line.releaseId }, creator: user, updater: user }))\n )\n }\n return candidate\n}\n\nexport interface CandidateLine {\n name: string\n releaseId: string\n}\n\n/**\n * Checks lines against the library (ADR-0114 결정 15): one line per name, a release of this domain's library, and the\n * release of that very name. Refused whole by the first fault, named.\n */\nexport async function assertLines(tx: EntityManager, domain: Domain, lines: readonly CandidateLine[]): Promise<Map<string, FigureLibraryRelease>> {\n const seen = new Set<string>()\n for (const line of lines) {\n if (seen.has(line.name)) {\n throw new Refusal('figure-type-map-duplicate', { name: line.name }, '{name} appears more than once in the type map.')\n }\n seen.add(line.name)\n }\n const ids = [...new Set(lines.map(line => line.releaseId))]\n const releases = ids.length ? await tx.getRepository(FigureLibraryRelease).find({ where: { id: In(ids) } }) : []\n const byId = new Map(releases.map(release => [release.id!, release]))\n for (const line of lines) {\n const release = byId.get(line.releaseId)\n if (!release) {\n throw new Refusal('figure-type-map-missing-release', { name: line.name }, 'the release chosen for {name} is not in the library.')\n }\n if (release.domainId !== domain.id) {\n throw new Refusal('figure-type-map-foreign-release', { name: line.name }, 'the release chosen for {name} belongs to another domain.')\n }\n if (fullNameOf(release) !== line.name) {\n throw new Refusal(\n 'figure-type-map-name-mismatch',\n { name: line.name, ref: release.ref },\n '{ref} is not a release of {name}.'\n )\n }\n }\n return byId\n}\n\n/** Replaces the candidate's lines; each save raises the revision an open preview compares (결정 12). */\nexport async function saveCandidate(\n tx: EntityManager,\n domain: Domain,\n user: unknown,\n lines: readonly CandidateLine[],\n description?: string\n): Promise<FigureTypeMap> {\n await assertLines(tx, domain, lines)\n const candidate = (await candidateOf(tx, domain, user, true))!\n await tx.getRepository(FigureTypeMapEntry).delete({ typeMap: { id: candidate.id } })\n await tx.getRepository(FigureTypeMapEntry).save(\n lines.map(line => ({ domain, typeMap: candidate, name: line.name, release: { id: line.releaseId }, creator: user, updater: user }))\n )\n return await bumpRevision(tx, candidate, user, description)\n}\n\n/** Puts an imported release into the candidate: a new line, or its figure's line moved to it (결정 7). */\nexport async function putIntoCandidate(tx: EntityManager, domain: Domain, user: unknown, release: FigureLibraryRelease): Promise<void> {\n const candidate = (await candidateOf(tx, domain, user, true))!\n const name = fullNameOf(release)\n const repository = tx.getRepository(FigureTypeMapEntry)\n const line = await repository.findOne({ where: { typeMap: { id: candidate.id }, name } })\n if (line) await repository.update({ id: line.id }, { release: { id: release.id }, updater: user } as any)\n else await repository.save({ domain, typeMap: candidate, name, release: { id: release.id }, creator: user, updater: user })\n await bumpRevision(tx, candidate, user)\n}\n\nasync function bumpRevision(tx: EntityManager, map: FigureTypeMap, user: unknown, description?: string): Promise<FigureTypeMap> {\n await tx\n .getRepository(FigureTypeMap)\n .update({ id: map.id }, { revision: (map.revision ?? 0) + 1, updater: user, ...(description !== undefined ? { description } : {}) } as any)\n return await tx.getRepository(FigureTypeMap).findOneOrFail({ where: { id: map.id } })\n}\n\n/**\n * Makes a release ACTIVE in one transaction: the candidate after a check, or an ARCHIVED one to roll back. The active\n * one before becomes ARCHIVED; a candidate left aside by a roll back stays a candidate (ADR-0114 결정 6).\n */\nexport async function activate(tx: EntityManager, domain: Domain, user: unknown, version: number): Promise<FigureTypeMap> {\n const repository = tx.getRepository(FigureTypeMap)\n const map = await repository.findOne({ where: { domain: { id: domain.id }, version } })\n if (!map) throw new Refusal('figure-type-map-not-found', { version }, 'there is no type map R{version}.')\n if (map.state === FigureTypeMapState.ACTIVE) return map\n\n const active = await mapOfState(tx, domain, FigureTypeMapState.ACTIVE)\n if (active) await repository.update({ id: active.id }, { state: FigureTypeMapState.ARCHIVED, updater: user } as any)\n await repository.update({ id: map.id }, { state: FigureTypeMapState.ACTIVE, activatedAt: new Date(), activator: user, updater: user } as any)\n\n const actives = await repository.count({ where: { domain: { id: domain.id }, state: FigureTypeMapState.ACTIVE } })\n if (actives !== 1) throw new Refusal('figure-type-map-raced', { version }, 'another activation ran at the same time. try again.')\n return await repository.findOneOrFail({ where: { id: map.id } })\n}\n"]}
|