@platformos/platformos-language-server-common 0.0.7 → 0.0.9

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.
Files changed (249) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/PropertyShapeInference.d.ts +18 -0
  3. package/dist/PropertyShapeInference.js +62 -0
  4. package/dist/PropertyShapeInference.js.map +1 -1
  5. package/dist/TypeSystem.d.ts +4 -9
  6. package/dist/TypeSystem.js +246 -390
  7. package/dist/TypeSystem.js.map +1 -1
  8. package/dist/codeActions/providers/GenerateDocBlockProvider.d.ts +10 -0
  9. package/dist/codeActions/providers/GenerateDocBlockProvider.js +39 -0
  10. package/dist/codeActions/providers/GenerateDocBlockProvider.js.map +1 -0
  11. package/dist/commands/providers/GenerateDocBlockCommandProvider.d.ts +19 -0
  12. package/dist/commands/providers/GenerateDocBlockCommandProvider.js +64 -0
  13. package/dist/commands/providers/GenerateDocBlockCommandProvider.js.map +1 -0
  14. package/dist/completions/CompletionsProvider.d.ts +6 -10
  15. package/dist/completions/CompletionsProvider.js +6 -9
  16. package/dist/completions/CompletionsProvider.js.map +1 -1
  17. package/dist/completions/params/LiquidCompletionParams.js +6 -17
  18. package/dist/completions/params/LiquidCompletionParams.js.map +1 -1
  19. package/dist/completions/providers/ContentForCompletionProvider.js +2 -4
  20. package/dist/completions/providers/ContentForCompletionProvider.js.map +1 -1
  21. package/dist/completions/providers/FilterNamedParameterCompletionProvider.d.ts +3 -3
  22. package/dist/completions/providers/FilterNamedParameterCompletionProvider.js +6 -6
  23. package/dist/completions/providers/FilterNamedParameterCompletionProvider.js.map +1 -1
  24. package/dist/completions/providers/LiquidDocParamTypeCompletionProvider.d.ts +3 -3
  25. package/dist/completions/providers/LiquidDocParamTypeCompletionProvider.js +3 -3
  26. package/dist/completions/providers/LiquidDocParamTypeCompletionProvider.js.map +1 -1
  27. package/dist/completions/providers/LiquidTagsCompletionProvider.d.ts +3 -3
  28. package/dist/completions/providers/LiquidTagsCompletionProvider.js +3 -3
  29. package/dist/completions/providers/LiquidTagsCompletionProvider.js.map +1 -1
  30. package/dist/completions/providers/RenderPartialParameterCompletionProvider.js +1 -1
  31. package/dist/completions/providers/RenderPartialParameterCompletionProvider.js.map +1 -1
  32. package/dist/completions/providers/index.d.ts +0 -3
  33. package/dist/completions/providers/index.js +1 -7
  34. package/dist/completions/providers/index.js.map +1 -1
  35. package/dist/css/CSSLanguageService.d.ts +19 -5
  36. package/dist/css/CSSLanguageService.js +77 -63
  37. package/dist/css/CSSLanguageService.js.map +1 -1
  38. package/dist/definitions/DefinitionProvider.d.ts +1 -1
  39. package/dist/definitions/DefinitionProvider.js +1 -3
  40. package/dist/definitions/DefinitionProvider.js.map +1 -1
  41. package/dist/diagnostics/offenseToDiagnostic.js +1 -1
  42. package/dist/diagnostics/offenseToDiagnostic.js.map +1 -1
  43. package/dist/diagnostics/runChecks.d.ts +3 -5
  44. package/dist/diagnostics/runChecks.js +12 -64
  45. package/dist/diagnostics/runChecks.js.map +1 -1
  46. package/dist/docset/MarkdownRenderer.js +1 -1
  47. package/dist/docset/MarkdownRenderer.js.map +1 -1
  48. package/dist/documentLinks/DocumentLinksProvider.d.ts +3 -3
  49. package/dist/documentLinks/DocumentLinksProvider.js +3 -3
  50. package/dist/documentLinks/DocumentLinksProvider.js.map +1 -1
  51. package/dist/documents/DocumentManager.d.ts +4 -5
  52. package/dist/documents/DocumentManager.js +17 -12
  53. package/dist/documents/DocumentManager.js.map +1 -1
  54. package/dist/documents/types.d.ts +16 -3
  55. package/dist/documents/types.js +3 -3
  56. package/dist/documents/types.js.map +1 -1
  57. package/dist/hover/HoverProvider.d.ts +5 -8
  58. package/dist/hover/HoverProvider.js +8 -14
  59. package/dist/hover/HoverProvider.js.map +1 -1
  60. package/dist/hover/providers/LiquidFilterArgumentHoverProvider.d.ts +3 -3
  61. package/dist/hover/providers/LiquidFilterArgumentHoverProvider.js +3 -3
  62. package/dist/hover/providers/LiquidFilterArgumentHoverProvider.js.map +1 -1
  63. package/dist/hover/providers/LiquidFilterHoverProvider.d.ts +3 -3
  64. package/dist/hover/providers/LiquidFilterHoverProvider.js +3 -3
  65. package/dist/hover/providers/LiquidFilterHoverProvider.js.map +1 -1
  66. package/dist/hover/providers/LiquidTagHoverProvider.d.ts +3 -3
  67. package/dist/hover/providers/LiquidTagHoverProvider.js +3 -3
  68. package/dist/hover/providers/LiquidTagHoverProvider.js.map +1 -1
  69. package/dist/hover/providers/RenderPartialHoverProvider.js +1 -1
  70. package/dist/hover/providers/RenderPartialHoverProvider.js.map +1 -1
  71. package/dist/hover/providers/RenderPartialParameterHoverProvider.js +1 -1
  72. package/dist/hover/providers/RenderPartialParameterHoverProvider.js.map +1 -1
  73. package/dist/hover/providers/TranslationHoverProvider.d.ts +3 -3
  74. package/dist/hover/providers/TranslationHoverProvider.js +3 -3
  75. package/dist/hover/providers/TranslationHoverProvider.js.map +1 -1
  76. package/dist/index.d.ts +1 -1
  77. package/dist/index.js.map +1 -1
  78. package/dist/internal-types.d.ts +1 -1
  79. package/dist/json/JSONContributions.d.ts +1 -5
  80. package/dist/json/JSONContributions.js +4 -36
  81. package/dist/json/JSONContributions.js.map +1 -1
  82. package/dist/json/JSONLanguageService.d.ts +4 -12
  83. package/dist/json/JSONLanguageService.js +17 -80
  84. package/dist/json/JSONLanguageService.js.map +1 -1
  85. package/dist/json/test/test-helpers.d.ts +1 -3
  86. package/dist/json/test/test-helpers.js +3 -19
  87. package/dist/json/test/test-helpers.js.map +1 -1
  88. package/dist/json/utils.d.ts +0 -5
  89. package/dist/json/utils.js +0 -24
  90. package/dist/json/utils.js.map +1 -1
  91. package/dist/rename/RenameProvider.d.ts +2 -2
  92. package/dist/rename/RenameProvider.js +2 -2
  93. package/dist/rename/RenameProvider.js.map +1 -1
  94. package/dist/rename/providers/LiquidVariableRenameProvider.d.ts +3 -3
  95. package/dist/rename/providers/LiquidVariableRenameProvider.js +4 -4
  96. package/dist/rename/providers/LiquidVariableRenameProvider.js.map +1 -1
  97. package/dist/renamed/RenameHandler.d.ts +2 -3
  98. package/dist/renamed/RenameHandler.js +3 -8
  99. package/dist/renamed/RenameHandler.js.map +1 -1
  100. package/dist/renamed/handlers/AssetRenameHandler.d.ts +3 -3
  101. package/dist/renamed/handlers/AssetRenameHandler.js +5 -5
  102. package/dist/renamed/handlers/AssetRenameHandler.js.map +1 -1
  103. package/dist/renamed/handlers/PartialRenameHandler.d.ts +3 -3
  104. package/dist/renamed/handlers/PartialRenameHandler.js +5 -5
  105. package/dist/renamed/handlers/PartialRenameHandler.js.map +1 -1
  106. package/dist/renamed/handlers/utils.d.ts +1 -1
  107. package/dist/server/AppGraphManager.d.ts +32 -0
  108. package/dist/server/AppGraphManager.js +155 -0
  109. package/dist/server/AppGraphManager.js.map +1 -0
  110. package/dist/server/startServer.d.ts +2 -2
  111. package/dist/server/startServer.js +62 -164
  112. package/dist/server/startServer.js.map +1 -1
  113. package/dist/tsconfig.tsbuildinfo +1 -1
  114. package/dist/types.d.ts +33 -54
  115. package/dist/types.js +21 -26
  116. package/dist/types.js.map +1 -1
  117. package/dist/utils/liquidDoc.js +1 -1
  118. package/dist/utils/liquidDoc.js.map +1 -1
  119. package/dist/utils/uri.d.ts +2 -9
  120. package/dist/utils/uri.js +5 -21
  121. package/dist/utils/uri.js.map +1 -1
  122. package/package.json +4 -4
  123. package/src/ClientCapabilities.ts +1 -1
  124. package/src/PropertyShapeInference.ts +81 -1
  125. package/src/TypeSystem.spec.ts +206 -449
  126. package/src/TypeSystem.ts +267 -460
  127. package/src/codeActions/providers/FixAllProvider.spec.ts +1 -1
  128. package/src/codeActions/providers/FixProvider.spec.ts +11 -11
  129. package/src/codeActions/providers/SuggestionProvider.spec.ts +2 -2
  130. package/src/commands/providers/ApplyFixesProvider.ts +2 -2
  131. package/src/commands/providers/ApplySuggestionProvider.ts +2 -2
  132. package/src/commands/providers/RunChecksProvider.ts +2 -2
  133. package/src/completions/CompletionsProvider.ts +14 -35
  134. package/src/completions/params/LiquidCompletionParams.spec.ts +0 -9
  135. package/src/completions/params/LiquidCompletionParams.ts +8 -17
  136. package/src/completions/params/fix.spec.ts +0 -3
  137. package/src/completions/providers/FilterCompletionProvider.spec.ts +2 -8
  138. package/src/completions/providers/FilterNamedParameterCompletionProvider.spec.ts +1 -5
  139. package/src/completions/providers/FilterNamedParameterCompletionProvider.ts +6 -6
  140. package/src/completions/providers/HtmlAttributeCompletionProvider.spec.ts +1 -4
  141. package/src/completions/providers/HtmlAttributeValueCompletionProvider.spec.ts +1 -4
  142. package/src/completions/providers/HtmlTagCompletionProvider.spec.ts +1 -4
  143. package/src/completions/providers/LiquidDocParamTypeCompletionProvider.spec.ts +1 -28
  144. package/src/completions/providers/LiquidDocParamTypeCompletionProvider.ts +3 -3
  145. package/src/completions/providers/LiquidDocTagCompletionProvider.spec.ts +1 -26
  146. package/src/completions/providers/LiquidTagsCompletionProvider.spec.ts +4 -18
  147. package/src/completions/providers/LiquidTagsCompletionProvider.ts +3 -3
  148. package/src/completions/providers/ObjectAttributeCompletionProvider.spec.ts +2 -31
  149. package/src/completions/providers/ObjectCompletionProvider.spec.ts +34 -123
  150. package/src/completions/providers/PartialCompletionProvider.spec.ts +6 -15
  151. package/src/completions/providers/RenderPartialParameterCompletionProvider.spec.ts +13 -15
  152. package/src/completions/providers/RenderPartialParameterCompletionProvider.ts +2 -3
  153. package/src/completions/providers/TranslationCompletionProvider.spec.ts +1 -4
  154. package/src/completions/providers/TranslationCompletionProvider.ts +3 -3
  155. package/src/completions/providers/index.ts +0 -3
  156. package/src/css/CSSLanguageService.ts +97 -81
  157. package/src/definitions/DefinitionProvider.ts +0 -6
  158. package/src/definitions/providers/TranslationStringDefinitionProvider.spec.ts +1 -5
  159. package/src/diagnostics/offenseToDiagnostic.ts +1 -1
  160. package/src/diagnostics/runChecks.spec.ts +22 -30
  161. package/src/diagnostics/runChecks.ts +17 -91
  162. package/src/docset/MarkdownRenderer.ts +1 -1
  163. package/src/documentLinks/DocumentLinksProvider.ts +10 -10
  164. package/src/documents/DocumentManager.spec.ts +46 -119
  165. package/src/documents/DocumentManager.ts +19 -15
  166. package/src/documents/types.ts +18 -9
  167. package/src/hover/HoverProvider.ts +9 -21
  168. package/src/hover/providers/HtmlAttributeHoverProvider.spec.ts +1 -3
  169. package/src/hover/providers/HtmlAttributeValueHoverProvider.spec.ts +1 -3
  170. package/src/hover/providers/HtmlTagHoverProvider.spec.ts +1 -3
  171. package/src/hover/providers/LiquidDocTagHoverProvider.spec.ts +1 -4
  172. package/src/hover/providers/LiquidFilterArgumentHoverProvider.spec.ts +0 -3
  173. package/src/hover/providers/LiquidFilterArgumentHoverProvider.ts +3 -3
  174. package/src/hover/providers/LiquidFilterHoverProvider.spec.ts +0 -3
  175. package/src/hover/providers/LiquidFilterHoverProvider.ts +3 -3
  176. package/src/hover/providers/LiquidObjectAttributeHoverProvider.spec.ts +1 -3
  177. package/src/hover/providers/LiquidObjectHoverProvider.spec.ts +46 -129
  178. package/src/hover/providers/LiquidTagHoverProvider.spec.ts +0 -3
  179. package/src/hover/providers/LiquidTagHoverProvider.ts +3 -3
  180. package/src/hover/providers/RenderPartialHoverProvider.spec.ts +11 -14
  181. package/src/hover/providers/RenderPartialHoverProvider.ts +1 -5
  182. package/src/hover/providers/RenderPartialParameterHoverProvider.spec.ts +10 -13
  183. package/src/hover/providers/RenderPartialParameterHoverProvider.ts +2 -3
  184. package/src/hover/providers/TranslationHoverProvider.spec.ts +1 -4
  185. package/src/hover/providers/TranslationHoverProvider.ts +3 -3
  186. package/src/index.ts +4 -7
  187. package/src/internal-types.ts +1 -1
  188. package/src/json/JSONContributions.ts +4 -61
  189. package/src/json/JSONLanguageService.ts +19 -117
  190. package/src/json/test/test-helpers.ts +4 -35
  191. package/src/json/utils.ts +0 -27
  192. package/src/rename/RenameProvider.ts +4 -4
  193. package/src/rename/providers/LiquidVariableRenameProvider.spec.ts +5 -5
  194. package/src/rename/providers/LiquidVariableRenameProvider.ts +6 -6
  195. package/src/renamed/RenameHandler.ts +4 -9
  196. package/src/renamed/handlers/AssetRenameHandler.spec.ts +28 -28
  197. package/src/renamed/handlers/AssetRenameHandler.ts +6 -6
  198. package/src/renamed/handlers/PartialRenameHandler.spec.ts +9 -9
  199. package/src/renamed/handlers/PartialRenameHandler.ts +10 -10
  200. package/src/server/{ThemeGraphManager.ts → AppGraphManager.ts} +21 -90
  201. package/src/server/safe.ts +1 -1
  202. package/src/server/startServer.spec.ts +10 -12
  203. package/src/server/startServer.ts +69 -222
  204. package/src/test/CompletionItemsAssertion.spec.ts +1 -4
  205. package/src/types.ts +33 -63
  206. package/src/utils/debounce.ts +1 -1
  207. package/src/utils/liquidDoc.ts +6 -6
  208. package/src/utils/uri.ts +5 -17
  209. package/src/completions/providers/ContentForBlockTypeCompletionProvider.spec.ts +0 -41
  210. package/src/completions/providers/ContentForBlockTypeCompletionProvider.ts +0 -42
  211. package/src/completions/providers/ContentForCompletionProvider.spec.ts +0 -96
  212. package/src/completions/providers/ContentForCompletionProvider.ts +0 -113
  213. package/src/completions/providers/ContentForParameterCompletionProvider.spec.ts +0 -362
  214. package/src/completions/providers/ContentForParameterCompletionProvider.ts +0 -187
  215. package/src/completions/providers/data/contentForParameterCompletionOptions.ts +0 -9
  216. package/src/css/CSSLanguageService.spec.ts +0 -159
  217. package/src/css/test/test-helpers.ts +0 -30
  218. package/src/definitions/providers/SchemaTranslationStringDefinitionProvider.spec.ts +0 -96
  219. package/src/definitions/providers/SchemaTranslationStringDefinitionProvider.ts +0 -82
  220. package/src/hover/providers/ContentForArgumentHoverProvider.spec.ts +0 -76
  221. package/src/hover/providers/ContentForArgumentHoverProvider.ts +0 -56
  222. package/src/hover/providers/ContentForTypeHoverProvider.spec.ts +0 -91
  223. package/src/hover/providers/ContentForTypeHoverProvider.ts +0 -42
  224. package/src/json/JSONLanguageService.spec.ts +0 -424
  225. package/src/json/completions/providers/BlockSettingsPropertyCompletionProvider.spec.ts +0 -163
  226. package/src/json/completions/providers/BlockSettingsPropertyCompletionProvider.ts +0 -121
  227. package/src/json/completions/providers/BlockTypeCompletionProvider.spec.ts +0 -137
  228. package/src/json/completions/providers/BlockTypeCompletionProvider.ts +0 -108
  229. package/src/json/completions/providers/ReferencedBlockTypeCompletionProvider.spec.ts +0 -132
  230. package/src/json/completions/providers/ReferencedBlockTypeCompletionProvider.ts +0 -120
  231. package/src/json/completions/providers/SchemaTranslationCompletionProvider.ts +0 -51
  232. package/src/json/completions/providers/SettingsPropertyCompletionProvider.spec.ts +0 -211
  233. package/src/json/completions/providers/SettingsPropertyCompletionProvider.ts +0 -75
  234. package/src/json/documentLinks/DocumentLinksProvider.spec.ts +0 -223
  235. package/src/json/documentLinks/DocumentLinksProvider.ts +0 -61
  236. package/src/json/hover/providers/BlockSettingsHoverProvider.spec.ts +0 -292
  237. package/src/json/hover/providers/BlockSettingsHoverProvider.ts +0 -99
  238. package/src/json/hover/providers/SchemaTranslationHoverProvider.ts +0 -35
  239. package/src/json/hover/providers/SettingsHoverProvider.spec.ts +0 -139
  240. package/src/json/hover/providers/SettingsHoverProvider.ts +0 -79
  241. package/src/json/schemaSettings.spec.ts +0 -103
  242. package/src/json/schemaSettings.ts +0 -53
  243. package/src/plugins/css.ts +0 -12
  244. package/src/renamed/handlers/BlockRenameHandler.spec.ts +0 -399
  245. package/src/renamed/handlers/BlockRenameHandler.ts +0 -402
  246. package/src/renamed/handlers/SectionRenameHandler.spec.ts +0 -321
  247. package/src/renamed/handlers/SectionRenameHandler.ts +0 -224
  248. package/src/renamed/handlers/utils.ts +0 -22
  249. package/src/settings/index.ts +0 -50
