@platformos/platformos-common 0.0.10 → 0.0.11
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 +6 -0
- package/CLAUDE.md +70 -0
- package/dist/path-utils.d.ts +59 -15
- package/dist/path-utils.js +100 -28
- package/dist/path-utils.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/path-utils.spec.ts +320 -33
- package/src/path-utils.ts +103 -28
package/src/path-utils.ts
CHANGED
|
@@ -8,28 +8,65 @@
|
|
|
8
8
|
* - getFileType() classifies any URI to a PlatformOSFileType
|
|
9
9
|
* - isPage(), isLayout(), isPartial() etc. are convenience wrappers around getFileType()
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
* /
|
|
13
|
-
*
|
|
14
|
-
* (
|
|
11
|
+
* Source of truth: app/services/app_builder/services/converters_config.rb and
|
|
12
|
+
* app/models/concerns/deployable.rb in the platformOS server codebase.
|
|
13
|
+
*
|
|
14
|
+
* DIR_PREFIX (Ruby): ^/?((marketplace_builder|app)/|modules/(.+)(private|public)/)?
|
|
15
|
+
* This means files can live under:
|
|
16
|
+
* - app/{dir}/
|
|
17
|
+
* - marketplace_builder/{dir}/ (legacy alias for app/)
|
|
18
|
+
* - modules/{name}/(public|private)/{dir}/
|
|
19
|
+
* - app/modules/{name}/(public|private)/{dir}/
|
|
15
20
|
*/
|
|
16
21
|
|
|
17
22
|
import { UriString } from './AbstractFileSystem';
|
|
18
23
|
|
|
19
24
|
/**
|
|
20
|
-
* File types that exist in a platformOS app, each
|
|
21
|
-
*
|
|
25
|
+
* File types that exist in a platformOS app, each corresponding to a server-side
|
|
26
|
+
* converter that processes the file on deploy.
|
|
27
|
+
*
|
|
28
|
+
* Liquid types: Page, Layout, Partial, Authorization, Email, ApiCall, Sms, Migration, FormConfiguration
|
|
29
|
+
* YAML types: CustomModelType, InstanceProfileType, TransactableType, Translation
|
|
30
|
+
* GraphQL types: GraphQL
|
|
31
|
+
* Binary/other: Asset
|
|
22
32
|
*/
|
|
23
33
|
export enum PlatformOSFileType {
|
|
34
|
+
// ── Liquid ──────────────────────────────────────────────────────────────────
|
|
35
|
+
/** views/pages/ or pages/ → PageConverter */
|
|
24
36
|
Page = 'Page',
|
|
37
|
+
/** views/layouts/ → LiquidViewConverter (layouts) */
|
|
25
38
|
Layout = 'Layout',
|
|
39
|
+
/** views/partials/ or lib/ → LiquidViewConverter (partials) */
|
|
26
40
|
Partial = 'Partial',
|
|
41
|
+
/** authorization_policies/ → AuthorizationPolicyConverter */
|
|
27
42
|
Authorization = 'Authorization',
|
|
43
|
+
/** emails/ or notifications/email_notifications/ → EmailNotificationConverter */
|
|
28
44
|
Email = 'Email',
|
|
45
|
+
/** api_calls/ or notifications/api_call_notifications/ → ApiCallNotificationConverter */
|
|
29
46
|
ApiCall = 'ApiCall',
|
|
47
|
+
/** smses/ or notifications/sms_notifications/ → SmsNotificationConverter */
|
|
30
48
|
Sms = 'Sms',
|
|
49
|
+
/** migrations/ → MigrationConverter */
|
|
31
50
|
Migration = 'Migration',
|
|
51
|
+
/** form_configurations/ or forms/ → FormConfigurationConverter */
|
|
52
|
+
FormConfiguration = 'FormConfiguration',
|
|
53
|
+
|
|
54
|
+
// ── YAML ────────────────────────────────────────────────────────────────────
|
|
55
|
+
/** custom_model_types/, model_schemas/, or schema/ → CustomModelTypeConverter */
|
|
56
|
+
CustomModelType = 'CustomModelType',
|
|
57
|
+
/** instance_profile_types/, user_profile_types/, or user_profile_schemas/ → InstanceProfileTypeConverter */
|
|
58
|
+
InstanceProfileType = 'InstanceProfileType',
|
|
59
|
+
/** transactable_types/ → TransactableTypeConverter */
|
|
60
|
+
TransactableType = 'TransactableType',
|
|
61
|
+
/** translations/ → TranslationConverter */
|
|
62
|
+
Translation = 'Translation',
|
|
63
|
+
|
|
64
|
+
// ── GraphQL ─────────────────────────────────────────────────────────────────
|
|
65
|
+
/** graphql/ or graph_queries/ → GraphQueryConverter */
|
|
32
66
|
GraphQL = 'GraphQL',
|
|
67
|
+
|
|
68
|
+
// ── Binary/other ────────────────────────────────────────────────────────────
|
|
69
|
+
/** assets/ → AssetConverter */
|
|
33
70
|
Asset = 'Asset',
|
|
34
71
|
}
|
|
35
72
|
|
|
@@ -37,30 +74,48 @@ export enum PlatformOSFileType {
|
|
|
37
74
|
* The single source of truth for the platformOS directory structure.
|
|
38
75
|
*
|
|
39
76
|
* Maps each file type to its canonical directory name(s) relative to:
|
|
40
|
-
* - the app root: app/{dir}/
|
|
77
|
+
* - the app root: (app|marketplace_builder)/{dir}/
|
|
41
78
|
* - a module access level: modules/{name}/(public|private)/{dir}/
|
|
42
79
|
* - a nested module access level: app/modules/{name}/(public|private)/{dir}/
|
|
43
80
|
*
|
|
81
|
+
* Multiple dirs per type represent canonical + legacy aliases from the server
|
|
82
|
+
* converters_config.rb FULL_PHYSICAL_PATH regexes.
|
|
83
|
+
*
|
|
44
84
|
* Types with multiple dirs (e.g. Partial) will match any of their dirs.
|
|
45
|
-
*
|
|
46
|
-
*
|
|
85
|
+
* Order within each array doesn't matter for matching. Across types,
|
|
86
|
+
* exact segment matching prevents false positives between overlapping paths
|
|
87
|
+
* (e.g. app/lib/smses/ → Partial, not Sms).
|
|
47
88
|
*/
|
|
48
89
|
export const FILE_TYPE_DIRS: Readonly<Record<PlatformOSFileType, readonly string[]>> = {
|
|
49
|
-
|
|
90
|
+
// Liquid
|
|
91
|
+
[PlatformOSFileType.Page]: ['views/pages', 'pages'],
|
|
50
92
|
[PlatformOSFileType.Layout]: ['views/layouts'],
|
|
51
93
|
[PlatformOSFileType.Partial]: ['views/partials', 'lib'],
|
|
52
94
|
[PlatformOSFileType.Authorization]: ['authorization_policies'],
|
|
53
|
-
[PlatformOSFileType.Email]: ['emails'],
|
|
54
|
-
[PlatformOSFileType.ApiCall]: ['api_calls'],
|
|
55
|
-
[PlatformOSFileType.Sms]: ['smses'],
|
|
95
|
+
[PlatformOSFileType.Email]: ['emails', 'notifications/email_notifications'],
|
|
96
|
+
[PlatformOSFileType.ApiCall]: ['api_calls', 'notifications/api_call_notifications'],
|
|
97
|
+
[PlatformOSFileType.Sms]: ['smses', 'notifications/sms_notifications'],
|
|
56
98
|
[PlatformOSFileType.Migration]: ['migrations'],
|
|
57
|
-
[PlatformOSFileType.
|
|
99
|
+
[PlatformOSFileType.FormConfiguration]: ['form_configurations', 'forms'],
|
|
100
|
+
// YAML
|
|
101
|
+
[PlatformOSFileType.CustomModelType]: ['custom_model_types', 'model_schemas', 'schema'],
|
|
102
|
+
[PlatformOSFileType.InstanceProfileType]: [
|
|
103
|
+
'instance_profile_types',
|
|
104
|
+
'user_profile_types',
|
|
105
|
+
'user_profile_schemas',
|
|
106
|
+
],
|
|
107
|
+
[PlatformOSFileType.TransactableType]: ['transactable_types'],
|
|
108
|
+
[PlatformOSFileType.Translation]: ['translations'],
|
|
109
|
+
// GraphQL
|
|
110
|
+
[PlatformOSFileType.GraphQL]: ['graphql', 'graph_queries'],
|
|
111
|
+
// Asset
|
|
58
112
|
[PlatformOSFileType.Asset]: ['assets'],
|
|
59
113
|
};
|
|
60
114
|
|
|
61
115
|
/**
|
|
62
|
-
* Liquid-containing file types. GraphQL and
|
|
63
|
-
* don't contain Liquid code and should not be passed to the
|
|
116
|
+
* Liquid-containing file types. GraphQL, Asset, and YAML types are excluded
|
|
117
|
+
* because they don't contain Liquid code and should not be passed to the
|
|
118
|
+
* Liquid linter.
|
|
64
119
|
*/
|
|
65
120
|
const LIQUID_FILE_TYPES = new Set<PlatformOSFileType>([
|
|
66
121
|
PlatformOSFileType.Page,
|
|
@@ -71,16 +126,17 @@ const LIQUID_FILE_TYPES = new Set<PlatformOSFileType>([
|
|
|
71
126
|
PlatformOSFileType.ApiCall,
|
|
72
127
|
PlatformOSFileType.Sms,
|
|
73
128
|
PlatformOSFileType.Migration,
|
|
129
|
+
PlatformOSFileType.FormConfiguration,
|
|
74
130
|
]);
|
|
75
131
|
|
|
76
132
|
/**
|
|
77
133
|
* Pre-compiled regex per file type, derived entirely from FILE_TYPE_DIRS.
|
|
78
134
|
*
|
|
79
|
-
* For each canonical dir,
|
|
80
|
-
* /app/{dir}/
|
|
81
|
-
* /(public|private)/{dir}/
|
|
82
|
-
*
|
|
83
|
-
*
|
|
135
|
+
* For each canonical dir, three pattern alternatives are generated:
|
|
136
|
+
* /(app|marketplace_builder)/{dir}/ — direct app-level path (modern + legacy root)
|
|
137
|
+
* /(public|private)/{dir}/ — module path, covers both:
|
|
138
|
+
* modules/{name}/(public|private)/{dir}/
|
|
139
|
+
* app/modules/{name}/(public|private)/{dir}/
|
|
84
140
|
*
|
|
85
141
|
* Exact path segment matching prevents false positives:
|
|
86
142
|
* /app/lib/smses/file.liquid → matches /app/lib/ → Partial (NOT Sms)
|
|
@@ -89,7 +145,10 @@ const LIQUID_FILE_TYPES = new Set<PlatformOSFileType>([
|
|
|
89
145
|
const TYPE_MATCHERS = new Map<PlatformOSFileType, RegExp>(
|
|
90
146
|
(Object.entries(FILE_TYPE_DIRS) as [PlatformOSFileType, readonly string[]][]).map(
|
|
91
147
|
([type, dirs]) => {
|
|
92
|
-
const alternatives = dirs.flatMap((dir) => [
|
|
148
|
+
const alternatives = dirs.flatMap((dir) => [
|
|
149
|
+
`/(app|marketplace_builder)/${dir}/`,
|
|
150
|
+
`/(public|private)/${dir}/`,
|
|
151
|
+
]);
|
|
93
152
|
return [type, new RegExp(alternatives.join('|'))];
|
|
94
153
|
},
|
|
95
154
|
),
|
|
@@ -99,9 +158,13 @@ const TYPE_MATCHERS = new Map<PlatformOSFileType, RegExp>(
|
|
|
99
158
|
* Returns the PlatformOSFileType for the given URI, or undefined if the URI
|
|
100
159
|
* does not belong to any recognized platformOS directory.
|
|
101
160
|
*
|
|
161
|
+
* Supports both modern (app/) and legacy (marketplace_builder/) app roots,
|
|
162
|
+
* as well as module paths (modules/{name}/public|private/).
|
|
163
|
+
*
|
|
102
164
|
* @example
|
|
103
|
-
* getFileType('file:///root/app/lib/smses/notify.liquid')
|
|
104
|
-
* getFileType('file:///root/app/smses/notify.liquid')
|
|
165
|
+
* getFileType('file:///root/app/lib/smses/notify.liquid') // → Partial
|
|
166
|
+
* getFileType('file:///root/app/smses/notify.liquid') // → Sms
|
|
167
|
+
* getFileType('file:///root/marketplace_builder/views/pages/home.liquid') // → Page
|
|
105
168
|
* getFileType('file:///root/modules/core/generators/templates/lib/create.liquid') // → undefined
|
|
106
169
|
*/
|
|
107
170
|
export function getFileType(uri: UriString): PlatformOSFileType | undefined {
|
|
@@ -113,10 +176,11 @@ export function getFileType(uri: UriString): PlatformOSFileType | undefined {
|
|
|
113
176
|
|
|
114
177
|
/**
|
|
115
178
|
* Returns app-level search paths for a file type (relative to project root).
|
|
179
|
+
* Uses the modern `app/` root (not the legacy `marketplace_builder/` alias).
|
|
116
180
|
*
|
|
117
181
|
* @example
|
|
118
182
|
* getAppPaths(PlatformOSFileType.Partial) // → ['app/views/partials', 'app/lib']
|
|
119
|
-
* getAppPaths(PlatformOSFileType.GraphQL) // → ['app/graphql']
|
|
183
|
+
* getAppPaths(PlatformOSFileType.GraphQL) // → ['app/graphql', 'app/graph_queries']
|
|
120
184
|
*/
|
|
121
185
|
export function getAppPaths(type: PlatformOSFileType): string[] {
|
|
122
186
|
return FILE_TYPE_DIRS[type].map((dir) => `app/${dir}`);
|
|
@@ -134,9 +198,7 @@ export function getAppPaths(type: PlatformOSFileType): string[] {
|
|
|
134
198
|
* 'modules/core/public/views/partials',
|
|
135
199
|
* 'modules/core/private/views/partials',
|
|
136
200
|
* 'app/modules/core/public/lib',
|
|
137
|
-
*
|
|
138
|
-
* 'modules/core/public/lib',
|
|
139
|
-
* 'modules/core/private/lib',
|
|
201
|
+
* ...
|
|
140
202
|
* ]
|
|
141
203
|
*/
|
|
142
204
|
export function getModulePaths(type: PlatformOSFileType, moduleName: string): string[] {
|
|
@@ -158,6 +220,15 @@ export function isKnownLiquidFile(uri: UriString): boolean {
|
|
|
158
220
|
return type !== undefined && LIQUID_FILE_TYPES.has(type);
|
|
159
221
|
}
|
|
160
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Returns true if the URI belongs to a recognized platformOS GraphQL directory
|
|
225
|
+
* and should be linted. Files outside known directories (e.g. generator
|
|
226
|
+
* templates, schema files, ERB templates) return false and are excluded.
|
|
227
|
+
*/
|
|
228
|
+
export function isKnownGraphQLFile(uri: UriString): boolean {
|
|
229
|
+
return getFileType(uri) === PlatformOSFileType.GraphQL;
|
|
230
|
+
}
|
|
231
|
+
|
|
161
232
|
export function isPartial(uri: UriString): boolean {
|
|
162
233
|
return getFileType(uri) === PlatformOSFileType.Partial;
|
|
163
234
|
}
|
|
@@ -189,3 +260,7 @@ export function isSms(uri: UriString): boolean {
|
|
|
189
260
|
export function isMigration(uri: UriString): boolean {
|
|
190
261
|
return getFileType(uri) === PlatformOSFileType.Migration;
|
|
191
262
|
}
|
|
263
|
+
|
|
264
|
+
export function isFormConfiguration(uri: UriString): boolean {
|
|
265
|
+
return getFileType(uri) === PlatformOSFileType.FormConfiguration;
|
|
266
|
+
}
|