@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.
- package/CHANGELOG.md +27 -0
- package/dist/documents-locator/DocumentsLocator.d.ts +13 -2
- package/dist/documents-locator/DocumentsLocator.js +49 -13
- package/dist/documents-locator/DocumentsLocator.js.map +1 -1
- package/dist/frontmatter.d.ts +75 -0
- package/dist/frontmatter.js +487 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/path-utils.d.ts +34 -0
- package/dist/path-utils.js +40 -0
- package/dist/path-utils.js.map +1 -1
- package/dist/route-table/RouteTable.d.ts +26 -0
- package/dist/route-table/RouteTable.js +18 -1
- package/dist/route-table/RouteTable.js.map +1 -1
- package/dist/route-table/index.d.ts +1 -1
- package/dist/route-table/index.js +2 -1
- package/dist/route-table/index.js.map +1 -1
- package/dist/translation-provider/TranslationProvider.d.ts +10 -1
- package/dist/translation-provider/TranslationProvider.js +32 -8
- package/dist/translation-provider/TranslationProvider.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/documents-locator/DocumentsLocator.spec.ts +68 -0
- package/src/documents-locator/DocumentsLocator.ts +62 -20
- package/src/frontmatter.ts +533 -0
- package/src/index.ts +1 -0
- package/src/path-utils.ts +55 -0
- package/src/route-table/RouteTable.ts +19 -2
- package/src/route-table/index.ts +1 -1
- package/src/translation-provider/TranslationProvider.ts +37 -15
|
@@ -55,6 +55,74 @@ function createMockFileSystem(files: Record<string, string>): AbstractFileSystem
|
|
|
55
55
|
describe('DocumentsLocator', () => {
|
|
56
56
|
const rootUri = URI.parse('file:///project');
|
|
57
57
|
|
|
58
|
+
describe('locateDefault', () => {
|
|
59
|
+
it('render → app/views/partials', () => {
|
|
60
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
61
|
+
expect(locator.locateDefault(rootUri, 'render', 'my/partial')).toBe(
|
|
62
|
+
'file:///project/app/views/partials/my/partial.liquid',
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('include → app/views/partials', () => {
|
|
67
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
68
|
+
expect(locator.locateDefault(rootUri, 'include', 'card')).toBe(
|
|
69
|
+
'file:///project/app/views/partials/card.liquid',
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('function → app/lib', () => {
|
|
74
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
75
|
+
expect(locator.locateDefault(rootUri, 'function', 'commands/apply')).toBe(
|
|
76
|
+
'file:///project/app/lib/commands/apply.liquid',
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('graphql → app/graphql', () => {
|
|
81
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
82
|
+
expect(locator.locateDefault(rootUri, 'graphql', 'users/search')).toBe(
|
|
83
|
+
'file:///project/app/graphql/users/search.graphql',
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('theme_render_rc → undefined', () => {
|
|
88
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
89
|
+
expect(locator.locateDefault(rootUri, 'theme_render_rc', 'card')).toBeUndefined();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('module render → modules/.../public/views/partials', () => {
|
|
93
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
94
|
+
expect(locator.locateDefault(rootUri, 'render', 'modules/core/my/partial')).toBe(
|
|
95
|
+
'file:///project/modules/core/public/views/partials/my/partial.liquid',
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('module function → modules/.../public/lib', () => {
|
|
100
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
101
|
+
expect(locator.locateDefault(rootUri, 'function', 'modules/core/commands/apply')).toBe(
|
|
102
|
+
'file:///project/modules/core/public/lib/commands/apply.liquid',
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('module graphql → modules/.../public/graphql', () => {
|
|
107
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
108
|
+
expect(locator.locateDefault(rootUri, 'graphql', 'modules/core/users/search')).toBe(
|
|
109
|
+
'file:///project/modules/core/public/graphql/users/search.graphql',
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('deeply nested path — creates all missing intermediate dirs', () => {
|
|
114
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
115
|
+
expect(locator.locateDefault(rootUri, 'render', 'a/b/c/d/partial')).toBe(
|
|
116
|
+
'file:///project/app/views/partials/a/b/c/d/partial.liquid',
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('asset → undefined (no canonical creation path)', () => {
|
|
121
|
+
const locator = new DocumentsLocator(createMockFileSystem({}));
|
|
122
|
+
expect(locator.locateDefault(rootUri, 'asset', 'logo.png')).toBeUndefined();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
58
126
|
describe('locate', () => {
|
|
59
127
|
it('should locate a partial file in app/lib', async () => {
|
|
60
128
|
const fs = createMockFileSystem({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import yaml from 'js-yaml';
|
|
2
2
|
import { AbstractFileSystem, FileType } from '../AbstractFileSystem';
|
|
3
|
-
import { getAppPaths, getModulePaths, PlatformOSFileType } from '../path-utils';
|
|
3
|
+
import { getAppPaths, getModulePaths, parseModulePrefix, PlatformOSFileType } from '../path-utils';
|
|
4
4
|
import { URI, Utils } from 'vscode-uri';
|
|
5
5
|
|
|
6
6
|
export type DocumentType =
|
|
@@ -34,9 +34,8 @@ export async function loadSearchPaths(
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
| { isModule: true; moduleName: string; key: string };
|
|
37
|
+
/** Maximum number of concrete paths generated by a single dynamic search-path expansion. */
|
|
38
|
+
const MAX_DYNAMIC_PATH_EXPANSIONS = 100;
|
|
40
39
|
|
|
41
40
|
export class DocumentsLocator {
|
|
42
41
|
constructor(private readonly fs: AbstractFileSystem) {}
|
|
@@ -49,17 +48,6 @@ export class DocumentsLocator {
|
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
private parseModulePath(fileName: string): ModulePathInfo {
|
|
53
|
-
if (!fileName.startsWith('modules/')) {
|
|
54
|
-
return { isModule: false, key: fileName };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const [, moduleName, ...rest] = fileName.split('/');
|
|
58
|
-
const key = rest.join('/');
|
|
59
|
-
|
|
60
|
-
return moduleName ? { isModule: true, moduleName, key } : { isModule: false, key: fileName };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
51
|
private getSearchPaths(type: 'partial' | 'graphql' | 'asset', moduleName?: string): string[] {
|
|
64
52
|
const fileType: PlatformOSFileType = {
|
|
65
53
|
partial: PlatformOSFileType.Partial,
|
|
@@ -75,7 +63,7 @@ export class DocumentsLocator {
|
|
|
75
63
|
fileName: string,
|
|
76
64
|
type: 'partial' | 'graphql' | 'asset',
|
|
77
65
|
): Promise<string | undefined> {
|
|
78
|
-
const parsed =
|
|
66
|
+
const parsed = parseModulePrefix(fileName);
|
|
79
67
|
const searchPaths = this.getSearchPaths(type, parsed.isModule ? parsed.moduleName : undefined);
|
|
80
68
|
|
|
81
69
|
let targetFile = parsed.key;
|
|
@@ -101,7 +89,7 @@ export class DocumentsLocator {
|
|
|
101
89
|
filePrefix: string,
|
|
102
90
|
type: 'partial' | 'graphql' | 'asset',
|
|
103
91
|
): Promise<string[]> {
|
|
104
|
-
const parsed =
|
|
92
|
+
const parsed = parseModulePrefix(filePrefix);
|
|
105
93
|
const searchPaths = this.getSearchPaths(type, parsed.isModule ? parsed.moduleName : undefined);
|
|
106
94
|
|
|
107
95
|
const results = new Set<string>();
|
|
@@ -185,7 +173,8 @@ export class DocumentsLocator {
|
|
|
185
173
|
* concrete directory prefixes by enumerating subdirectories at each dynamic
|
|
186
174
|
* segment. Static segments pass through unchanged.
|
|
187
175
|
*
|
|
188
|
-
* Results are cached per (rootUri, searchPath) and capped at
|
|
176
|
+
* Results are cached per (rootUri, searchPath) and capped at
|
|
177
|
+
* MAX_DYNAMIC_PATH_EXPANSIONS entries per dynamic segment.
|
|
189
178
|
*/
|
|
190
179
|
private async expandDynamicPath(rootUri: URI, searchPath: string): Promise<string[]> {
|
|
191
180
|
const segments = searchPath.split('/');
|
|
@@ -211,9 +200,9 @@ export class DocumentsLocator {
|
|
|
211
200
|
}
|
|
212
201
|
for (const sub of subdirs) {
|
|
213
202
|
nextPrefixes.push(prefix ? `${prefix}/${sub}` : sub);
|
|
214
|
-
if (nextPrefixes.length >=
|
|
203
|
+
if (nextPrefixes.length >= MAX_DYNAMIC_PATH_EXPANSIONS) break;
|
|
215
204
|
}
|
|
216
|
-
if (nextPrefixes.length >=
|
|
205
|
+
if (nextPrefixes.length >= MAX_DYNAMIC_PATH_EXPANSIONS) break;
|
|
217
206
|
}
|
|
218
207
|
prefixes = nextPrefixes;
|
|
219
208
|
}
|
|
@@ -263,6 +252,59 @@ export class DocumentsLocator {
|
|
|
263
252
|
return undefined;
|
|
264
253
|
}
|
|
265
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Returns the canonical URI where `fileName` would live — used as a
|
|
257
|
+
* go-to-definition fallback when the file doesn't exist yet.
|
|
258
|
+
* Returns undefined for theme_render_rc (ambiguous search path) and asset.
|
|
259
|
+
*/
|
|
260
|
+
locateDefault(rootUri: URI, nodeName: DocumentType, fileName: string): string | undefined {
|
|
261
|
+
const parsed = parseModulePrefix(fileName);
|
|
262
|
+
|
|
263
|
+
let basePath: string;
|
|
264
|
+
let ext: string;
|
|
265
|
+
|
|
266
|
+
switch (nodeName) {
|
|
267
|
+
case 'render':
|
|
268
|
+
case 'include':
|
|
269
|
+
basePath = parsed.isModule
|
|
270
|
+
? `modules/${parsed.moduleName}/public/views/partials`
|
|
271
|
+
: 'app/views/partials';
|
|
272
|
+
ext = '.liquid';
|
|
273
|
+
break;
|
|
274
|
+
case 'function':
|
|
275
|
+
basePath = parsed.isModule ? `modules/${parsed.moduleName}/public/lib` : 'app/lib';
|
|
276
|
+
ext = '.liquid';
|
|
277
|
+
break;
|
|
278
|
+
case 'graphql':
|
|
279
|
+
basePath = parsed.isModule ? `modules/${parsed.moduleName}/public/graphql` : 'app/graphql';
|
|
280
|
+
ext = '.graphql';
|
|
281
|
+
break;
|
|
282
|
+
case 'theme_render_rc': // ambiguous — multiple search paths, no single canonical location
|
|
283
|
+
case 'asset': // no canonical creation path
|
|
284
|
+
return undefined;
|
|
285
|
+
default:
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return Utils.joinPath(rootUri, basePath, parsed.key + ext).toString();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Resolves `fileName` to a filesystem URI (if the file exists), or falls
|
|
294
|
+
* back to the canonical default URI from `locateDefault`.
|
|
295
|
+
*/
|
|
296
|
+
async locateOrDefault(
|
|
297
|
+
rootUri: URI,
|
|
298
|
+
nodeName: DocumentType,
|
|
299
|
+
fileName: string,
|
|
300
|
+
themeSearchPaths?: string[] | null,
|
|
301
|
+
): Promise<string | undefined> {
|
|
302
|
+
return (
|
|
303
|
+
(await this.locate(rootUri, nodeName, fileName, themeSearchPaths)) ??
|
|
304
|
+
this.locateDefault(rootUri, nodeName, fileName)
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
266
308
|
async locate(
|
|
267
309
|
rootUri: URI,
|
|
268
310
|
nodeName: DocumentType,
|