package/src/TypeSystem.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  AssignMarkup,
3
+ AssignPushRhs,
3
4
  ComplexLiquidExpression,
4
5
  FunctionMarkup,
5
6
  LiquidDocParamNode,
@@ -23,33 +24,26 @@ import {
23
24
  ArrayReturnType,
24
25
  DocsetEntry,
25
26
  FilterEntry,
26
- MetafieldDefinitionMap,
27
- MetafieldDefinition,
28
27
  ObjectEntry,
29
28
  ReturnType,
30
29
  SourceCodeType,
31
- ThemeDocset,
30
+ PlatformOSDocset,
32
31
  isError,
33
32
  parseJSON,
34
33
  path,
35
- FETCHED_METAFIELD_CATEGORIES,
36
34
  BasicParamTypes,
37
35
  getValidParamTypes,
38
36
  parseParamType,
39
37
  } from '@platformos/platformos-check-common';
40
- import {
41
- GetThemeSettingsSchemaForURI,
42
- InputSetting,
43
- isInputSetting,
44
- isSettingsCategory,
45
- } from './settings';
46
38
  import { findLast, memo } from './utils';
47
39
  import { visit } from '@platformos/platformos-check-common';
48
40
  import {
49
41
  PropertyShape,
50
42
  inferShapeFromJSONString,
43
+ inferShapeFromJsonLiteral,
51
44
  inferShapeFromGraphQL,
52
45
  lookupPropertyPath,
46
+ mergeShapes,
53
47
  shapeToTypeString,
54
48
  shapeToDetailString,
55
49
  } from './PropertyShapeInference';
