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

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 (239) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/PropertyShapeInference.d.ts +18 -0
  3. package/dist/PropertyShapeInference.js +58 -0
  4. package/dist/PropertyShapeInference.js.map +1 -1
  5. package/dist/TypeSystem.d.ts +4 -9
  6. package/dist/TypeSystem.js +234 -388
  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 +4 -16
  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 +12 -11
  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 +0 -8
  120. package/dist/utils/uri.js +1 -17
  121. package/dist/utils/uri.js.map +1 -1
  122. package/package.json +4 -4
  123. package/src/PropertyShapeInference.ts +76 -1
  124. package/src/TypeSystem.spec.ts +188 -450
  125. package/src/TypeSystem.ts +251 -457
  126. package/src/completions/CompletionsProvider.ts +13 -34
  127. package/src/completions/params/LiquidCompletionParams.spec.ts +0 -9
  128. package/src/completions/params/LiquidCompletionParams.ts +4 -14
  129. package/src/completions/params/fix.spec.ts +0 -3
  130. package/src/completions/providers/FilterCompletionProvider.spec.ts +2 -8
  131. package/src/completions/providers/FilterNamedParameterCompletionProvider.spec.ts +1 -5
  132. package/src/completions/providers/FilterNamedParameterCompletionProvider.ts +6 -6
  133. package/src/completions/providers/HtmlAttributeCompletionProvider.spec.ts +1 -4
  134. package/src/completions/providers/HtmlAttributeValueCompletionProvider.spec.ts +1 -4
  135. package/src/completions/providers/HtmlTagCompletionProvider.spec.ts +1 -4
  136. package/src/completions/providers/LiquidDocParamTypeCompletionProvider.spec.ts +1 -28
  137. package/src/completions/providers/LiquidDocParamTypeCompletionProvider.ts +3 -3
  138. package/src/completions/providers/LiquidDocTagCompletionProvider.spec.ts +1 -26
  139. package/src/completions/providers/LiquidTagsCompletionProvider.spec.ts +2 -16
  140. package/src/completions/providers/LiquidTagsCompletionProvider.ts +3 -3
  141. package/src/completions/providers/ObjectAttributeCompletionProvider.spec.ts +2 -31
  142. package/src/completions/providers/ObjectCompletionProvider.spec.ts +34 -123
  143. package/src/completions/providers/PartialCompletionProvider.spec.ts +4 -13
  144. package/src/completions/providers/RenderPartialParameterCompletionProvider.spec.ts +3 -5
  145. package/src/completions/providers/RenderPartialParameterCompletionProvider.ts +0 -1
  146. package/src/completions/providers/TranslationCompletionProvider.spec.ts +1 -4
  147. package/src/completions/providers/index.ts +0 -3
  148. package/src/css/CSSLanguageService.ts +97 -81
  149. package/src/definitions/DefinitionProvider.ts +0 -6
  150. package/src/definitions/providers/TranslationStringDefinitionProvider.spec.ts +1 -5
  151. package/src/diagnostics/offenseToDiagnostic.ts +1 -1
  152. package/src/diagnostics/runChecks.spec.ts +16 -24
  153. package/src/diagnostics/runChecks.ts +17 -91
  154. package/src/docset/MarkdownRenderer.ts +1 -1
  155. package/src/documentLinks/DocumentLinksProvider.ts +3 -3
  156. package/src/documents/DocumentManager.spec.ts +12 -97
  157. package/src/documents/DocumentManager.ts +13 -14
  158. package/src/documents/types.ts +18 -9
  159. package/src/hover/HoverProvider.ts +9 -21
  160. package/src/hover/providers/HtmlAttributeHoverProvider.spec.ts +1 -3
  161. package/src/hover/providers/HtmlAttributeValueHoverProvider.spec.ts +1 -3
  162. package/src/hover/providers/HtmlTagHoverProvider.spec.ts +1 -3
  163. package/src/hover/providers/LiquidDocTagHoverProvider.spec.ts +0 -3
  164. package/src/hover/providers/LiquidFilterArgumentHoverProvider.spec.ts +0 -3
  165. package/src/hover/providers/LiquidFilterArgumentHoverProvider.ts +3 -3
  166. package/src/hover/providers/LiquidFilterHoverProvider.spec.ts +0 -3
  167. package/src/hover/providers/LiquidFilterHoverProvider.ts +3 -3
  168. package/src/hover/providers/LiquidObjectAttributeHoverProvider.spec.ts +1 -3
  169. package/src/hover/providers/LiquidObjectHoverProvider.spec.ts +46 -129
  170. package/src/hover/providers/LiquidTagHoverProvider.spec.ts +0 -3
  171. package/src/hover/providers/LiquidTagHoverProvider.ts +3 -3
  172. package/src/hover/providers/RenderPartialHoverProvider.spec.ts +1 -4
  173. package/src/hover/providers/RenderPartialHoverProvider.ts +1 -5
  174. package/src/hover/providers/RenderPartialParameterHoverProvider.spec.ts +1 -4
  175. package/src/hover/providers/RenderPartialParameterHoverProvider.ts +0 -1
  176. package/src/hover/providers/TranslationHoverProvider.spec.ts +1 -4
  177. package/src/hover/providers/TranslationHoverProvider.ts +3 -3
  178. package/src/index.ts +2 -5
  179. package/src/internal-types.ts +1 -1
  180. package/src/json/JSONContributions.ts +4 -61
  181. package/src/json/JSONLanguageService.ts +19 -117
  182. package/src/json/test/test-helpers.ts +4 -35
  183. package/src/json/utils.ts +0 -27
  184. package/src/rename/RenameProvider.ts +3 -3
  185. package/src/rename/providers/LiquidVariableRenameProvider.spec.ts +4 -4
  186. package/src/rename/providers/LiquidVariableRenameProvider.ts +4 -4
  187. package/src/renamed/RenameHandler.ts +4 -9
  188. package/src/renamed/handlers/AssetRenameHandler.spec.ts +3 -3
  189. package/src/renamed/handlers/AssetRenameHandler.ts +5 -5
  190. package/src/renamed/handlers/PartialRenameHandler.spec.ts +2 -2
  191. package/src/renamed/handlers/PartialRenameHandler.ts +5 -5
  192. package/src/renamed/handlers/utils.ts +1 -1
  193. package/src/server/{ThemeGraphManager.ts → AppGraphManager.ts} +21 -90
  194. package/src/server/startServer.spec.ts +7 -9
  195. package/src/server/startServer.ts +65 -217
  196. package/src/test/CompletionItemsAssertion.spec.ts +1 -4
  197. package/src/types.ts +33 -63
  198. package/src/utils/liquidDoc.ts +1 -1
  199. package/src/utils/uri.ts +0 -14
  200. package/src/completions/providers/ContentForBlockTypeCompletionProvider.spec.ts +0 -41
  201. package/src/completions/providers/ContentForBlockTypeCompletionProvider.ts +0 -42
  202. package/src/completions/providers/ContentForCompletionProvider.spec.ts +0 -96
  203. package/src/completions/providers/ContentForCompletionProvider.ts +0 -113
  204. package/src/completions/providers/ContentForParameterCompletionProvider.spec.ts +0 -362
  205. package/src/completions/providers/ContentForParameterCompletionProvider.ts +0 -187
  206. package/src/completions/providers/data/contentForParameterCompletionOptions.ts +0 -9
  207. package/src/css/CSSLanguageService.spec.ts +0 -159
  208. package/src/css/test/test-helpers.ts +0 -30
  209. package/src/definitions/providers/SchemaTranslationStringDefinitionProvider.spec.ts +0 -96
  210. package/src/definitions/providers/SchemaTranslationStringDefinitionProvider.ts +0 -82
  211. package/src/hover/providers/ContentForArgumentHoverProvider.spec.ts +0 -76
  212. package/src/hover/providers/ContentForArgumentHoverProvider.ts +0 -56
  213. package/src/hover/providers/ContentForTypeHoverProvider.spec.ts +0 -91
  214. package/src/hover/providers/ContentForTypeHoverProvider.ts +0 -42
  215. package/src/json/JSONLanguageService.spec.ts +0 -424
  216. package/src/json/completions/providers/BlockSettingsPropertyCompletionProvider.spec.ts +0 -163
  217. package/src/json/completions/providers/BlockSettingsPropertyCompletionProvider.ts +0 -121
  218. package/src/json/completions/providers/BlockTypeCompletionProvider.spec.ts +0 -137
  219. package/src/json/completions/providers/BlockTypeCompletionProvider.ts +0 -108
  220. package/src/json/completions/providers/ReferencedBlockTypeCompletionProvider.spec.ts +0 -132
  221. package/src/json/completions/providers/ReferencedBlockTypeCompletionProvider.ts +0 -120
  222. package/src/json/completions/providers/SchemaTranslationCompletionProvider.ts +0 -51
  223. package/src/json/completions/providers/SettingsPropertyCompletionProvider.spec.ts +0 -211
  224. package/src/json/completions/providers/SettingsPropertyCompletionProvider.ts +0 -75
  225. package/src/json/documentLinks/DocumentLinksProvider.spec.ts +0 -223
  226. package/src/json/documentLinks/DocumentLinksProvider.ts +0 -61
  227. package/src/json/hover/providers/BlockSettingsHoverProvider.spec.ts +0 -292
  228. package/src/json/hover/providers/BlockSettingsHoverProvider.ts +0 -99
  229. package/src/json/hover/providers/SchemaTranslationHoverProvider.ts +0 -35
  230. package/src/json/hover/providers/SettingsHoverProvider.spec.ts +0 -139
  231. package/src/json/hover/providers/SettingsHoverProvider.ts +0 -79
  232. package/src/json/schemaSettings.spec.ts +0 -103
  233. package/src/json/schemaSettings.ts +0 -53
  234. package/src/plugins/css.ts +0 -12
  235. package/src/renamed/handlers/BlockRenameHandler.spec.ts +0 -399
  236. package/src/renamed/handlers/BlockRenameHandler.ts +0 -402
  237. package/src/renamed/handlers/SectionRenameHandler.spec.ts +0 -321
  238. package/src/renamed/handlers/SectionRenameHandler.ts +0 -224
  239. package/src/settings/index.ts +0 -50
