@messagevisor/core 0.15.0 → 0.16.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 +11 -0
- package/lib/builder/index.js +4 -3
- package/lib/builder/index.js.map +1 -1
- package/lib/create/index.js +2 -1
- package/lib/create/index.js.map +1 -1
- package/lib/importer/index.js +4 -3
- package/lib/importer/index.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/linter/index.js +9 -6
- package/lib/linter/index.js.map +1 -1
- package/lib/path.d.ts +4 -0
- package/lib/path.js +60 -0
- package/lib/path.js.map +1 -0
- package/lib/promoter/index.js +5 -4
- package/lib/promoter/index.js.map +1 -1
- package/lib/prune/index.js +2 -1
- package/lib/prune/index.js.map +1 -1
- package/lib/sets.js +2 -1
- package/lib/sets.js.map +1 -1
- package/lib/tester/index.js +2 -1
- package/lib/tester/index.js.map +1 -1
- package/package.json +5 -5
- package/src/builder/index.ts +4 -3
- package/src/create/index.spec.ts +1 -3
- package/src/create/index.ts +2 -1
- package/src/importer/index.ts +4 -3
- package/src/index.ts +1 -0
- package/src/linter/index.spec.ts +1 -0
- package/src/linter/index.ts +8 -6
- package/src/path.spec.ts +20 -0
- package/src/path.ts +31 -0
- package/src/promoter/index.spec.ts +2 -5
- package/src/promoter/index.ts +8 -7
- package/src/prune/index.ts +3 -2
- package/src/sets.ts +3 -2
- package/src/tester/index.ts +2 -1
package/src/create/index.spec.ts
CHANGED
|
@@ -181,9 +181,7 @@ describe("createPlugin", function () {
|
|
|
181
181
|
expect(summary.requestedKeys).toEqual(["auth.signin", "auth.signout"]);
|
|
182
182
|
expect(summary.createdKeys).toEqual(["auth.signout"]);
|
|
183
183
|
expect(summary.skippedKeys).toEqual(["auth.signin"]);
|
|
184
|
-
expect(summary.createdFilePaths).toEqual([
|
|
185
|
-
path.relative(process.cwd(), path.join(root, "messages/auth/signout.yml")),
|
|
186
|
-
]);
|
|
184
|
+
expect(summary.createdFilePaths).toEqual([path.join("messages", "auth", "signout.yml")]);
|
|
187
185
|
logSpy.mockRestore();
|
|
188
186
|
});
|
|
189
187
|
|
package/src/create/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { Attribute, Locale, Message, Target, Segment } from "@messagevisor/
|
|
|
4
4
|
|
|
5
5
|
import type { Plugin } from "../cli";
|
|
6
6
|
import { MessagevisorCLIError, printMessagevisorCLIError } from "../error";
|
|
7
|
+
import { formatProjectPath } from "../path";
|
|
7
8
|
import { getProjectSetExecutions } from "../sets";
|
|
8
9
|
|
|
9
10
|
type CreateEntityType = "messages" | "locales" | "targets" | "attributes" | "segments";
|
|
@@ -224,7 +225,7 @@ async function createDefinitions(
|
|
|
224
225
|
await writeEntity(datasource, entityType, key);
|
|
225
226
|
createdKeys.push(key);
|
|
226
227
|
createdFilePaths.push(
|
|
227
|
-
|
|
228
|
+
formatProjectPath(projectConfig, getEntityFilePath(projectConfig, entityType, key)),
|
|
228
229
|
);
|
|
229
230
|
existingKeys.add(key);
|
|
230
231
|
}
|
package/src/importer/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { Locale, Message, Override, Translation } from "@messagevisor/types
|
|
|
7
7
|
import type { ProjectConfig } from "../config";
|
|
8
8
|
import type { Datasource } from "../datasource";
|
|
9
9
|
import { MessagevisorCLIError, printMessagevisorCLIError } from "../error";
|
|
10
|
+
import { formatProjectPath } from "../path";
|
|
10
11
|
import { getProjectSetExecutions } from "../sets";
|
|
11
12
|
import {
|
|
12
13
|
CLI_FORMAT_BOLD,
|
|
@@ -1091,12 +1092,12 @@ export async function importProjectSets(
|
|
|
1091
1092
|
);
|
|
1092
1093
|
}
|
|
1093
1094
|
|
|
1094
|
-
function printImportResult(result: ImportProjectResult) {
|
|
1095
|
+
function printImportResult(projectConfig: ProjectConfig, result: ImportProjectResult) {
|
|
1095
1096
|
console.log("");
|
|
1096
1097
|
console.log(CLI_FORMAT_BOLD, "Importing Messagevisor translations");
|
|
1097
1098
|
const inputLabel = isHttpUrl(result.inputFilePath)
|
|
1098
1099
|
? result.inputFilePath
|
|
1099
|
-
:
|
|
1100
|
+
: formatProjectPath(projectConfig, result.inputFilePath);
|
|
1100
1101
|
console.log(` Input: ${colorize(inputLabel, 36)}`);
|
|
1101
1102
|
console.log(` Mode: ${result.apply ? "apply" : "preview"}`);
|
|
1102
1103
|
if (result.summary.sets.length > 0) {
|
|
@@ -1152,7 +1153,7 @@ export const importPlugin = {
|
|
|
1152
1153
|
parsed,
|
|
1153
1154
|
);
|
|
1154
1155
|
|
|
1155
|
-
printImportResult(result);
|
|
1156
|
+
printImportResult(projectConfig, result);
|
|
1156
1157
|
} catch (error) {
|
|
1157
1158
|
if (printMessagevisorCLIError(error)) {
|
|
1158
1159
|
return false;
|
package/src/index.ts
CHANGED
package/src/linter/index.spec.ts
CHANGED
package/src/linter/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getProjectSetExecutions,
|
|
22
22
|
getProjectSetRelativeFilePath,
|
|
23
23
|
} from "../sets";
|
|
24
|
+
import { formatProjectPath, getProjectRootDirectoryPath } from "../path";
|
|
24
25
|
import { CLI_FORMAT_BOLD, CLI_FORMAT_GREEN, CLI_FORMAT_RED, colorize } from "../tester/cliFormat";
|
|
25
26
|
import { prettyDuration } from "../tester/prettyDuration";
|
|
26
27
|
|
|
@@ -102,7 +103,7 @@ function getFullPathFromKey(projectConfig: ProjectConfig, entityType: LintEntity
|
|
|
102
103
|
: path.join(projectConfig.testsDirectoryPath, fileName);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
return path.join(
|
|
106
|
+
return path.join(getProjectRootDirectoryPath(projectConfig), "messagevisor.config.js");
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
async function readAll<T>(
|
|
@@ -147,7 +148,7 @@ export async function lintProject(
|
|
|
147
148
|
) {
|
|
148
149
|
for (const issue of getLintIssuesFromZodError(error)) {
|
|
149
150
|
recordError({
|
|
150
|
-
filePath:
|
|
151
|
+
filePath: formatProjectPath(projectConfig, fullPath),
|
|
151
152
|
entityType,
|
|
152
153
|
entityKey: key,
|
|
153
154
|
message: issue.message,
|
|
@@ -168,7 +169,7 @@ export async function lintProject(
|
|
|
168
169
|
|
|
169
170
|
if (!isValidEntityKey(projectConfig, key)) {
|
|
170
171
|
recordError({
|
|
171
|
-
filePath:
|
|
172
|
+
filePath: formatProjectPath(projectConfig, fullPath),
|
|
172
173
|
entityType,
|
|
173
174
|
entityKey: key,
|
|
174
175
|
message: `Invalid name: "${key}". ${ENTITY_NAME_REGEX_ERROR}`,
|
|
@@ -186,7 +187,7 @@ export async function lintProject(
|
|
|
186
187
|
}
|
|
187
188
|
} catch (error) {
|
|
188
189
|
recordError({
|
|
189
|
-
filePath:
|
|
190
|
+
filePath: formatProjectPath(projectConfig, fullPath),
|
|
190
191
|
entityType,
|
|
191
192
|
entityKey: key,
|
|
192
193
|
message: error instanceof Error ? error.message : String(error),
|
|
@@ -252,7 +253,7 @@ export async function lintProject(
|
|
|
252
253
|
const fullPath = getFullPathFromKey(projectConfig, "locale", key);
|
|
253
254
|
|
|
254
255
|
recordError({
|
|
255
|
-
filePath:
|
|
256
|
+
filePath: formatProjectPath(projectConfig, fullPath),
|
|
256
257
|
entityType: "locale",
|
|
257
258
|
entityKey: key,
|
|
258
259
|
message: `Circular locale dependency detected for ${field}: ${circularDependency.cycle.join(" -> ")}`,
|
|
@@ -289,7 +290,8 @@ export async function lintProject(
|
|
|
289
290
|
...lintMessageIcuFormatStyles(
|
|
290
291
|
Object.fromEntries(Object.entries(messagesByKey).filter(([key]) => shouldLintKey(key))),
|
|
291
292
|
localesByKey,
|
|
292
|
-
(key) =>
|
|
293
|
+
(key) =>
|
|
294
|
+
formatProjectPath(projectConfig, getFullPathFromKey(projectConfig, "message", key)),
|
|
293
295
|
{ icuSkeleton: projectConfig.icuSkeleton },
|
|
294
296
|
),
|
|
295
297
|
);
|
package/src/path.spec.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
|
|
3
|
+
import { formatRootRelativePath } from "./path";
|
|
4
|
+
|
|
5
|
+
describe("path formatting", function () {
|
|
6
|
+
it("formats paths relative to the selected project root", function () {
|
|
7
|
+
const root = path.join(path.sep, "tmp", "messagevisor-project");
|
|
8
|
+
|
|
9
|
+
expect(formatRootRelativePath(root, path.join(root, "messages/auth/signin.yml"))).toEqual(
|
|
10
|
+
path.join("messages", "auth", "signin.yml"),
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("keeps paths outside the selected project root absolute", function () {
|
|
15
|
+
const root = path.join(path.sep, "tmp", "messagevisor-project");
|
|
16
|
+
const outside = path.join(path.sep, "tmp", "other", "translations.csv");
|
|
17
|
+
|
|
18
|
+
expect(formatRootRelativePath(root, outside)).toEqual(outside);
|
|
19
|
+
});
|
|
20
|
+
});
|
package/src/path.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
|
|
3
|
+
import type { ProjectConfig } from "./config";
|
|
4
|
+
|
|
5
|
+
export function getProjectRootDirectoryPath(projectConfig: ProjectConfig) {
|
|
6
|
+
return path.dirname(projectConfig.setsDirectoryPath);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function formatRootRelativePath(rootDirectoryPath: string, filePath: string) {
|
|
10
|
+
const absoluteRootDirectoryPath = path.resolve(rootDirectoryPath);
|
|
11
|
+
const absoluteFilePath = path.resolve(filePath);
|
|
12
|
+
const relativePath = path.relative(absoluteRootDirectoryPath, absoluteFilePath);
|
|
13
|
+
|
|
14
|
+
if (!relativePath) {
|
|
15
|
+
return ".";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (
|
|
19
|
+
relativePath === ".." ||
|
|
20
|
+
relativePath.startsWith(`..${path.sep}`) ||
|
|
21
|
+
path.isAbsolute(relativePath)
|
|
22
|
+
) {
|
|
23
|
+
return absoluteFilePath;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return relativePath;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function formatProjectPath(projectConfig: ProjectConfig, filePath: string) {
|
|
30
|
+
return formatRootRelativePath(getProjectRootDirectoryPath(projectConfig), filePath);
|
|
31
|
+
}
|
|
@@ -488,10 +488,7 @@ describe("promoteProjectSets", function () {
|
|
|
488
488
|
".messagevisor/promotions/20260419T102030-dev-to-staging-1.md",
|
|
489
489
|
);
|
|
490
490
|
|
|
491
|
-
const audit = await fs.promises.readFile(
|
|
492
|
-
path.resolve(process.cwd(), first.auditFilePath),
|
|
493
|
-
"utf8",
|
|
494
|
-
);
|
|
491
|
+
const audit = await fs.promises.readFile(path.resolve(root, first.auditFilePath), "utf8");
|
|
495
492
|
expect(audit).toContain("# Messagevisor Promotion");
|
|
496
493
|
expect(audit).toContain("- Mode: apply");
|
|
497
494
|
expect(audit).toContain("messages/product/price.yml");
|
|
@@ -516,7 +513,7 @@ describe("promoteProjectSets", function () {
|
|
|
516
513
|
expect(result.auditFilePath).toContain(".json");
|
|
517
514
|
|
|
518
515
|
const audit = JSON.parse(
|
|
519
|
-
await fs.promises.readFile(path.resolve(
|
|
516
|
+
await fs.promises.readFile(path.resolve(root, result.auditFilePath!), "utf8"),
|
|
520
517
|
);
|
|
521
518
|
|
|
522
519
|
expect(audit.apply).toEqual(true);
|
package/src/promoter/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type { ProjectConfig } from "../config";
|
|
|
16
16
|
import type { Datasource } from "../datasource";
|
|
17
17
|
import { MessagevisorCLIError, printMessagevisorCLIError } from "../error";
|
|
18
18
|
import { lintProject, type LintError } from "../linter";
|
|
19
|
+
import { formatProjectPath } from "../path";
|
|
19
20
|
import { CLI_FORMAT_BOLD, CLI_FORMAT_GREEN, colorize } from "../tester/cliFormat";
|
|
20
21
|
import { prettyDuration } from "../tester/prettyDuration";
|
|
21
22
|
|
|
@@ -1008,7 +1009,7 @@ async function writePromotionAudit(
|
|
|
1008
1009
|
|
|
1009
1010
|
await fs.promises.writeFile(filePath, content);
|
|
1010
1011
|
|
|
1011
|
-
return
|
|
1012
|
+
return formatProjectPath(projectConfig, filePath);
|
|
1012
1013
|
}
|
|
1013
1014
|
|
|
1014
1015
|
export async function promoteProjectSets(
|
|
@@ -1075,24 +1076,24 @@ export async function promoteProjectSets(
|
|
|
1075
1076
|
const created = plans
|
|
1076
1077
|
.filter((plan) => !plan.destination)
|
|
1077
1078
|
.map((plan) =>
|
|
1078
|
-
|
|
1079
|
-
|
|
1079
|
+
formatProjectPath(
|
|
1080
|
+
projectConfig,
|
|
1080
1081
|
getEntityFilePath(destinationDatasource.getConfig(), plan.type, plan.key),
|
|
1081
1082
|
),
|
|
1082
1083
|
);
|
|
1083
1084
|
const updated = plans
|
|
1084
1085
|
.filter((plan) => plan.destination && !deepEqual(plan.destination, plan.merged))
|
|
1085
1086
|
.map((plan) =>
|
|
1086
|
-
|
|
1087
|
-
|
|
1087
|
+
formatProjectPath(
|
|
1088
|
+
projectConfig,
|
|
1088
1089
|
getEntityFilePath(destinationDatasource.getConfig(), plan.type, plan.key),
|
|
1089
1090
|
),
|
|
1090
1091
|
);
|
|
1091
1092
|
const unchanged = plans
|
|
1092
1093
|
.filter((plan) => plan.destination && deepEqual(plan.destination, plan.merged))
|
|
1093
1094
|
.map((plan) =>
|
|
1094
|
-
|
|
1095
|
-
|
|
1095
|
+
formatProjectPath(
|
|
1096
|
+
projectConfig,
|
|
1096
1097
|
getEntityFilePath(destinationDatasource.getConfig(), plan.type, plan.key),
|
|
1097
1098
|
),
|
|
1098
1099
|
);
|
package/src/prune/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
import type { ProjectConfig } from "../config";
|
|
14
14
|
import type { Datasource } from "../datasource";
|
|
15
15
|
import { mergeFormatPresets } from "../formats";
|
|
16
|
+
import { formatProjectPath } from "../path";
|
|
16
17
|
import { getProjectSetExecutions } from "../sets";
|
|
17
18
|
import { CLI_FORMAT_BOLD, CLI_FORMAT_GREEN } from "../tester/cliFormat";
|
|
18
19
|
|
|
@@ -100,8 +101,8 @@ function getEntityFilePath(
|
|
|
100
101
|
) {
|
|
101
102
|
const parser = projectConfig.parser as CustomParser;
|
|
102
103
|
|
|
103
|
-
return
|
|
104
|
-
|
|
104
|
+
return formatProjectPath(
|
|
105
|
+
projectConfig,
|
|
105
106
|
path.join(directoryPath, ...key.split(projectConfig.namespaceCharacter)) +
|
|
106
107
|
`${suffix}.${parser.extension}`,
|
|
107
108
|
);
|
package/src/sets.ts
CHANGED
|
@@ -3,6 +3,7 @@ import * as path from "path";
|
|
|
3
3
|
import type { ProjectConfig } from "./config";
|
|
4
4
|
import type { Datasource } from "./datasource";
|
|
5
5
|
import { MessagevisorCLIError } from "./error";
|
|
6
|
+
import { formatProjectPath } from "./path";
|
|
6
7
|
|
|
7
8
|
export interface ProjectSetExecution {
|
|
8
9
|
set: string;
|
|
@@ -61,8 +62,8 @@ export function getProjectSetRelativeFilePath(
|
|
|
61
62
|
set: string,
|
|
62
63
|
filePath: string,
|
|
63
64
|
) {
|
|
64
|
-
const setDirectoryPath =
|
|
65
|
-
|
|
65
|
+
const setDirectoryPath = formatProjectPath(
|
|
66
|
+
projectConfig,
|
|
66
67
|
path.join(projectConfig.setsDirectoryPath, set),
|
|
67
68
|
);
|
|
68
69
|
|
package/src/tester/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { ProjectConfig } from "../config";
|
|
|
7
7
|
import type { Datasource } from "../datasource";
|
|
8
8
|
import { buildDatafile, resolveFormats } from "../builder";
|
|
9
9
|
import { evaluateSegment } from "../evaluate";
|
|
10
|
+
import { formatProjectPath } from "../path";
|
|
10
11
|
import {
|
|
11
12
|
assertProjectSetJsonSelection,
|
|
12
13
|
getProjectSetExecutions,
|
|
@@ -200,7 +201,7 @@ function getTestFilePath(projectConfig: ProjectConfig, testKey: string) {
|
|
|
200
201
|
const specPath = `${basePath}.spec.${extension}`;
|
|
201
202
|
const legacyPath = `${basePath}.${extension}`;
|
|
202
203
|
|
|
203
|
-
return
|
|
204
|
+
return formatProjectPath(projectConfig, fs.existsSync(specPath) ? specPath : legacyPath);
|
|
204
205
|
}
|
|
205
206
|
|
|
206
207
|
async function runTest(
|