@@ -61,17 +55,15 @@ export class TypeSystem {
61
55
  private graphqlSchemaLoaded = false;
62
56
 
63
57
  constructor(
64
- private readonly themeDocset: ThemeDocset,
65
- private readonly getThemeSettingsSchemaForURI: GetThemeSettingsSchemaForURI,
66
- private readonly getMetafieldDefinitions: (rootUri: string) => Promise<MetafieldDefinitionMap>,
58
+ private readonly platformosDocset: PlatformOSDocset,
67
59
  private readonly fs?: AbstractFileSystem,
68
60
  private readonly documentsLocator?: DocumentsLocator,
69
- private readonly findThemeRootURI?: (uri: string) => Promise<string | null>,
61
+ private readonly findAppRootURI?: (uri: string) => Promise<string | null>,
70
62
  ) {}
71
63
 
72
64
  private async getGraphQLSchema(): Promise<string | undefined> {
73
65
  if (!this.graphqlSchemaLoaded) {
74
- this.graphqlSchemaCache = (await this.themeDocset.graphQL()) ?? undefined;
66
+ this.graphqlSchemaCache = (await this.platformosDocset.graphQL()) ?? undefined;
75
67
  this.graphqlSchemaLoaded = true;
76
68
  }
77
69
  return this.graphqlSchemaCache;
@@ -125,174 +117,15 @@ export class TypeSystem {
125
117
  });
126
118
  }