package/src/TypeSystem.ts CHANGED
@@ -23,33 +23,26 @@ import {
23
23
  ArrayReturnType,
24
24
  DocsetEntry,
25
25
  FilterEntry,
26
- MetafieldDefinitionMap,
27
- MetafieldDefinition,
28
26
  ObjectEntry,
29
27
  ReturnType,
30
28
  SourceCodeType,
31
- ThemeDocset,
29
+ PlatformOSDocset,
32
30
  isError,
33
31
  parseJSON,
34
32
  path,
35
- FETCHED_METAFIELD_CATEGORIES,
36
33
  BasicParamTypes,
37
34
  getValidParamTypes,
38
35
  parseParamType,
39
36
  } from '@platformos/platformos-check-common';
40
- import {
41
- GetThemeSettingsSchemaForURI,
42
- InputSetting,
43
- isInputSetting,
44
- isSettingsCategory,
45
- } from './settings';
46
37
  import { findLast, memo } from './utils';
47
38
  import { visit } from '@platformos/platformos-check-common';
48
39
  import {
49
40
  PropertyShape,
50
41
  inferShapeFromJSONString,
42
+ inferShapeFromJsonLiteral,
51
43
  inferShapeFromGraphQL,
52
44
  lookupPropertyPath,
45
+ mergeShapes,
53
46
  shapeToTypeString,
54
47
  shapeToDetailString,
55
48
  } from './PropertyShapeInference';
