@platformos/platformos-common 0.0.12 → 0.0.16

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.
@@ -1,14 +1,34 @@
1
1
  import { AbstractFileSystem, FileType } from '../AbstractFileSystem';
2
+ import { parseModulePrefix } from '../path-utils';
2
3
  import { URI, Utils } from 'vscode-uri';
3
4
  import yaml from 'js-yaml';
4
5
 
5
- type ModuleKeyInfo =
6
- | { isModule: false; key: string }
7
- | { isModule: true; moduleName: string; key: string };
8
-
9
6
  export class TranslationProvider {
10
7
  constructor(private readonly fs: AbstractFileSystem) {}
11
8
 
9
+ /** Cache for filesystem-only translation loads (bypassed when contentOverride is set). */
10
+ private translationsCache = new Map<string, Record<string, any>>();
11
+
12
+ /**
13
+ * Invalidate cached translations. Call after any translation file is written
14
+ * to disk so subsequent calls re-read from the filesystem.
15
+ *
16
+ * Omitting `uri` clears the entire cache.
17
+ * Passing a `uri` removes only the entries whose base directory contains that file.
18
+ */
19
+ clearTranslationsCache(uri?: string): void {
20
+ if (!uri) {
21
+ this.translationsCache.clear();
22
+ return;
23
+ }
24
+ for (const key of this.translationsCache.keys()) {
25
+ const baseUri = key.slice(0, key.lastIndexOf(':'));
26
+ if (uri.startsWith(baseUri)) {
27
+ this.translationsCache.delete(key);
28
+ }
29
+ }
30
+ }
31
+
12
32
  private async isFile(path: string): Promise<boolean> {
13
33
  try {
14
34
  return (await this.fs.stat(path)).type === FileType.File;
@@ -42,16 +62,6 @@ export class TranslationProvider {
42
62
  return true;
43
63
  }
44
64
 
45
- private parseModuleKey(translationKey: string): ModuleKeyInfo {
46
- if (!translationKey.startsWith('modules/')) {
47
- return { isModule: false, key: translationKey };
48
- }
49
-
50
- const [, moduleName, key] = translationKey.split('/', 3);
51
-
52
- return key ? { isModule: true, moduleName, key } : { isModule: false, key: translationKey };
53
- }
54
-
55
65
  static getSearchPaths(moduleName?: string): string[] {
56
66
  if (!moduleName) {
57
67
  return ['app/translations'];
@@ -70,7 +80,7 @@ export class TranslationProvider {
70
80
  translationKey: string,
71
81
  defaultLocale: string,
72
82
  ): Promise<[string | undefined, string | undefined]> {
73
- const parsed = this.parseModuleKey(translationKey);
83
+ const parsed = parseModulePrefix(translationKey);
74
84
 
75
85
  if (!parsed.key) {
76
86
  return [undefined, undefined];
@@ -129,6 +139,14 @@ export class TranslationProvider {
129
139
  locale: string,
130
140
  contentOverride?: (uri: string) => string | undefined,
131
141
  ): Promise<Record<string, any>> {
142
+ const cacheKey = `${translationBaseUri.toString()}:${locale}`;
143
+
144
+ // Return cached result when the caller has no editor overrides (e.g. linter/CI).
145
+ // Skip cache when contentOverride is set — unsaved buffer content may differ from disk.
146
+ if (!contentOverride && this.translationsCache.has(cacheKey)) {
147
+ return this.translationsCache.get(cacheKey)!;
148
+ }
149
+
132
150
  const merged: Record<string, any> = {};
133
151
 
134
152
  const read = async (uri: string): Promise<string | undefined> => {
@@ -158,6 +176,10 @@ export class TranslationProvider {
158
176
  }
159
177
  }
160
178
 
179
+ if (!contentOverride) {
180
+ this.translationsCache.set(cacheKey, merged);
181
+ }
182
+
161
183
  return merged;
162
184
  }
163
185