127
119
 
128
- public async themeSettingProperties(uri: string): Promise<ObjectEntry[]> {
129
- const themeSettingsSchema = await this.getThemeSettingsSchemaForURI(uri);
130
- const categories = themeSettingsSchema.filter(isSettingsCategory);
131
- const result: ObjectEntry[] = [];
132
- for (const category of categories) {
133
- const inputSettings = category.settings.filter(isInputSetting);
134
- for (const setting of inputSettings) {
135
- result.push({
136
- name: setting.id,
137
- summary: '', // TODO, this should lookup the locale file for settings... setting.label
138
- description: '', // TODO , this should lookup the locale file as well... setting.info,
139
- return_type: settingReturnType(setting),
140
- access: {
141
- global: false,
142
- parents: [],
143
- template: [],
144
- },
145
- });
146
- }
147
- }
148
- return result;
149
- }
150
-
151
120
  /**
152
121
  * An indexed representation of objects.json by name
153
122
  *
154
123
  * e.g. objectMap['product'] returns the product ObjectEntry.
155
124
  */
156
125
  public objectMap = async (uri: string, ast: LiquidHtmlNode): Promise<ObjectMap> => {
157
- const [objectMap, themeSettingProperties, metafieldDefinitionsObjectMap] = await Promise.all([
158
- this._objectMap(),
159
- this.themeSettingProperties(uri),
160
- this.metafieldDefinitionsObjectMap(uri),
161
- ]);
162
-
163
- // Here we shallow mutate `settings.properties` to have the properties made
164
- // available by settings_schema.json
165
- const result: ObjectMap = {
166
- ...objectMap,
167
- settings: {
168
- ...(objectMap.settings ?? {}),
169
- properties: themeSettingProperties,
170
- },
171
- ...customMetafieldTypeEntries(objectMap['metafield']),
172
- ...metafieldDefinitionsObjectMap,
173
- };
174
-
175
- // For each metafield definition fetched, we need to override existing types with `metafields` property
176
- // to `${category}_metafield`.
177
- //
178
- // WARNING: Since we aren't cloning the object, we are mutating the original type for all themes in
179
- // the workspace. However, this is fine since these changes are not unique to a theme.
180
- for (let category of FETCHED_METAFIELD_CATEGORIES) {
181
- if (!result[category]) continue;
182
-
183
- let metafieldsProperty = result[category].properties?.find(
184
- (prop) => prop.name === 'metafields',
185
- );
186
-
187
- if (!metafieldsProperty) continue;
188
-
189
- metafieldsProperty.return_type = [{ type: `${category}_metafields`, name: '' }];
190
- }
191
-
192
- // Deal with sections/file.liquid section.settings by infering the type from the {% schema %}
193
- if (/[\/\\]sections[\/\\]/.test(uri) && result.section) {
194
- result.section = JSON.parse(JSON.stringify(result.section)); // easy deep clone
195
- const settings = result.section.properties?.find((x) => x.name === 'settings');
196
- if (!settings || !settings.return_type) return result;
197
- settings.return_type = [{ type: 'section_settings', name: '' }];
198
- result.section_settings = {
199
- name: 'section_settings',
200
- access: {
201
- global: false,
202
- parents: [],
203
- template: [],
204
- },
205
- properties: schemaSettingsAsProperties(ast),
206
- return_type: [],
207
- };
208
- }
209
-
210
- // Deal with blocks/files.liquid block.settings in a similar fashion
211
- if (/[\/\\]blocks[\/\\]/.test(uri) && result.block) {
212
- result.block = JSON.parse(JSON.stringify(result.block)); // easy deep clone
213
- const settings = result.block.properties?.find((x) => x.name === 'settings');
214
- if (!settings || !settings.return_type) return result;
215
- settings.return_type = [{ type: 'block_settings', name: '' }];
216
- result.block_settings = {
217
- name: 'block_settings',
218
- access: {
219
- global: false,
220
- parents: [],
221
- template: [],
222
- },
223
- properties: schemaSettingsAsProperties(ast),
224
- return_type: [],
225
- };
226
- }
227
-
228
- return result;
126
+ return this._objectMap();
229
127
  };
230
128
 
231
- public async metafieldDefinitionsObjectMap(uri: string): Promise<ObjectMap> {
232
- let result: ObjectMap = {};
233
-
234
- const metafieldDefinitionMap = await this.getMetafieldDefinitions(uri);
235
-
236
- for (let [category, definitions] of Object.entries(metafieldDefinitionMap)) {
237
- // Metafield definitions need to be grouped by their namespace
238
- let metafieldNamespaces = new Map<string, ObjectEntry[]>();
239
-
240
- for (let definition of definitions as MetafieldDefinition[]) {
241
- if (!metafieldNamespaces.has(definition.namespace)) {
242
- metafieldNamespaces.set(definition.namespace, []);
243
- }
244
-
245
- metafieldNamespaces.get(definition.namespace)!.push({
246
- name: definition.key,
247
- description: definition.description,
248
- return_type: metafieldReturnType(definition.type.name),
249
- });
250
- }
251
-
252
- let metafieldGroupProperties: ObjectEntry[] = [];
253
-
254
- for (let [namespace, namespaceProperties] of metafieldNamespaces) {
255
- const metafieldCategoryNamespaceHandle = `${category}_metafield_${namespace}`;
256
-
257
- // Since the namespace can be shared by multiple categories, we need to make sure the return_type
258
- // handle is unique across all categories
259
- metafieldGroupProperties.push({
260
- name: namespace,
261
- return_type: [{ type: metafieldCategoryNamespaceHandle, name: '' }],
262
- access: {
263
- global: false,
264
- parents: [],
265
- template: [],
266
- },
267
- });
268
-
269
- result[metafieldCategoryNamespaceHandle] = {
270
- name: metafieldCategoryNamespaceHandle,
271
- properties: namespaceProperties,
272
- access: {
273
- global: false,
274
- parents: [],
275
- template: [],
276
- },
277
- };
278
- }
279
-
280
- const metafieldCategoryHandle = `${category}_metafields`;
281
-
282
- result[metafieldCategoryHandle] = {
283
- name: metafieldCategoryHandle,
284
- properties: metafieldGroupProperties,
285
- access: {
286
- global: false,
287
- parents: [],
288
- template: [],
289
- },
290
- };
291
- }
292
-
293
- return result;
294
- }
295
-
296
129
  // This is the big one we reuse (memoized)