@@ -61,17 +54,15 @@ export class TypeSystem {
61
54
  private graphqlSchemaLoaded = false;
62
55
 
63
56
  constructor(
64
- private readonly themeDocset: ThemeDocset,
65
- private readonly getThemeSettingsSchemaForURI: GetThemeSettingsSchemaForURI,
66
- private readonly getMetafieldDefinitions: (rootUri: string) => Promise<MetafieldDefinitionMap>,
57
+ private readonly platformosDocset: PlatformOSDocset,
67
58
  private readonly fs?: AbstractFileSystem,
68
59
  private readonly documentsLocator?: DocumentsLocator,
69
- private readonly findThemeRootURI?: (uri: string) => Promise<string | null>,
60
+ private readonly findAppRootURI?: (uri: string) => Promise<string | null>,
70
61
  ) {}
71
62
 
72
63
  private async getGraphQLSchema(): Promise<string | undefined> {
73
64
  if (!this.graphqlSchemaLoaded) {
74
- this.graphqlSchemaCache = (await this.themeDocset.graphQL()) ?? undefined;
65
+ this.graphqlSchemaCache = (await this.platformosDocset.graphQL()) ?? undefined;
75
66
  this.graphqlSchemaLoaded = true;
76
67
  }
77
68
  return this.graphqlSchemaCache;
@@ -125,174 +116,15 @@ export class TypeSystem {
125
116
  });
126
117
  }
