@messagevisor/core 0.0.1 → 0.1.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/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +7 -0
- package/jest.config.js +8 -0
- package/lib/benchmark/index.d.ts +2 -0
- package/lib/benchmark/index.js +417 -0
- package/lib/benchmark/index.js.map +1 -0
- package/lib/builder/index.d.ts +70 -0
- package/lib/builder/index.js +831 -0
- package/lib/builder/index.js.map +1 -0
- package/lib/cli/index.d.ts +28 -0
- package/lib/cli/index.js +182 -0
- package/lib/cli/index.js.map +1 -0
- package/lib/config/index.d.ts +61 -0
- package/lib/config/index.js +255 -0
- package/lib/config/index.js.map +1 -0
- package/lib/create/index.d.ts +2 -0
- package/lib/create/index.js +405 -0
- package/lib/create/index.js.map +1 -0
- package/lib/datasource/filesystemAdapter.d.ts +44 -0
- package/lib/datasource/filesystemAdapter.js +424 -0
- package/lib/datasource/filesystemAdapter.js.map +1 -0
- package/lib/datasource/index.d.ts +39 -0
- package/lib/datasource/index.js +96 -0
- package/lib/datasource/index.js.map +1 -0
- package/lib/error.d.ts +6 -0
- package/lib/error.js +49 -0
- package/lib/error.js.map +1 -0
- package/lib/evaluate/cli.d.ts +8 -0
- package/lib/evaluate/cli.js +179 -0
- package/lib/evaluate/cli.js.map +1 -0
- package/lib/evaluate/index.d.ts +10 -0
- package/lib/evaluate/index.js +131 -0
- package/lib/evaluate/index.js.map +1 -0
- package/lib/examples/coerceExampleIsoDates.d.ts +12 -0
- package/lib/examples/coerceExampleIsoDates.js +81 -0
- package/lib/examples/coerceExampleIsoDates.js.map +1 -0
- package/lib/examples/index.d.ts +63 -0
- package/lib/examples/index.js +713 -0
- package/lib/examples/index.js.map +1 -0
- package/lib/exporter/index.d.ts +60 -0
- package/lib/exporter/index.js +610 -0
- package/lib/exporter/index.js.map +1 -0
- package/lib/find-duplicates/index.d.ts +41 -0
- package/lib/find-duplicates/index.js +297 -0
- package/lib/find-duplicates/index.js.map +1 -0
- package/lib/generate-code/index.d.ts +11 -0
- package/lib/generate-code/index.js +157 -0
- package/lib/generate-code/index.js.map +1 -0
- package/lib/generate-code/typescript.d.ts +14 -0
- package/lib/generate-code/typescript.js +307 -0
- package/lib/generate-code/typescript.js.map +1 -0
- package/lib/importer/index.d.ts +64 -0
- package/lib/importer/index.js +1092 -0
- package/lib/importer/index.js.map +1 -0
- package/lib/index.d.ts +18 -0
- package/lib/index.js +35 -0
- package/lib/index.js.map +1 -0
- package/lib/info/index.d.ts +17 -0
- package/lib/info/index.js +132 -0
- package/lib/info/index.js.map +1 -0
- package/lib/init/index.d.ts +30 -0
- package/lib/init/index.js +348 -0
- package/lib/init/index.js.map +1 -0
- package/lib/lint/index.d.ts +1 -0
- package/lib/lint/index.js +6 -0
- package/lib/lint/index.js.map +1 -0
- package/lib/linter/attributeSchema.d.ts +7 -0
- package/lib/linter/attributeSchema.js +36 -0
- package/lib/linter/attributeSchema.js.map +1 -0
- package/lib/linter/checkLocaleCircularDependency.d.ts +7 -0
- package/lib/linter/checkLocaleCircularDependency.js +42 -0
- package/lib/linter/checkLocaleCircularDependency.js.map +1 -0
- package/lib/linter/conditionSchema.d.ts +3 -0
- package/lib/linter/conditionSchema.js +283 -0
- package/lib/linter/conditionSchema.js.map +1 -0
- package/lib/linter/formatSchema.d.ts +325 -0
- package/lib/linter/formatSchema.js +165 -0
- package/lib/linter/formatSchema.js.map +1 -0
- package/lib/linter/icuStyleLint.d.ts +6 -0
- package/lib/linter/icuStyleLint.js +226 -0
- package/lib/linter/icuStyleLint.js.map +1 -0
- package/lib/linter/index.d.ts +34 -0
- package/lib/linter/index.js +557 -0
- package/lib/linter/index.js.map +1 -0
- package/lib/linter/localeSchema.d.ts +672 -0
- package/lib/linter/localeSchema.js +50 -0
- package/lib/linter/localeSchema.js.map +1 -0
- package/lib/linter/messageSchema.d.ts +35 -0
- package/lib/linter/messageSchema.js +115 -0
- package/lib/linter/messageSchema.js.map +1 -0
- package/lib/linter/printError.d.ts +8 -0
- package/lib/linter/printError.js +41 -0
- package/lib/linter/printError.js.map +1 -0
- package/lib/linter/schema.d.ts +33 -0
- package/lib/linter/schema.js +192 -0
- package/lib/linter/schema.js.map +1 -0
- package/lib/linter/segmentSchema.d.ts +8 -0
- package/lib/linter/segmentSchema.js +18 -0
- package/lib/linter/segmentSchema.js.map +1 -0
- package/lib/linter/targetSchema.d.ts +337 -0
- package/lib/linter/targetSchema.js +39 -0
- package/lib/linter/targetSchema.js.map +1 -0
- package/lib/linter/testSchema.d.ts +71 -0
- package/lib/linter/testSchema.js +165 -0
- package/lib/linter/testSchema.js.map +1 -0
- package/lib/linter/zodHelpers.d.ts +2 -0
- package/lib/linter/zodHelpers.js +15 -0
- package/lib/linter/zodHelpers.js.map +1 -0
- package/lib/list/index.d.ts +8 -0
- package/lib/list/index.js +524 -0
- package/lib/list/index.js.map +1 -0
- package/lib/matrix.d.ts +4 -0
- package/lib/matrix.js +66 -0
- package/lib/matrix.js.map +1 -0
- package/lib/promoter/index.d.ts +65 -0
- package/lib/promoter/index.js +1208 -0
- package/lib/promoter/index.js.map +1 -0
- package/lib/prune/index.d.ts +37 -0
- package/lib/prune/index.js +673 -0
- package/lib/prune/index.js.map +1 -0
- package/lib/sets.d.ts +10 -0
- package/lib/sets.js +120 -0
- package/lib/sets.js.map +1 -0
- package/lib/tester/cliFormat.d.ts +8 -0
- package/lib/tester/cliFormat.js +15 -0
- package/lib/tester/cliFormat.js.map +1 -0
- package/lib/tester/index.d.ts +35 -0
- package/lib/tester/index.js +713 -0
- package/lib/tester/index.js.map +1 -0
- package/lib/tester/matrix.d.ts +14 -0
- package/lib/tester/matrix.js +76 -0
- package/lib/tester/matrix.js.map +1 -0
- package/lib/tester/prettyDuration.d.ts +1 -0
- package/lib/tester/prettyDuration.js +30 -0
- package/lib/tester/prettyDuration.js.map +1 -0
- package/lib/tester/printTestResult.d.ts +2 -0
- package/lib/tester/printTestResult.js +32 -0
- package/lib/tester/printTestResult.js.map +1 -0
- package/lib/tester/types.d.ts +29 -0
- package/lib/tester/types.js +3 -0
- package/lib/tester/types.js.map +1 -0
- package/package.json +41 -13
- package/src/benchmark/index.spec.ts +375 -0
- package/src/benchmark/index.ts +433 -0
- package/src/builder/index.spec.ts +822 -0
- package/src/builder/index.ts +920 -0
- package/src/cli/index.spec.ts +54 -0
- package/src/cli/index.ts +150 -0
- package/src/config/index.spec.ts +70 -0
- package/src/config/index.ts +259 -0
- package/src/create/index.spec.ts +272 -0
- package/src/create/index.ts +295 -0
- package/src/datasource/filesystemAdapter.ts +313 -0
- package/src/datasource/index.ts +135 -0
- package/src/error.ts +33 -0
- package/src/evaluate/cli.spec.ts +368 -0
- package/src/evaluate/cli.ts +130 -0
- package/src/evaluate/index.ts +161 -0
- package/src/examples/coerceExampleIsoDates.spec.ts +81 -0
- package/src/examples/coerceExampleIsoDates.ts +98 -0
- package/src/examples/index.spec.ts +453 -0
- package/src/examples/index.ts +854 -0
- package/src/exporter/index.spec.ts +443 -0
- package/src/exporter/index.ts +643 -0
- package/src/find-duplicates/index.spec.ts +289 -0
- package/src/find-duplicates/index.ts +314 -0
- package/src/generate-code/index.ts +92 -0
- package/src/generate-code/typescript.spec.ts +241 -0
- package/src/generate-code/typescript.ts +284 -0
- package/src/importer/index.spec.ts +1101 -0
- package/src/importer/index.ts +1190 -0
- package/src/index.ts +18 -0
- package/src/info/index.ts +67 -0
- package/src/init/index.spec.ts +279 -0
- package/src/init/index.ts +292 -0
- package/src/lint/index.ts +1 -0
- package/src/linter/attributeSchema.ts +38 -0
- package/src/linter/checkLocaleCircularDependency.ts +51 -0
- package/src/linter/conditionSchema.ts +386 -0
- package/src/linter/formatSchema.ts +170 -0
- package/src/linter/icuStyleLint.ts +312 -0
- package/src/linter/index.spec.ts +824 -0
- package/src/linter/index.ts +460 -0
- package/src/linter/localeSchema.ts +70 -0
- package/src/linter/messageSchema.ts +152 -0
- package/src/linter/printError.ts +52 -0
- package/src/linter/schema.ts +230 -0
- package/src/linter/segmentSchema.ts +15 -0
- package/src/linter/targetSchema.ts +50 -0
- package/src/linter/testSchema.spec.ts +405 -0
- package/src/linter/testSchema.ts +239 -0
- package/src/linter/zodHelpers.ts +16 -0
- package/src/list/index.spec.ts +431 -0
- package/src/list/index.ts +463 -0
- package/src/matrix.ts +69 -0
- package/src/promoter/index.spec.ts +584 -0
- package/src/promoter/index.ts +1267 -0
- package/src/prune/index.spec.ts +418 -0
- package/src/prune/index.ts +693 -0
- package/src/sets.ts +74 -0
- package/src/tester/cliFormat.ts +11 -0
- package/src/tester/featurevisorIntegration.spec.ts +101 -0
- package/src/tester/index.spec.ts +577 -0
- package/src/tester/index.ts +679 -0
- package/src/tester/matrix.ts +106 -0
- package/src/tester/prettyDuration.ts +34 -0
- package/src/tester/printTestResult.ts +40 -0
- package/src/tester/types.ts +32 -0
- package/tsconfig.cjs.json +11 -0
- package/tsconfig.typecheck.json +4 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
|
|
4
|
+
import type { CustomParser } from "@featurevisor/parsers";
|
|
5
|
+
import type {
|
|
6
|
+
Attribute,
|
|
7
|
+
DatafileContent,
|
|
8
|
+
Locale,
|
|
9
|
+
Message,
|
|
10
|
+
Target,
|
|
11
|
+
Segment,
|
|
12
|
+
Test,
|
|
13
|
+
} from "@messagevisor/types";
|
|
14
|
+
|
|
15
|
+
import { formatDatafilePath, type ProjectConfig } from "../config";
|
|
16
|
+
import type { WriteDatafileOptions } from "./index";
|
|
17
|
+
|
|
18
|
+
export type EntityType = "locale" | "message" | "segment" | "attribute" | "target" | "test";
|
|
19
|
+
|
|
20
|
+
const ENTITY_DIRECTORIES: Record<EntityType, keyof ProjectConfig> = {
|
|
21
|
+
locale: "localesDirectoryPath",
|
|
22
|
+
message: "messagesDirectoryPath",
|
|
23
|
+
segment: "segmentsDirectoryPath",
|
|
24
|
+
attribute: "attributesDirectoryPath",
|
|
25
|
+
target: "targetsDirectoryPath",
|
|
26
|
+
test: "testsDirectoryPath",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const TEST_SPEC_SUFFIX = ".spec";
|
|
30
|
+
|
|
31
|
+
export class FilesystemAdapter {
|
|
32
|
+
constructor(
|
|
33
|
+
private config: ProjectConfig,
|
|
34
|
+
private rootDirectoryPath?: string,
|
|
35
|
+
) {}
|
|
36
|
+
|
|
37
|
+
private get parser() {
|
|
38
|
+
return this.config.parser as CustomParser;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private getEntityDirectory(type: EntityType) {
|
|
42
|
+
return this.config[ENTITY_DIRECTORIES[type]] as string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async listSets(): Promise<string[]> {
|
|
46
|
+
if (!this.config.sets || !fs.existsSync(this.config.setsDirectoryPath)) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const entries = await fs.promises.readdir(this.config.setsDirectoryPath, {
|
|
51
|
+
withFileTypes: true,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return entries
|
|
55
|
+
.filter((entry) => entry.isDirectory())
|
|
56
|
+
.map((entry) => entry.name)
|
|
57
|
+
.sort();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private getEntityPath(type: EntityType, key: string) {
|
|
61
|
+
const extension = `.${this.parser.extension}`;
|
|
62
|
+
const basePath = path.join(
|
|
63
|
+
this.getEntityDirectory(type),
|
|
64
|
+
...key.split(this.config.namespaceCharacter),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if (type === "test") {
|
|
68
|
+
const specPath = `${basePath}${TEST_SPEC_SUFFIX}${extension}`;
|
|
69
|
+
|
|
70
|
+
if (fs.existsSync(specPath)) {
|
|
71
|
+
return specPath;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const legacyPath = `${basePath}${extension}`;
|
|
75
|
+
|
|
76
|
+
if (fs.existsSync(legacyPath)) {
|
|
77
|
+
return legacyPath;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return specPath;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return `${basePath}${extension}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private getEntityWritePath(type: EntityType, key: string) {
|
|
87
|
+
return (
|
|
88
|
+
path.join(this.getEntityDirectory(type), ...key.split(this.config.namespaceCharacter)) +
|
|
89
|
+
`${type === "test" ? TEST_SPEC_SUFFIX : ""}.${this.parser.extension}`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private getKeyFromEntityPath(type: EntityType, directoryPath: string, filePath: string) {
|
|
94
|
+
const extension = `.${this.parser.extension}`;
|
|
95
|
+
const relativePath = path.relative(directoryPath, filePath).slice(0, -extension.length);
|
|
96
|
+
const pathSegments = relativePath.split(path.sep);
|
|
97
|
+
|
|
98
|
+
if (type === "test") {
|
|
99
|
+
const lastSegment = pathSegments[pathSegments.length - 1];
|
|
100
|
+
|
|
101
|
+
if (lastSegment.endsWith(TEST_SPEC_SUFFIX)) {
|
|
102
|
+
pathSegments[pathSegments.length - 1] = lastSegment.slice(0, -TEST_SPEC_SUFFIX.length);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return pathSegments.join(this.config.namespaceCharacter);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private assertReservedCharactersNotInPathName(
|
|
110
|
+
type: EntityType,
|
|
111
|
+
entryName: string,
|
|
112
|
+
entryPath: string,
|
|
113
|
+
isFile: boolean,
|
|
114
|
+
) {
|
|
115
|
+
let nameToCheck = isFile ? entryName.slice(0, -`.${this.parser.extension}`.length) : entryName;
|
|
116
|
+
|
|
117
|
+
if (type === "test" && isFile && nameToCheck.endsWith(TEST_SPEC_SUFFIX)) {
|
|
118
|
+
nameToCheck = nameToCheck.slice(0, -TEST_SPEC_SUFFIX.length);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const reservedCharacters = [
|
|
122
|
+
["namespaceCharacter", this.config.namespaceCharacter],
|
|
123
|
+
["exportOverrideKeySeparator", this.config.exportOverrideKeySeparator],
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
for (const [label, reservedCharacter] of reservedCharacters) {
|
|
127
|
+
if (!reservedCharacter || !nameToCheck.includes(reservedCharacter)) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Invalid ${type} path "${entryPath}": ${label} "${reservedCharacter}" is not allowed in directory or file names.`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private async readFile<T>(filePath: string): Promise<T> {
|
|
138
|
+
const content = await fs.promises.readFile(filePath, "utf8");
|
|
139
|
+
return this.parser.parse<T>(content, filePath);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private async writeFile(filePath: string, content: unknown) {
|
|
143
|
+
await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
144
|
+
await fs.promises.writeFile(filePath, this.parser.stringify(content, filePath));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async listEntities(type: EntityType): Promise<string[]> {
|
|
148
|
+
const directoryPath = this.getEntityDirectory(type);
|
|
149
|
+
|
|
150
|
+
if (!fs.existsSync(directoryPath)) {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const extension = `.${this.parser.extension}`;
|
|
155
|
+
const files: string[] = [];
|
|
156
|
+
|
|
157
|
+
const assertReservedCharactersNotInPathName =
|
|
158
|
+
this.assertReservedCharactersNotInPathName.bind(this);
|
|
159
|
+
|
|
160
|
+
async function walk(currentDirectoryPath: string) {
|
|
161
|
+
const entries = await fs.promises.readdir(currentDirectoryPath, { withFileTypes: true });
|
|
162
|
+
|
|
163
|
+
for (const entry of entries) {
|
|
164
|
+
const entryPath = path.join(currentDirectoryPath, entry.name);
|
|
165
|
+
|
|
166
|
+
if (entry.isDirectory()) {
|
|
167
|
+
assertReservedCharactersNotInPathName(type, entry.name, entryPath, false);
|
|
168
|
+
await walk(entryPath);
|
|
169
|
+
} else if (entry.isFile() && entry.name.endsWith(extension)) {
|
|
170
|
+
assertReservedCharactersNotInPathName(type, entry.name, entryPath, true);
|
|
171
|
+
files.push(entryPath);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
await walk(directoryPath);
|
|
177
|
+
|
|
178
|
+
return Array.from(
|
|
179
|
+
new Set(files.map((filePath) => this.getKeyFromEntityPath(type, directoryPath, filePath))),
|
|
180
|
+
).sort();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
entityExists(type: EntityType, key: string) {
|
|
184
|
+
return fs.existsSync(this.getEntityPath(type, key));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async readEntity<T>(type: EntityType, key: string): Promise<T> {
|
|
188
|
+
const entity = await this.readFile<T>(this.getEntityPath(type, key));
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
key,
|
|
192
|
+
...entity,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async writeEntity<T>(type: EntityType, key: string, entity: T): Promise<void> {
|
|
197
|
+
await this.writeFile(this.getEntityWritePath(type, key), entity);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async readRevision() {
|
|
201
|
+
const revisionFilePath = path.join(
|
|
202
|
+
this.config.stateDirectoryPath,
|
|
203
|
+
this.config.revisionFileName,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
if (!fs.existsSync(revisionFilePath)) {
|
|
207
|
+
return "0";
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return (await fs.promises.readFile(revisionFilePath, "utf8")).trim() || "0";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async writeRevision(revision: string) {
|
|
214
|
+
await fs.promises.mkdir(this.config.stateDirectoryPath, { recursive: true });
|
|
215
|
+
await fs.promises.writeFile(
|
|
216
|
+
path.join(this.config.stateDirectoryPath, this.config.revisionFileName),
|
|
217
|
+
revision,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async writeDatafile(datafileContent: DatafileContent, options: WriteDatafileOptions = {}) {
|
|
222
|
+
const datafilePath = path.join(
|
|
223
|
+
this.config.datafilesDirectoryPath,
|
|
224
|
+
formatDatafilePath(this.config, datafileContent.target, datafileContent.locale),
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
await fs.promises.mkdir(path.dirname(datafilePath), { recursive: true });
|
|
228
|
+
await fs.promises.writeFile(
|
|
229
|
+
datafilePath,
|
|
230
|
+
options.pretty ? JSON.stringify(datafileContent, null, 2) : JSON.stringify(datafileContent),
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async readDatafile(target: string, locale: string): Promise<DatafileContent> {
|
|
235
|
+
const datafilePath = path.join(
|
|
236
|
+
this.config.datafilesDirectoryPath,
|
|
237
|
+
formatDatafilePath(this.config, target, locale),
|
|
238
|
+
);
|
|
239
|
+
return JSON.parse(await fs.promises.readFile(datafilePath, "utf8"));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
listLocales() {
|
|
243
|
+
return this.listEntities("locale");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
readLocale(key: string) {
|
|
247
|
+
return this.readEntity<Locale>("locale", key);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
writeLocale(key: string, locale: Locale) {
|
|
251
|
+
return this.writeEntity<Locale>("locale", key, locale);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
listMessages() {
|
|
255
|
+
return this.listEntities("message");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
readMessage(key: string) {
|
|
259
|
+
return this.readEntity<Message>("message", key);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
writeMessage(key: string, message: Message) {
|
|
263
|
+
return this.writeEntity<Message>("message", key, message);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
listSegments() {
|
|
267
|
+
return this.listEntities("segment");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
readSegment(key: string) {
|
|
271
|
+
return this.readEntity<Segment>("segment", key);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
writeSegment(key: string, segment: Segment) {
|
|
275
|
+
return this.writeEntity<Segment>("segment", key, segment);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
listAttributes() {
|
|
279
|
+
return this.listEntities("attribute");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
readAttribute(key: string) {
|
|
283
|
+
return this.readEntity<Attribute>("attribute", key);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
writeAttribute(key: string, attribute: Attribute) {
|
|
287
|
+
return this.writeEntity<Attribute>("attribute", key, attribute);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
listTargets() {
|
|
291
|
+
return this.listEntities("target");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
readTarget(key: string) {
|
|
295
|
+
return this.readEntity<Target>("target", key);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
writeTarget(key: string, target: Target) {
|
|
299
|
+
return this.writeEntity<Target>("target", key, target);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
listTests() {
|
|
303
|
+
return this.listEntities("test");
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
readTest(key: string) {
|
|
307
|
+
return this.readEntity<Test>("test", key);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
writeTest(key: string, test: Test) {
|
|
311
|
+
return this.writeEntity<Test>("test", key, test);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Attribute,
|
|
3
|
+
DatafileContent,
|
|
4
|
+
Locale,
|
|
5
|
+
Message,
|
|
6
|
+
Target,
|
|
7
|
+
Segment,
|
|
8
|
+
Test,
|
|
9
|
+
} from "@messagevisor/types";
|
|
10
|
+
|
|
11
|
+
import { getProjectConfigForSet, type ProjectConfig } from "../config";
|
|
12
|
+
import type { FilesystemAdapter } from "./filesystemAdapter";
|
|
13
|
+
|
|
14
|
+
export interface WriteDatafileOptions {
|
|
15
|
+
pretty?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class Datasource {
|
|
19
|
+
private adapter: FilesystemAdapter;
|
|
20
|
+
private rootConfig: ProjectConfig;
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
private config: ProjectConfig,
|
|
24
|
+
private rootDirectoryPath?: string,
|
|
25
|
+
private set?: string,
|
|
26
|
+
) {
|
|
27
|
+
this.rootConfig = config;
|
|
28
|
+
this.config = set ? getProjectConfigForSet(this.rootConfig, set) : config;
|
|
29
|
+
this.adapter = new this.config.adapter(this.config, rootDirectoryPath);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getConfig() {
|
|
33
|
+
return this.config;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getSet() {
|
|
37
|
+
return this.set;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
forSet(set: string) {
|
|
41
|
+
return new Datasource(this.rootConfig, this.rootDirectoryPath, set);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
listSets() {
|
|
45
|
+
return this.adapter.listSets();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
readRevision() {
|
|
49
|
+
return this.adapter.readRevision();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
writeRevision(revision: string) {
|
|
53
|
+
return this.adapter.writeRevision(revision);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
writeDatafile(datafileContent: DatafileContent, options: WriteDatafileOptions = {}) {
|
|
57
|
+
return this.adapter.writeDatafile(datafileContent, options);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
readDatafile(target: string, locale: string) {
|
|
61
|
+
return this.adapter.readDatafile(target, locale);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
listLocales() {
|
|
65
|
+
return this.adapter.listLocales();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
readLocale(localeKey: string): Promise<Locale> {
|
|
69
|
+
return this.adapter.readLocale(localeKey);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
writeLocale(localeKey: string, locale: Locale) {
|
|
73
|
+
return this.adapter.writeLocale(localeKey, locale);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
listMessages() {
|
|
77
|
+
return this.adapter.listMessages();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
readMessage(messageKey: string): Promise<Message> {
|
|
81
|
+
return this.adapter.readMessage(messageKey);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
writeMessage(messageKey: string, message: Message) {
|
|
85
|
+
return this.adapter.writeMessage(messageKey, message);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
listSegments() {
|
|
89
|
+
return this.adapter.listSegments();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
readSegment(segmentKey: string): Promise<Segment> {
|
|
93
|
+
return this.adapter.readSegment(segmentKey);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
writeSegment(segmentKey: string, segment: Segment) {
|
|
97
|
+
return this.adapter.writeSegment(segmentKey, segment);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
listAttributes() {
|
|
101
|
+
return this.adapter.listAttributes();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
readAttribute(attributeKey: string): Promise<Attribute> {
|
|
105
|
+
return this.adapter.readAttribute(attributeKey);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
writeAttribute(attributeKey: string, attribute: Attribute) {
|
|
109
|
+
return this.adapter.writeAttribute(attributeKey, attribute);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
listTargets() {
|
|
113
|
+
return this.adapter.listTargets();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
readTarget(targetKey: string): Promise<Target> {
|
|
117
|
+
return this.adapter.readTarget(targetKey);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
writeTarget(targetKey: string, target: Target) {
|
|
121
|
+
return this.adapter.writeTarget(targetKey, target);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
listTests() {
|
|
125
|
+
return this.adapter.listTests();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
readTest(testKey: string): Promise<Test> {
|
|
129
|
+
return this.adapter.readTest(testKey);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
writeTest(testKey: string, test: Test) {
|
|
133
|
+
return this.adapter.writeTest(testKey, test);
|
|
134
|
+
}
|
|
135
|
+
}
|
package/src/error.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export class MessagevisorCLIError extends Error {
|
|
2
|
+
public readonly cliMessage: string;
|
|
3
|
+
|
|
4
|
+
constructor(message: string) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "MessagevisorCLIError";
|
|
7
|
+
this.cliMessage = message;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getMessagevisorCLIErrorMessage(error: unknown) {
|
|
12
|
+
if (
|
|
13
|
+
typeof error === "object" &&
|
|
14
|
+
error !== null &&
|
|
15
|
+
"cliMessage" in error &&
|
|
16
|
+
typeof (error as { cliMessage?: unknown }).cliMessage === "string"
|
|
17
|
+
) {
|
|
18
|
+
return (error as { cliMessage: string }).cliMessage;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function printMessagevisorCLIError(error: unknown) {
|
|
25
|
+
const message = getMessagevisorCLIErrorMessage(error);
|
|
26
|
+
|
|
27
|
+
if (typeof message === "undefined") {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.error(message);
|
|
32
|
+
return true;
|
|
33
|
+
}
|