297
130
  private _objectMap = memo(async (): Promise<ObjectMap> => {
298
131
  const entries = await this.objectEntries();
@@ -312,20 +145,20 @@ export class TypeSystem {
312
145
  });
313
146
 
314
147
  public filterEntries = memo(async () => {
315
- return this.themeDocset.filters();
148
+ return this.platformosDocset.filters();
316
149
  });
317
150
 
318
151
  public objectEntries = memo(async () => {
319
- return this.themeDocset.objects();
152
+ return this.platformosDocset.objects();
320
153
  });
321
154
 
322
155
  private async symbolsTable(partialAst: LiquidHtmlNode, uri: string): Promise<SymbolsTable> {
323
156
  const [seedSymbolsTable, liquidDrops, graphqlSchema, rootUri, objectMap, filtersMap] =
324
157
  await Promise.all([
325
158
  this.seedSymbolsTable(uri),
326
- this.themeDocset.liquidDrops(),
159
+ this.platformosDocset.liquidDrops(),
327
160
  this.getGraphQLSchema(),
328
- this.findThemeRootURI?.(uri) ?? null,
161
+ this.findAppRootURI?.(uri) ?? null,
329
162
  this.objectMap(uri, partialAst),
330
163
  this.filtersMap(),
331
164
  ]);
@@ -382,36 +215,10 @@ export class TypeSystem {
382
215
  };
383
216
  }
384
217
 
385
- const SECTION_FILE_REGEX = /sections[\/\\][^.\\\/]*\.liquid$/;
386
- const BLOCK_FILE_REGEX = /blocks[\/\\][^.\\\/]*\.liquid$/;
387
218
  const PARTIAL_FILE_REGEX = /(views[\/\\]partials[\/\\]|[\/\\]lib[\/\\])[^.]*\.liquid$/;
388
- const LAYOUT_FILE_REGEX = /layout[\/\\]checkout\.liquid$/;
389
219
 
390
220
  function getContextualEntries(uri: string): string[] {
391
221
  const normalizedUri = path.normalize(uri);
392
- if (LAYOUT_FILE_REGEX.test(normalizedUri)) {
393
- return [
394
- 'locale',
395
- 'direction',
396
- 'skip_to_content_link',
397
- 'checkout_html_classes',
398
- 'checkout_stylesheets',
399
- 'checkout_scripts',
400
- 'content_for_logo',
401
- 'breadcrumb',
402
- 'order_summary_toggle',
403
- 'content_for_order_summary',
404
- 'alternative_payment_methods',
405
- 'content_for_footer',
406
- 'tracking_code',
407
- ];
408
- }
409
- if (SECTION_FILE_REGEX.test(normalizedUri)) {
410
- return ['section', 'predictive_search', 'recommendations', 'comment'];
411
- }
412
- if (BLOCK_FILE_REGEX.test(normalizedUri)) {
413
- return ['app', 'section', 'recommendations', 'block'];
414
- }
415
222
  if (PARTIAL_FILE_REGEX.test(normalizedUri)) {
416
223
  return ['app'];
417
224
  }
@@ -434,7 +241,7 @@ type FilterEntryName = FilterEntry['name'];
434
241
  export const Untyped = 'untyped' as const;
435
242
  export type Untyped = typeof Untyped;
436
243
 
437
- /** Unknown is for variables that don't exist, type would come from context (e.g. snippet var without LiquidDoc) */
244
+ /** Unknown is for variables that don't exist, type would come from context (e.g. partial var without LiquidDoc) */
438
245
  export const Unknown = 'unknown' as const;
439
246
  export type Unknown = typeof Untyped;
440
247
 
@@ -574,54 +381,215 @@ async function buildSymbolsTable(
574
381
  const typeRanges = await visit<SourceCodeType.LiquidHtml, TypeRange | TypeRange[]>(partialAst, {
575
382
  // {% assign x = foo.x | filter %}
576
383
  // {% assign x = '{"a": 1}' | parse_json %}
384
+ // {% assign x = {a: 1, b: "hello"} %}
385
+ // {% assign x["key"] = value %}
386
+ // {% assign arr << item %}
387
+ // {% assign arr = source << item %}
577
388
  async AssignMarkup(node) {
578
- // Check if this has a parse_json or to_hash filter
579
- const hasParseJsonFilter = node.value.filters?.some(
580
- (f: { name: string }) => f.name === 'parse_json' || f.name === 'to_hash',
581
- );
389
+ // For explicit push form (assign a = source << value), treat as array append
390
+ const isPushRhs = node.value.type === NodeTypes.AssignPushRhs;
391
+ const effectiveValue = isPushRhs
392
+ ? (node.value as AssignPushRhs).pushValue
393
+ : (node.value as LiquidVariable);
394
+ const effectiveOperator = isPushRhs ? '<<' : node.operator;
395
+ const expression = effectiveValue.expression;
396
+ let valueShape: PropertyShape | undefined;
397
+
398
+ // Resolver for variable references inside JSON literals
399
+ const resolveExpr = (expr: LiquidExpression): PropertyShape | undefined => {
400
+ if (expr.type !== NodeTypes.VariableLookup || !expr.name) return undefined;
401
+
402
+ // Look up the variable's shape from already-processed assignments
403
+ const shapes = variableShapes.get(expr.name);
404
+ const shapeEntry = shapes
405
+ ? findLastApplicableShape(shapes, node.position.start)
406
+ : undefined;
407
+ let shape = shapeEntry?.shape;
408
+
409
+ // Fall back to seedSymbolsTable
410
+ if (!shape && seedSymbolsTable[expr.name]) {
411
+ for (const tr of seedSymbolsTable[expr.name]) {
412
+ if (tr.range[0] < node.position.start) {
413
+ if (typeof tr.type !== 'string' && tr.type.kind === 'shape') {
414
+ shape = tr.type.shape;
415
+ } else if (typeof tr.type === 'string' || tr.type.kind === 'array') {
416
+ shape = resolvedTypeToShape(tr.type);
417
+ }
418
+ }
419
+ }
420
+ }
582
421
 
583
- if (hasParseJsonFilter) {
584
- let jsonString: string | undefined;
422
+ if (!shape) return undefined;
585
423
 
586
- // Check if expression is a direct JSON string
587
- if (node.value.expression.type === NodeTypes.String) {
588
- jsonString = node.value.expression.value;
424
+ // Resolve lookups (e.g. a.x or a["key"])
425
+ for (const lookup of expr.lookups) {
426
+ if (shape.kind === 'object' && lookup.type === NodeTypes.String && shape.properties) {
427
+ const prop = shape.properties.get(lookup.value);
428
+ if (prop) {
429
+ shape = prop;
430
+ } else {
431
+ return undefined;
432
+ }
433
+ } else if (shape.kind === 'array') {
434
+ if (
435
+ lookup.type === NodeTypes.Number ||
436
+ (lookup.type === NodeTypes.String &&
437
+ (lookup.value === 'first' || lookup.value === 'last'))
438
+ ) {
439
+ shape = shape.itemShape;
440
+ if (!shape) return undefined;
441
+ } else {
442
+ return undefined;
443
+ }
444
+ } else {
445
+ return undefined;
446
+ }
589
447
  }
590
448
 
591
- // Check if there's a default filter with a JSON string argument
592
- if (!jsonString && node.value.filters) {
593
- const defaultFilter = node.value.filters.find(
594
- (f: { name: string }) => f.name === 'default',
595
- );
596
- if (defaultFilter && defaultFilter.args && defaultFilter.args.length > 0) {
597
- const firstArg = defaultFilter.args[0];
598
- if (firstArg.type === NodeTypes.String) {
599
- jsonString = firstArg.value;
449
+ return shape;
450
+ };
451
+
452
+ // Case 1: JSON literal expression
453
+ if (
454
+ expression.type === NodeTypes.JsonHashLiteral ||
455
+ expression.type === NodeTypes.JsonArrayLiteral
456
+ ) {
457
+ valueShape = inferShapeFromJsonLiteral(expression, resolveExpr);
458
+ }
459
+
460
+ // Case 2: parse_json / to_hash filter on a string
461
+ if (!valueShape) {
462
+ const hasParseJsonFilter = effectiveValue.filters?.some(
463
+ (f: { name: string }) => f.name === 'parse_json' || f.name === 'to_hash',
464
+ );
465
+ if (hasParseJsonFilter) {
466
+ let jsonString: string | undefined;
467
+ if (expression.type === NodeTypes.String) {
468
+ jsonString = expression.value;
469
+ }
470
+ if (!jsonString && effectiveValue.filters) {
471
+ const defaultFilter = effectiveValue.filters.find(
472
+ (f: { name: string }) => f.name === 'default',
473
+ );
474
+ if (
475
+ defaultFilter &&
476
+ defaultFilter.args &&
477
+ defaultFilter.args.length > 0 &&
478
+ defaultFilter.args[0].type === NodeTypes.String
479
+ ) {
480
+ jsonString = defaultFilter.args[0].value;
600
481
  }
601
482
  }
483
+ if (jsonString) {
484
+ valueShape = inferShapeFromJSONString(jsonString) ?? undefined;
485
+ }
602
486
  }
487
+ }
603
488
 
604
- if (jsonString) {
605
- const shape = inferShapeFromJSONString(jsonString);
606
- if (shape) {
607
- // Track shape for potential hash_assign merging
608
- if (!variableShapes.has(node.name)) {
609
- variableShapes.set(node.name, []);
610
- }
611
- variableShapes.get(node.name)!.push({ shape, rangeEnd: node.position.end });
489
+ // Case 3: Infer primitive shape for << and LHS lookup scenarios
490
+ if (
491
+ !valueShape &&
492
+ ((node.lookups && node.lookups.length > 0) || effectiveOperator === '<<')
493
+ ) {
494
+ if (expression.type === NodeTypes.String) {
495
+ valueShape = { kind: 'primitive', primitiveType: 'string' };
496
+ } else if (expression.type === NodeTypes.Number) {
497
+ valueShape = { kind: 'primitive', primitiveType: 'number' };
498
+ } else if (expression.type === NodeTypes.LiquidLiteral) {
499
+ if (expression.value === null) {
500
+ valueShape = { kind: 'primitive', primitiveType: 'null' };
501
+ } else if (typeof expression.value === 'boolean') {
502
+ valueShape = { kind: 'primitive', primitiveType: 'boolean' };
503
+ }
504
+ }
505
+ }
612
506
 
613
- return {
614
- identifier: node.name,
615
- type: shapeType(shape),
616
- range: [node.position.end],
617
- };
507
+ // Handle lookups on the LHS (assign x["key"] = value)
508
+ if (node.lookups && node.lookups.length > 0) {
509
+ const lookupPath = getAssignLookupPath(node.lookups);
510
+ if (lookupPath && lookupPath.length > 0) {
511
+ const existingShapes = variableShapes.get(node.name) || [];
512
+ const existingShapeEntry = findLastApplicableShape(existingShapes, node.position.start);
513
+
514
+ let baseShape: PropertyShape;
515
+ if (existingShapeEntry) {
516
+ baseShape = existingShapeEntry.shape;
517
+ } else {
518
+ let existingType: PseudoType | ArrayType | ShapeType | UnionType | undefined;
519
+ if (seedSymbolsTable[node.name]) {
520
+ for (const tr of seedSymbolsTable[node.name]) {
521
+ if (tr.range[0] < node.position.start) {
522
+ if (typeof tr.type !== 'string' && tr.type.kind === 'shape') {
523
+ existingType = tr.type;
524
+ }
525
+ }
526
+ }
527
+ }
528
+ baseShape =
529
+ existingType && isShapeType(existingType)
530
+ ? existingType.shape
531
+ : { kind: 'object', properties: new Map() };
618
532
  }
533
+
534
+ const newShape = mergeNestedPropertyIntoShape(
535
+ baseShape,
536
+ lookupPath,
537
+ valueShape ?? { kind: 'primitive' },
538
+ );
539
+
540
+ if (!variableShapes.has(node.name)) variableShapes.set(node.name, []);
541
+ variableShapes.get(node.name)!.push({ shape: newShape, rangeEnd: node.position.end });
542
+
543
+ return {
544
+ identifier: node.name,
545
+ type: shapeType(newShape),
546
+ range: [node.position.end],
547
+ };
548
+ }
549
+ }
550
+
551
+ // Handle << operator (array append), including explicit form (assign a = source << value)
552
+ if (effectiveOperator === '<<') {
553
+ const itemShape: PropertyShape = valueShape ?? { kind: 'primitive' };
554
+ const existingShapes = variableShapes.get(node.name) || [];
555
+ const existingShapeEntry = findLastApplicableShape(existingShapes, node.position.start);
556
+
557
+ let arrayShape: PropertyShape;
558
+ if (existingShapeEntry?.shape.kind === 'array') {
559
+ const existing = existingShapeEntry.shape.itemShape;
560
+ arrayShape = {
561
+ kind: 'array',
562
+ itemShape: existing ? mergeShapes(existing, itemShape) : itemShape,
563
+ };
564
+ } else {
565
+ arrayShape = { kind: 'array', itemShape };
619
566
  }
567
+
568
+ if (!variableShapes.has(node.name)) variableShapes.set(node.name, []);
569
+ variableShapes.get(node.name)!.push({ shape: arrayShape, rangeEnd: node.position.end });
570
+
571
+ return {
572
+ identifier: node.name,
573
+ type: shapeType(arrayShape),
574
+ range: [node.position.end],
575
+ };
620
576
  }
621
577
 
578
+ // Simple assignment with shape (JSON literal or parse_json)
579
+ if (valueShape) {
580
+ if (!variableShapes.has(node.name)) variableShapes.set(node.name, []);
581
+ variableShapes.get(node.name)!.push({ shape: valueShape, rangeEnd: node.position.end });
582
+ return {
583
+ identifier: node.name,
584
+ type: shapeType(valueShape),
585
+ range: [node.position.end],
586
+ };
587
+ }
588
+
589
+ // Default: lazy variable type
622
590
  return {
623
591
  identifier: node.name,
624
- type: lazyVariable(node.value, node.position.start),
592
+ type: lazyVariable(effectiveValue, node.position.start),
625
593
  range: [node.position.end],
626
594
  };
627
595
  },
@@ -657,12 +625,6 @@ async function buildSymbolsTable(
657
625
  type: String,
658
626
  range: [node.position.end],
659
627
  };
660
- } else if (['form', 'paginate'].includes(node.name)) {
661
- return {
662
- identifier: node.name,
663
- type: node.name,
664
- range: [node.blockStartPosition.end, end(node.blockEndPosition?.end)],
665
- };
666
628
  } else if (['for', 'tablerow'].includes(node.name)) {
667
629
  return {
668
630
  identifier: node.name + 'loop',
@@ -1022,10 +984,22 @@ function inferType(
1022
984
  return arrayType('number');
1023
985
  }
1024
986
 
987
+ // JSON literal expressions: {key: val} or [1, 2, 3]
988
+ case NodeTypes.JsonHashLiteral:
989
+ case NodeTypes.JsonArrayLiteral: {
990
+ const resolver = (expr: LiquidExpression): PropertyShape | undefined => {
991
+ const type = inferType(expr, symbolsTable, objectMap, filtersMap);
992
+ return resolvedTypeToShape(type);
993
+ };
994
+ return shapeType(inferShapeFromJsonLiteral(thing, resolver));
995
+ }
996
+
1025
997
  // The type of the assign markup is the type of the right hand side.
1026
998
  // {% assign x = y.property | filter1 | filter2 %}
1027
999
  case NodeTypes.AssignMarkup: {
1028
- return inferType(thing.value, symbolsTable, objectMap, filtersMap);
1000
+ const assignValue =
1001
+ thing.value.type === NodeTypes.AssignPushRhs ? thing.value.pushValue : thing.value;
1002
+ return inferType(assignValue, symbolsTable, objectMap, filtersMap);
1029
1003
  }
1030
1004
 
1031
1005
  // A variable lookup is expression[.lookup]*
@@ -1346,6 +1320,36 @@ function shapeToType(shape: PropertyShape): PseudoType | ArrayType | ShapeType {
1346
1320
  return Untyped;
1347
1321
  }
1348
1322
 
1323
+ /**
1324
+ * Convert a resolved type back to a PropertyShape (inverse of shapeToType).
1325
+ * Used when embedding resolved variable types into JSON literal shapes.
1326
+ */
1327
+ function resolvedTypeToShape(
1328
+ type: PseudoType | ArrayType | ShapeType | UnionType,
1329
+ ): PropertyShape | undefined {
1330
+ if (typeof type === 'string') {
1331
+ switch (type) {
1332
+ case 'string':
1333
+ return { kind: 'primitive', primitiveType: 'string' };
1334
+ case 'number':
1335
+ return { kind: 'primitive', primitiveType: 'number' };
1336
+ case 'boolean':
1337
+ return { kind: 'primitive', primitiveType: 'boolean' };
1338
+ case Untyped:
1339
+ case Unknown:
1340
+ return undefined;
1341
+ default:
1342
+ return { kind: 'primitive' };
1343
+ }
1344
+ }
1345
+ if (isShapeType(type)) return type.shape;
1346
+ if (isArrayType(type)) {
1347
+ const itemShape = resolvedTypeToShape(type.valueType);
1348
+ return { kind: 'array', itemShape };
1349
+ }
1350
+ return undefined;
1351
+ }
1352
+
1349
1353
  function inferPseudoTypePropertyType(
1350
1354
  curr: PseudoType, // settings
1351
1355
  lookup: LiquidExpression,
@@ -1656,6 +1660,24 @@ export function typeToDisplayString(type: PseudoType | ArrayType | ShapeType | U
1656
1660
  return 'unknown';
1657
1661
  }
1658
1662
 
1663
+ /**
1664
+ * Extract the lookup path from assign lookups.
1665
+ * For {% assign a["key1"]["key2"] = value %}, returns ['key1', 'key2']
1666
+ */
1667
+ function getAssignLookupPath(lookups: LiquidExpression[]): string[] | undefined {
1668
+ const path: string[] = [];
1669
+ for (const lookup of lookups) {
1670
+ if (lookup.type === NodeTypes.String) {
1671
+ path.push(lookup.value);
1672
+ } else if (lookup.type === NodeTypes.Number) {
1673
+ path.push(`${lookup.value}`);
1674
+ } else {
1675
+ return undefined;
1676
+ }
1677
+ }
1678
+ return path.length > 0 ? path : undefined;
1679
+ }
1680
+
1659
1681
  /**
1660
1682
  * Extract the lookup path from a hash_assign target.
1661
1683
  * For {% hash_assign a['key1']['key2'] = value %}, returns ['key1', 'key2']
@@ -1731,218 +1753,3 @@ function findLastApplicableShape(
1731
1753
  }
1732
1754
  return result;
1733
1755
  }
1734
-
1735
- function settingReturnType(setting: InputSetting): ObjectEntry['return_type'] {
1736
- switch (setting.type) {
1737
- // basic settings
1738
- case 'checkbox':
1739
- return [{ type: 'boolean', name: '' }];
1740
-
1741
- case 'range':
1742
- case 'number':
1743
- return [{ type: 'number', name: '' }];
1744
-
1745
- case 'radio':
1746
- case 'select':
1747
- case 'text':
1748
- case 'textarea':
1749
- return [{ type: 'string', name: '' }];
1750
-
1751
- // specialized settings
1752
- case 'article':
1753
- return [{ type: 'article', name: '' }];
1754
-
1755
- case 'blog':
1756
- return [{ type: 'blog', name: '' }];
1757
-
1758
- case 'collection':
1759
- return [{ type: 'collection', name: '' }];
1760
-
1761
- case 'collection_list':
1762
- return [{ type: 'array', array_value: 'collection' }];
1763
-
1764
- case 'color':
1765
- return [{ type: 'color', name: '' }];
1766
-
1767
- case 'color_background':
1768
- return [{ type: 'string', name: '' }];
1769
-
1770
- case 'color_scheme':
1771
- return [{ type: 'color_scheme', name: '' }];
1772
-
1773
- // TODO ??
1774
- case 'color_scheme_group':
1775
- return [];
1776
-
1777
- case 'font_picker':
1778
- return [{ type: 'font', name: '' }];
1779
-
1780
- case 'html':
1781
- return [{ type: 'string', name: '' }];
1782
-
1783
- case 'image_picker':
1784
- return [{ type: 'image', name: '' }];
1785
-
1786
- case 'inline_richtext':
1787
- return [{ type: 'string', name: '' }];
1788
-
1789
- case 'link_list':
1790
- return [{ type: 'linklist', name: '' }];
1791
-
1792
- case 'liquid':
1793
- return [{ type: 'string', name: '' }];
1794
-
1795
- case 'page':
1796
- return [{ type: 'page', name: '' }];
1797
-
1798
- case 'product':
1799
- return [{ type: 'product', name: '' }];
1800
-
1801
- case 'product_list':
1802
- return [{ type: 'array', array_value: 'product' }];
1803
-
1804
- case 'richtext':
1805
- return [{ type: 'string', name: '' }];
1806
-
1807
- case 'text_alignment':
1808
- return [{ type: 'string', name: '' }];
1809
-
1810
- case 'url':
1811
- return [{ type: 'string', name: '' }];
1812
-
1813
- case 'video':
1814
- return [{ type: 'video', name: '' }];
1815
-
1816
- case 'video_url':
1817
- return [{ type: 'string', name: '' }];
1818
-
1819
- default:
1820
- return [];
1821
- }
1822
- }
1823
-
1824
- const METAFIELD_TYPE_TO_TYPE = Object.freeze({
1825
- single_line_text_field: String,
1826
- multi_line_text_field: String,
1827
- url_reference: String,
1828
- date: String,
1829
- date_time: String,
1830
- number_integer: 'number',
1831
- number_decimal: 'number',
1832
- product_reference: 'product',
1833
- collection_reference: 'collection',
1834
- variant_reference: 'variant',
1835
- page_reference: 'page',
1836
- boolean: 'boolean',
1837
- color: 'color',
1838
- weight: 'measurement',
1839
- volume: 'measurement',
1840
- dimension: 'measurement',
1841
- rating: 'rating',
1842
- money: 'money',
1843
- json: Untyped,
1844
- metaobject_reference: 'metaobject',
1845
- mixed_reference: Untyped,
1846
- rich_text_field: Untyped,
1847
- file_reference: Untyped,
1848
- });
1849
-
1850
- const REFERENCE_TYPE_METAFIELDS = Object.entries(METAFIELD_TYPE_TO_TYPE)
1851
- .filter(([metafieldType, _type]) => metafieldType.endsWith('_reference'))
1852
- .map(([_metafieldType, type]) => type);
1853
-
1854
- function metafieldReturnType(metafieldType: string): ObjectEntry['return_type'] {
1855
- let isArray = metafieldType.startsWith('list.');
1856
-
1857
- if (isArray) {
1858
- metafieldType = metafieldType.split('.')[1];
1859
- }
1860
-
1861
- let type = 'metafield_' + ((METAFIELD_TYPE_TO_TYPE as any)[metafieldType] ?? Untyped);
1862
-
1863
- if (isArray) {
1864
- return [{ type: `${type}_array`, name: '' }];
1865
- }
1866
-
1867
- return [{ type: type, name: '' }];
1868
- }
1869
-
1870
- // The default `metafield` type has an untyped `value` property.
1871
- // We need to create new metafield types with the labels `metafield_x` and `metafield_x_array`
1872
- // where x is the type of metafield inside the `value` property. The metafields ending with `x_array`
1873
- // is where the value is an array of type x.
1874
- const customMetafieldTypeEntries = memo((baseMetafieldEntry: ObjectEntry) => {
1875
- if (!baseMetafieldEntry) return {} as ObjectMap;
1876
-
1877
- return [
1878
- ...new Set([...Object.values(METAFIELD_TYPE_TO_TYPE), ...FETCHED_METAFIELD_CATEGORIES]),
1879
- ].reduce((map, type) => {
1880
- {
1881
- const metafieldEntry = JSON.parse(JSON.stringify(baseMetafieldEntry)); // easy deep clone
1882
- const metafieldValueProp = metafieldEntry.properties?.find(
1883
- (prop: any) => prop.name === 'value',
1884
- );
1885
-
1886
- if (metafieldValueProp) {
1887
- metafieldValueProp.return_type = [{ type: type, name: '' }];
1888
- metafieldValueProp.description = '';
1889
- metafieldEntry.name = `metafield_${type}`;
1890
- map[metafieldEntry.name] = metafieldEntry;
1891
- }
1892
- }
1893
-
1894
- {
1895
- const metafieldArrayEntry = JSON.parse(JSON.stringify(baseMetafieldEntry)); // easy deep clone
1896
- const metafieldArrayValueProp = metafieldArrayEntry.properties?.find(
1897
- (prop: any) => prop.name === 'value',
1898
- );
1899
-
1900
- if (metafieldArrayValueProp) {
1901
- // A metafield definition using a list of references does not use an array, but a separate type of collection.
1902
- // For auto-completion purposes, we can't use the array type
1903
- // https://shopify.dev/docs/api/liquid/objects/metafield#metafield-determining-the-length-of-a-list-metafield
1904
- if (REFERENCE_TYPE_METAFIELDS.includes(type as any)) {
1905
- metafieldArrayValueProp.return_type = [{ type: 'untyped', name: '' }];
1906
- } else {
1907
- metafieldArrayValueProp.return_type = [{ type: 'array', name: '', array_value: type }];
1908
- }
1909
- metafieldArrayValueProp.description = '';
1910
- metafieldArrayEntry.name = `metafield_${type}_array`;
1911
- map[metafieldArrayEntry.name] = metafieldArrayEntry;
1912
- }
1913
- }
1914
-
1915
- return map;
1916
- }, {} as ObjectMap);
1917
- });
1918
-
1919
- function schemaSettingsAsProperties(ast: LiquidHtmlNode): ObjectEntry[] {
1920
- if (ast.type !== NodeTypes.Document) return [];
1921
- try {
1922
- const source = ast._source; // (the unfixed source)
1923
- const start = /\{%\s*schema\s*%\}/m.exec(source);
1924
- const end = /\{%\s*endschema\s*%\}/m.exec(source);
1925
- if (!start || !end) return [];
1926
- const schema = source.slice(start.index + start[0].length, end.index);
1927
- const json = parseJSON(schema);
1928
- if (isError(json) || !('settings' in json) || !Array.isArray(json.settings)) return [];
1929
- const result: ObjectEntry[] = [];
1930
- const inputSettings = json.settings.filter(isInputSetting);
1931
- for (const setting of inputSettings) {
1932
- result.push({
1933
- name: setting.id,
1934
- summary: '', // TODO, this should lookup the locale file for settings... setting.label
1935
- description: '', // TODO , this should lookup the locale file as well... setting.info,
1936
- return_type: settingReturnType(setting),
1937
- access: {
1938
- global: false,
1939
- parents: [],
1940
- template: [],
1941
- },
1942
- });
1943
- }
1944
- return result;
1945
- } catch (_) {
1946
- return [];
1947
- }
1948
- }