127
118
 
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
119
  /**
152
120
  * An indexed representation of objects.json by name
153
121
  *
154
122
  * e.g. objectMap['product'] returns the product ObjectEntry.
155
123
  */
156
124
  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;
125
+ return this._objectMap();
229
126
  };
230
127
 
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
128
  // This is the big one we reuse (memoized)
297
129
  private _objectMap = memo(async (): Promise<ObjectMap> => {
298
130
  const entries = await this.objectEntries();
@@ -312,20 +144,20 @@ export class TypeSystem {
312
144
  });
313
145
 
314
146
  public filterEntries = memo(async () => {
315
- return this.themeDocset.filters();
147
+ return this.platformosDocset.filters();
316
148
  });
317
149
 
318
150
  public objectEntries = memo(async () => {
319
- return this.themeDocset.objects();
151
+ return this.platformosDocset.objects();
320
152
  });
321
153
 
322
154
  private async symbolsTable(partialAst: LiquidHtmlNode, uri: string): Promise<SymbolsTable> {
323
155
  const [seedSymbolsTable, liquidDrops, graphqlSchema, rootUri, objectMap, filtersMap] =
324
156
  await Promise.all([
325
157
  this.seedSymbolsTable(uri),
326
- this.themeDocset.liquidDrops(),
158
+ this.platformosDocset.liquidDrops(),
327
159
  this.getGraphQLSchema(),
328
- this.findThemeRootURI?.(uri) ?? null,
160
+ this.findAppRootURI?.(uri) ?? null,
329
161
  this.objectMap(uri, partialAst),
330
162
  this.filtersMap(),
331
163
  ]);
@@ -382,36 +214,10 @@ export class TypeSystem {
382
214
  };
383
215
  }
384
216
 
385
- const SECTION_FILE_REGEX = /sections[\/\\][^.\\\/]*\.liquid$/;
386
- const BLOCK_FILE_REGEX = /blocks[\/\\][^.\\\/]*\.liquid$/;
387
217
  const PARTIAL_FILE_REGEX = /(views[\/\\]partials[\/\\]|[\/\\]lib[\/\\])[^.]*\.liquid$/;
388
- const LAYOUT_FILE_REGEX = /layout[\/\\]checkout\.liquid$/;
389
218
 
390
219
  function getContextualEntries(uri: string): string[] {
391
220
  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
221
  if (PARTIAL_FILE_REGEX.test(normalizedUri)) {
416
222
  return ['app'];
417
223
  }
@@ -574,51 +380,202 @@ async function buildSymbolsTable(
574
380
  const typeRanges = await visit<SourceCodeType.LiquidHtml, TypeRange | TypeRange[]>(partialAst, {
575
381
  // {% assign x = foo.x | filter %}
576
382
  // {% assign x = '{"a": 1}' | parse_json %}
383
+ // {% assign x = {a: 1, b: "hello"} %}
384
+ // {% assign x["key"] = value %}
385
+ // {% assign arr << item %}
577
386
  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
- );
387
+ const expression = node.value.expression;
388
+ let valueShape: PropertyShape | undefined;
389
+
390
+ // Resolver for variable references inside JSON literals
391
+ const resolveExpr = (expr: LiquidExpression): PropertyShape | undefined => {
392
+ if (expr.type !== NodeTypes.VariableLookup || !expr.name) return undefined;
393
+
394
+ // Look up the variable's shape from already-processed assignments
395
+ const shapes = variableShapes.get(expr.name);
396
+ const shapeEntry = shapes
397
+ ? findLastApplicableShape(shapes, node.position.start)
398
+ : undefined;
399
+ let shape = shapeEntry?.shape;
400
+
401
+ // Fall back to seedSymbolsTable
402
+ if (!shape && seedSymbolsTable[expr.name]) {
403
+ for (const tr of seedSymbolsTable[expr.name]) {
404
+ if (tr.range[0] < node.position.start) {
405
+ if (typeof tr.type !== 'string' && tr.type.kind === 'shape') {
406
+ shape = tr.type.shape;
407
+ } else if (typeof tr.type === 'string' || tr.type.kind === 'array') {
408
+ shape = resolvedTypeToShape(tr.type);
409
+ }
410
+ }
411
+ }
412
+ }
582
413
 
583
- if (hasParseJsonFilter) {
584
- let jsonString: string | undefined;
414
+ if (!shape) return undefined;
585
415
 
586
- // Check if expression is a direct JSON string
587
- if (node.value.expression.type === NodeTypes.String) {
588
- jsonString = node.value.expression.value;
416
+ // Resolve lookups (e.g. a.x or a["key"])
417
+ for (const lookup of expr.lookups) {
418
+ if (shape.kind === 'object' && lookup.type === NodeTypes.String && shape.properties) {
419
+ const prop = shape.properties.get(lookup.value);
420
+ if (prop) {
421
+ shape = prop;
422
+ } else {
423
+ return undefined;
424
+ }
425
+ } else if (shape.kind === 'array') {
426
+ if (
427
+ lookup.type === NodeTypes.Number ||
428
+ (lookup.type === NodeTypes.String &&
429
+ (lookup.value === 'first' || lookup.value === 'last'))
430
+ ) {
431
+ shape = shape.itemShape;
432
+ if (!shape) return undefined;
433
+ } else {
434
+ return undefined;
435
+ }
436
+ } else {
437
+ return undefined;
438
+ }
589
439
  }
590
440
 
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;
441
+ return shape;
442
+ };
443
+
444
+ // Case 1: JSON literal expression
445
+ if (
446
+ expression.type === NodeTypes.JsonHashLiteral ||
447
+ expression.type === NodeTypes.JsonArrayLiteral
448
+ ) {
449
+ valueShape = inferShapeFromJsonLiteral(expression, resolveExpr);
450
+ }
451
+
452
+ // Case 2: parse_json / to_hash filter on a string
453
+ if (!valueShape) {
454
+ const hasParseJsonFilter = node.value.filters?.some(
455
+ (f: { name: string }) => f.name === 'parse_json' || f.name === 'to_hash',
456
+ );
457
+ if (hasParseJsonFilter) {
458
+ let jsonString: string | undefined;
459
+ if (expression.type === NodeTypes.String) {
460
+ jsonString = expression.value;
461
+ }
462
+ if (!jsonString && node.value.filters) {
463
+ const defaultFilter = node.value.filters.find(
464
+ (f: { name: string }) => f.name === 'default',
465
+ );
466
+ if (
467
+ defaultFilter &&
468
+ defaultFilter.args &&
469
+ defaultFilter.args.length > 0 &&
470
+ defaultFilter.args[0].type === NodeTypes.String
471
+ ) {
472
+ jsonString = defaultFilter.args[0].value;
600
473
  }
601
474
  }
475
+ if (jsonString) {
476
+ valueShape = inferShapeFromJSONString(jsonString) ?? undefined;
477
+ }
602
478
  }
479
+ }
603
480
 
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 });
481
+ // Case 3: Infer primitive shape for << and LHS lookup scenarios
482
+ if (!valueShape && ((node.lookups && node.lookups.length > 0) || node.operator === '<<')) {
483
+ if (expression.type === NodeTypes.String) {
484
+ valueShape = { kind: 'primitive', primitiveType: 'string' };
485
+ } else if (expression.type === NodeTypes.Number) {
486
+ valueShape = { kind: 'primitive', primitiveType: 'number' };
487
+ } else if (expression.type === NodeTypes.LiquidLiteral) {
488
+ if (expression.value === null) {
489
+ valueShape = { kind: 'primitive', primitiveType: 'null' };
490
+ } else if (typeof expression.value === 'boolean') {
491
+ valueShape = { kind: 'primitive', primitiveType: 'boolean' };
492
+ }
493
+ }
494
+ }
612
495
 
613
- return {
614
- identifier: node.name,
615
- type: shapeType(shape),
616
- range: [node.position.end],
617
- };
496
+ // Handle lookups on the LHS (assign x["key"] = value)
497
+ if (node.lookups && node.lookups.length > 0) {
498
+ const lookupPath = getAssignLookupPath(node.lookups);
499
+ if (lookupPath && lookupPath.length > 0) {
500
+ const existingShapes = variableShapes.get(node.name) || [];
501
+ const existingShapeEntry = findLastApplicableShape(existingShapes, node.position.start);
502
+
503
+ let baseShape: PropertyShape;
504
+ if (existingShapeEntry) {
505
+ baseShape = existingShapeEntry.shape;
506
+ } else {
507
+ let existingType: PseudoType | ArrayType | ShapeType | UnionType | undefined;
508
+ if (seedSymbolsTable[node.name]) {
509
+ for (const tr of seedSymbolsTable[node.name]) {
510
+ if (tr.range[0] < node.position.start) {
511
+ if (typeof tr.type !== 'string' && tr.type.kind === 'shape') {
512
+ existingType = tr.type;
513
+ }
514
+ }
515
+ }
516
+ }
517
+ baseShape =
518
+ existingType && isShapeType(existingType)
519
+ ? existingType.shape
520
+ : { kind: 'object', properties: new Map() };
618
521
  }
522
+
523
+ const newShape = mergeNestedPropertyIntoShape(
524
+ baseShape,
525
+ lookupPath,
526
+ valueShape ?? { kind: 'primitive' },
527
+ );
528
+
529
+ if (!variableShapes.has(node.name)) variableShapes.set(node.name, []);
530
+ variableShapes.get(node.name)!.push({ shape: newShape, rangeEnd: node.position.end });
531
+
532
+ return {
533
+ identifier: node.name,
534
+ type: shapeType(newShape),
535
+ range: [node.position.end],
536
+ };
537
+ }
538
+ }
539
+
540
+ // Handle << operator (array append)
541
+ if (node.operator === '<<') {
542
+ const itemShape: PropertyShape = valueShape ?? { kind: 'primitive' };
543
+ const existingShapes = variableShapes.get(node.name) || [];
544
+ const existingShapeEntry = findLastApplicableShape(existingShapes, node.position.start);
545
+
546
+ let arrayShape: PropertyShape;
547
+ if (existingShapeEntry?.shape.kind === 'array') {
548
+ const existing = existingShapeEntry.shape.itemShape;
549
+ arrayShape = {
550
+ kind: 'array',
551
+ itemShape: existing ? mergeShapes(existing, itemShape) : itemShape,
552
+ };
553
+ } else {
554
+ arrayShape = { kind: 'array', itemShape };
619
555
  }
556
+
557
+ if (!variableShapes.has(node.name)) variableShapes.set(node.name, []);
558
+ variableShapes.get(node.name)!.push({ shape: arrayShape, rangeEnd: node.position.end });
559
+
560
+ return {
561
+ identifier: node.name,
562
+ type: shapeType(arrayShape),
563
+ range: [node.position.end],
564
+ };
620
565
  }
621
566
 
567
+ // Simple assignment with shape (JSON literal or parse_json)
568
+ if (valueShape) {
569
+ if (!variableShapes.has(node.name)) variableShapes.set(node.name, []);
570
+ variableShapes.get(node.name)!.push({ shape: valueShape, rangeEnd: node.position.end });
571
+ return {
572
+ identifier: node.name,
573
+ type: shapeType(valueShape),
574
+ range: [node.position.end],
575
+ };
576
+ }
577
+
578
+ // Default: lazy variable type
622
579
  return {
623
580
  identifier: node.name,
624
581
  type: lazyVariable(node.value, node.position.start),
@@ -657,12 +614,6 @@ async function buildSymbolsTable(
657
614
  type: String,
658
615
  range: [node.position.end],
659
616
  };
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
617
  } else if (['for', 'tablerow'].includes(node.name)) {
667
618
  return {
668
619
  identifier: node.name + 'loop',
@@ -1022,6 +973,16 @@ function inferType(
1022
973
  return arrayType('number');
1023
974
  }
1024
975
 
976
+ // JSON literal expressions: {key: val} or [1, 2, 3]
977
+ case NodeTypes.JsonHashLiteral:
978
+ case NodeTypes.JsonArrayLiteral: {
979
+ const resolver = (expr: LiquidExpression): PropertyShape | undefined => {
980
+ const type = inferType(expr, symbolsTable, objectMap, filtersMap);
981
+ return resolvedTypeToShape(type);
982
+ };
983
+ return shapeType(inferShapeFromJsonLiteral(thing, resolver));
984
+ }
985
+
1025
986
  // The type of the assign markup is the type of the right hand side.
1026
987
  // {% assign x = y.property | filter1 | filter2 %}
1027
988
  case NodeTypes.AssignMarkup: {
@@ -1346,6 +1307,36 @@ function shapeToType(shape: PropertyShape): PseudoType | ArrayType | ShapeType {
1346
1307
  return Untyped;
1347
1308
  }
1348
1309
 
1310
+ /**
1311
+ * Convert a resolved type back to a PropertyShape (inverse of shapeToType).
1312
+ * Used when embedding resolved variable types into JSON literal shapes.
1313
+ */
1314
+ function resolvedTypeToShape(
1315
+ type: PseudoType | ArrayType | ShapeType | UnionType,
1316
+ ): PropertyShape | undefined {
1317
+ if (typeof type === 'string') {
1318
+ switch (type) {
1319
+ case 'string':
1320
+ return { kind: 'primitive', primitiveType: 'string' };
1321
+ case 'number':
1322
+ return { kind: 'primitive', primitiveType: 'number' };
1323
+ case 'boolean':
1324
+ return { kind: 'primitive', primitiveType: 'boolean' };
1325
+ case Untyped:
1326
+ case Unknown:
1327
+ return undefined;
1328
+ default:
1329
+ return { kind: 'primitive' };
1330
+ }
1331
+ }
1332
+ if (isShapeType(type)) return type.shape;
1333
+ if (isArrayType(type)) {
1334
+ const itemShape = resolvedTypeToShape(type.valueType);
1335
+ return { kind: 'array', itemShape };
1336
+ }
1337
+ return undefined;
1338
+ }
1339
+
1349
1340
  function inferPseudoTypePropertyType(
1350
1341
  curr: PseudoType, // settings
1351
1342
  lookup: LiquidExpression,
@@ -1656,6 +1647,24 @@ export function typeToDisplayString(type: PseudoType | ArrayType | ShapeType | U
1656
1647
  return 'unknown';
1657
1648
  }
1658
1649
 
1650
+ /**
1651
+ * Extract the lookup path from assign lookups.
1652
+ * For {% assign a["key1"]["key2"] = value %}, returns ['key1', 'key2']
1653
+ */
1654
+ function getAssignLookupPath(lookups: LiquidExpression[]): string[] | undefined {
1655
+ const path: string[] = [];
1656
+ for (const lookup of lookups) {
1657
+ if (lookup.type === NodeTypes.String) {
1658
+ path.push(lookup.value);
1659
+ } else if (lookup.type === NodeTypes.Number) {
1660
+ path.push(`${lookup.value}`);
1661
+ } else {
1662
+ return undefined;
1663
+ }
1664
+ }
1665
+ return path.length > 0 ? path : undefined;
1666
+ }
1667
+
1659
1668
  /**
1660
1669
  * Extract the lookup path from a hash_assign target.
1661
1670
  * For {% hash_assign a['key1']['key2'] = value %}, returns ['key1', 'key2']
@@ -1731,218 +1740,3 @@ function findLastApplicableShape(
1731
1740
  }
1732
1741
  return result;
1733
1742
  }
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
- }