@platformos/platformos-language-server-common 0.0.6 → 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 (247) hide show
  1. package/CHANGELOG.md +20 -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/completions/CompletionsProvider.d.ts +6 -10
  9. package/dist/completions/CompletionsProvider.js +6 -9
  10. package/dist/completions/CompletionsProvider.js.map +1 -1
  11. package/dist/completions/params/LiquidCompletionParams.js +4 -16
  12. package/dist/completions/params/LiquidCompletionParams.js.map +1 -1
  13. package/dist/completions/providers/ContentForCompletionProvider.js +2 -4
  14. package/dist/completions/providers/ContentForCompletionProvider.js.map +1 -1
  15. package/dist/completions/providers/FilterCompletionProvider.js.map +1 -1
  16. package/dist/completions/providers/FilterNamedParameterCompletionProvider.d.ts +3 -3
  17. package/dist/completions/providers/FilterNamedParameterCompletionProvider.js +6 -6
  18. package/dist/completions/providers/FilterNamedParameterCompletionProvider.js.map +1 -1
  19. package/dist/completions/providers/LiquidDocParamTypeCompletionProvider.d.ts +3 -3
  20. package/dist/completions/providers/LiquidDocParamTypeCompletionProvider.js +3 -3
  21. package/dist/completions/providers/LiquidDocParamTypeCompletionProvider.js.map +1 -1
  22. package/dist/completions/providers/LiquidTagsCompletionProvider.d.ts +3 -3
  23. package/dist/completions/providers/LiquidTagsCompletionProvider.js +3 -3
  24. package/dist/completions/providers/LiquidTagsCompletionProvider.js.map +1 -1
  25. package/dist/completions/providers/RenderPartialParameterCompletionProvider.js +1 -1
  26. package/dist/completions/providers/RenderPartialParameterCompletionProvider.js.map +1 -1
  27. package/dist/completions/providers/TranslationCompletionProvider.js +1 -1
  28. package/dist/completions/providers/TranslationCompletionProvider.js.map +1 -1
  29. package/dist/completions/providers/index.d.ts +0 -3
  30. package/dist/completions/providers/index.js +1 -7
  31. package/dist/completions/providers/index.js.map +1 -1
  32. package/dist/css/CSSLanguageService.d.ts +19 -5
  33. package/dist/css/CSSLanguageService.js +77 -63
  34. package/dist/css/CSSLanguageService.js.map +1 -1
  35. package/dist/definitions/DefinitionProvider.d.ts +1 -1
  36. package/dist/definitions/DefinitionProvider.js +1 -3
  37. package/dist/definitions/DefinitionProvider.js.map +1 -1
  38. package/dist/diagnostics/offenseToDiagnostic.js +1 -1
  39. package/dist/diagnostics/offenseToDiagnostic.js.map +1 -1
  40. package/dist/diagnostics/runChecks.d.ts +3 -5
  41. package/dist/diagnostics/runChecks.js +12 -64
  42. package/dist/diagnostics/runChecks.js.map +1 -1
  43. package/dist/docset/MarkdownRenderer.js +1 -1
  44. package/dist/docset/MarkdownRenderer.js.map +1 -1
  45. package/dist/documentHighlights/providers/HtmlTagNameDocumentHighlightsProvider.d.ts +1 -1
  46. package/dist/documentLinks/DocumentLinksProvider.d.ts +3 -3
  47. package/dist/documentLinks/DocumentLinksProvider.js +3 -3
  48. package/dist/documentLinks/DocumentLinksProvider.js.map +1 -1
  49. package/dist/documents/DocumentManager.d.ts +4 -5
  50. package/dist/documents/DocumentManager.js +12 -11
  51. package/dist/documents/DocumentManager.js.map +1 -1
  52. package/dist/documents/types.d.ts +16 -3
  53. package/dist/documents/types.js +3 -3
  54. package/dist/documents/types.js.map +1 -1
  55. package/dist/formatting/OnTypeFormattingProvider.d.ts +1 -1
  56. package/dist/formatting/providers/HtmlElementAutoclosingOnTypeFormattingProvider.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/linkedEditingRanges/providers/HtmlTagNameLinkedRangesProvider.d.ts +1 -1
  92. package/dist/progress.js.map +1 -1
  93. package/dist/rename/RenameProvider.d.ts +2 -2
  94. package/dist/rename/RenameProvider.js +2 -2
  95. package/dist/rename/RenameProvider.js.map +1 -1
  96. package/dist/rename/providers/LiquidVariableRenameProvider.d.ts +3 -3
  97. package/dist/rename/providers/LiquidVariableRenameProvider.js +4 -4
  98. package/dist/rename/providers/LiquidVariableRenameProvider.js.map +1 -1
  99. package/dist/renamed/RenameHandler.d.ts +2 -3
  100. package/dist/renamed/RenameHandler.js +3 -8
  101. package/dist/renamed/RenameHandler.js.map +1 -1
  102. package/dist/renamed/handlers/AssetRenameHandler.d.ts +3 -3
  103. package/dist/renamed/handlers/AssetRenameHandler.js +5 -5
  104. package/dist/renamed/handlers/AssetRenameHandler.js.map +1 -1
  105. package/dist/renamed/handlers/PartialRenameHandler.d.ts +3 -3
  106. package/dist/renamed/handlers/PartialRenameHandler.js +5 -5
  107. package/dist/renamed/handlers/PartialRenameHandler.js.map +1 -1
  108. package/dist/renamed/handlers/utils.d.ts +1 -1
  109. package/dist/server/AppGraphManager.d.ts +32 -0
  110. package/dist/server/AppGraphManager.js +155 -0
  111. package/dist/server/AppGraphManager.js.map +1 -0
  112. package/dist/server/Configuration.js.map +1 -1
  113. package/dist/server/startServer.d.ts +2 -2
  114. package/dist/server/startServer.js +62 -164
  115. package/dist/server/startServer.js.map +1 -1
  116. package/dist/tsconfig.tsbuildinfo +1 -1
  117. package/dist/types.d.ts +33 -54
  118. package/dist/types.js +21 -26
  119. package/dist/types.js.map +1 -1
  120. package/dist/utils/liquidDoc.js +1 -1
  121. package/dist/utils/liquidDoc.js.map +1 -1
  122. package/dist/utils/uri.d.ts +0 -8
  123. package/dist/utils/uri.js +1 -17
  124. package/dist/utils/uri.js.map +1 -1
  125. package/package.json +9 -9
  126. package/src/PropertyShapeInference.ts +76 -1
  127. package/src/TypeSystem.spec.ts +187 -452
  128. package/src/TypeSystem.ts +253 -459
  129. package/src/completions/CompletionsProvider.ts +13 -34
  130. package/src/completions/params/LiquidCompletionParams.spec.ts +0 -9
  131. package/src/completions/params/LiquidCompletionParams.ts +4 -14
  132. package/src/completions/params/fix.spec.ts +0 -3
  133. package/src/completions/providers/FilterCompletionProvider.spec.ts +2 -8
  134. package/src/completions/providers/FilterCompletionProvider.ts +6 -6
  135. package/src/completions/providers/FilterNamedParameterCompletionProvider.spec.ts +1 -5
  136. package/src/completions/providers/FilterNamedParameterCompletionProvider.ts +6 -6
  137. package/src/completions/providers/HtmlAttributeCompletionProvider.spec.ts +1 -4
  138. package/src/completions/providers/HtmlAttributeValueCompletionProvider.spec.ts +1 -4
  139. package/src/completions/providers/HtmlTagCompletionProvider.spec.ts +1 -4
  140. package/src/completions/providers/LiquidDocParamTypeCompletionProvider.spec.ts +1 -28
  141. package/src/completions/providers/LiquidDocParamTypeCompletionProvider.ts +3 -3
  142. package/src/completions/providers/LiquidDocTagCompletionProvider.spec.ts +1 -26
  143. package/src/completions/providers/LiquidTagsCompletionProvider.spec.ts +2 -16
  144. package/src/completions/providers/LiquidTagsCompletionProvider.ts +3 -3
  145. package/src/completions/providers/ObjectAttributeCompletionProvider.spec.ts +2 -31
  146. package/src/completions/providers/ObjectCompletionProvider.spec.ts +34 -123
  147. package/src/completions/providers/PartialCompletionProvider.spec.ts +4 -13
  148. package/src/completions/providers/RenderPartialParameterCompletionProvider.spec.ts +3 -5
  149. package/src/completions/providers/RenderPartialParameterCompletionProvider.ts +0 -1
  150. package/src/completions/providers/TranslationCompletionProvider.spec.ts +1 -4
  151. package/src/completions/providers/TranslationCompletionProvider.ts +1 -1
  152. package/src/completions/providers/index.ts +0 -3
  153. package/src/css/CSSLanguageService.ts +97 -81
  154. package/src/definitions/DefinitionProvider.ts +0 -6
  155. package/src/definitions/providers/TranslationStringDefinitionProvider.spec.ts +1 -5
  156. package/src/diagnostics/offenseToDiagnostic.ts +1 -1
  157. package/src/diagnostics/runChecks.spec.ts +16 -24
  158. package/src/diagnostics/runChecks.ts +17 -91
  159. package/src/docset/MarkdownRenderer.ts +1 -1
  160. package/src/documentLinks/DocumentLinksProvider.ts +3 -3
  161. package/src/documents/DocumentManager.spec.ts +12 -97
  162. package/src/documents/DocumentManager.ts +13 -14
  163. package/src/documents/types.ts +18 -9
  164. package/src/formatting/providers/HtmlElementAutoclosingOnTypeFormattingProvider.ts +1 -3
  165. package/src/hover/HoverProvider.ts +9 -21
  166. package/src/hover/providers/HtmlAttributeHoverProvider.spec.ts +1 -3
  167. package/src/hover/providers/HtmlAttributeValueHoverProvider.spec.ts +1 -3
  168. package/src/hover/providers/HtmlTagHoverProvider.spec.ts +1 -3
  169. package/src/hover/providers/LiquidDocTagHoverProvider.spec.ts +0 -3
  170. package/src/hover/providers/LiquidFilterArgumentHoverProvider.spec.ts +0 -3
  171. package/src/hover/providers/LiquidFilterArgumentHoverProvider.ts +3 -3
  172. package/src/hover/providers/LiquidFilterHoverProvider.spec.ts +0 -3
  173. package/src/hover/providers/LiquidFilterHoverProvider.ts +3 -3
  174. package/src/hover/providers/LiquidObjectAttributeHoverProvider.spec.ts +1 -3
  175. package/src/hover/providers/LiquidObjectHoverProvider.spec.ts +46 -129
  176. package/src/hover/providers/LiquidTagHoverProvider.spec.ts +0 -3
  177. package/src/hover/providers/LiquidTagHoverProvider.ts +3 -3
  178. package/src/hover/providers/RenderPartialHoverProvider.spec.ts +1 -4
  179. package/src/hover/providers/RenderPartialHoverProvider.ts +1 -5
  180. package/src/hover/providers/RenderPartialParameterHoverProvider.spec.ts +1 -4
  181. package/src/hover/providers/RenderPartialParameterHoverProvider.ts +0 -1
  182. package/src/hover/providers/TranslationHoverProvider.spec.ts +1 -4
  183. package/src/hover/providers/TranslationHoverProvider.ts +3 -3
  184. package/src/index.ts +2 -5
  185. package/src/internal-types.ts +1 -1
  186. package/src/json/JSONContributions.ts +4 -61
  187. package/src/json/JSONLanguageService.ts +19 -117
  188. package/src/json/test/test-helpers.ts +4 -35
  189. package/src/json/utils.ts +0 -27
  190. package/src/progress.ts +4 -1
  191. package/src/rename/RenameProvider.ts +3 -3
  192. package/src/rename/providers/LiquidVariableRenameProvider.spec.ts +4 -4
  193. package/src/rename/providers/LiquidVariableRenameProvider.ts +4 -4
  194. package/src/renamed/RenameHandler.ts +4 -9
  195. package/src/renamed/handlers/AssetRenameHandler.spec.ts +3 -3
  196. package/src/renamed/handlers/AssetRenameHandler.ts +5 -5
  197. package/src/renamed/handlers/PartialRenameHandler.spec.ts +2 -2
  198. package/src/renamed/handlers/PartialRenameHandler.ts +5 -5
  199. package/src/renamed/handlers/utils.ts +1 -1
  200. package/src/server/{ThemeGraphManager.ts → AppGraphManager.ts} +21 -90
  201. package/src/server/Configuration.ts +4 -1
  202. package/src/server/startServer.spec.ts +7 -9
  203. package/src/server/startServer.ts +65 -217
  204. package/src/test/CompletionItemsAssertion.spec.ts +1 -4
  205. package/src/types.ts +33 -63
  206. package/src/utils/liquidDoc.ts +1 -1
  207. package/src/utils/uri.ts +0 -14
  208. package/src/completions/providers/ContentForBlockTypeCompletionProvider.spec.ts +0 -41
  209. package/src/completions/providers/ContentForBlockTypeCompletionProvider.ts +0 -42
  210. package/src/completions/providers/ContentForCompletionProvider.spec.ts +0 -96
  211. package/src/completions/providers/ContentForCompletionProvider.ts +0 -113
  212. package/src/completions/providers/ContentForParameterCompletionProvider.spec.ts +0 -362
  213. package/src/completions/providers/ContentForParameterCompletionProvider.ts +0 -187
  214. package/src/completions/providers/data/contentForParameterCompletionOptions.ts +0 -9
  215. package/src/css/CSSLanguageService.spec.ts +0 -161
  216. package/src/css/test/test-helpers.ts +0 -30
  217. package/src/definitions/providers/SchemaTranslationStringDefinitionProvider.spec.ts +0 -96
  218. package/src/definitions/providers/SchemaTranslationStringDefinitionProvider.ts +0 -82
  219. package/src/hover/providers/ContentForArgumentHoverProvider.spec.ts +0 -76
  220. package/src/hover/providers/ContentForArgumentHoverProvider.ts +0 -56
  221. package/src/hover/providers/ContentForTypeHoverProvider.spec.ts +0 -91
  222. package/src/hover/providers/ContentForTypeHoverProvider.ts +0 -42
  223. package/src/json/JSONLanguageService.spec.ts +0 -424
  224. package/src/json/completions/providers/BlockSettingsPropertyCompletionProvider.spec.ts +0 -163
  225. package/src/json/completions/providers/BlockSettingsPropertyCompletionProvider.ts +0 -121
  226. package/src/json/completions/providers/BlockTypeCompletionProvider.spec.ts +0 -137
  227. package/src/json/completions/providers/BlockTypeCompletionProvider.ts +0 -108
  228. package/src/json/completions/providers/ReferencedBlockTypeCompletionProvider.spec.ts +0 -132
  229. package/src/json/completions/providers/ReferencedBlockTypeCompletionProvider.ts +0 -120
  230. package/src/json/completions/providers/SchemaTranslationCompletionProvider.ts +0 -51
  231. package/src/json/completions/providers/SettingsPropertyCompletionProvider.spec.ts +0 -211
  232. package/src/json/completions/providers/SettingsPropertyCompletionProvider.ts +0 -75
  233. package/src/json/documentLinks/DocumentLinksProvider.spec.ts +0 -223
  234. package/src/json/documentLinks/DocumentLinksProvider.ts +0 -61
  235. package/src/json/hover/providers/BlockSettingsHoverProvider.spec.ts +0 -292
  236. package/src/json/hover/providers/BlockSettingsHoverProvider.ts +0 -99
  237. package/src/json/hover/providers/SchemaTranslationHoverProvider.ts +0 -35
  238. package/src/json/hover/providers/SettingsHoverProvider.spec.ts +0 -139
  239. package/src/json/hover/providers/SettingsHoverProvider.ts +0 -79
  240. package/src/json/schemaSettings.spec.ts +0 -103
  241. package/src/json/schemaSettings.ts +0 -53
  242. package/src/plugins/css.ts +0 -12
  243. package/src/renamed/handlers/BlockRenameHandler.spec.ts +0 -399
  244. package/src/renamed/handlers/BlockRenameHandler.ts +0 -402
  245. package/src/renamed/handlers/SectionRenameHandler.spec.ts +0 -321
  246. package/src/renamed/handlers/SectionRenameHandler.ts +0 -224
  247. package/src/settings/index.ts +0 -50
@@ -7,20 +7,17 @@ import {
7
7
  toLiquidHtmlAST,
8
8
  } from '@platformos/liquid-html-parser';
9
9
  import {
10
- MetafieldDefinitionMap,
11
10
  path as pathUtils,
12
11
  BasicParamTypes,
13
12
  ObjectEntry,
14
13
  } from '@platformos/platformos-check-common';
15
14
  import { assert, beforeEach, describe, expect, it, vi } from 'vitest';
16
15
  import { URI } from 'vscode-uri';
17
- import { SettingsSchemaJSONFile } from './settings';
18
16
  import { ArrayType, ShapeType, TypeSystem, UnionType } from './TypeSystem';
19
17
  import { isLiquidVariableOutput, isNamedLiquidTag } from './utils';
20
18
 
21
19
  describe('Module: TypeSystem', () => {
22
20
  let typeSystem: TypeSystem;
23
- let settingsProvider: any;
24
21
  const literalContexts = [
25
22
  { value: `10`, type: 'number' },
26
23
  { value: `'string'`, type: 'string' },
@@ -28,53 +25,62 @@ describe('Module: TypeSystem', () => {
28
25
  // { value: `null`, type: 'untyped' },
29
26
  ];
30
27
 
31
- beforeEach(() => {
28
+ beforeEach(async () => {
32
29
  const _objects: ObjectEntry[] = [
33
30
  {
34
- name: 'all_products',
35
- return_type: [{ type: 'array', array_value: 'product' }],
31
+ name: 'context',
32
+ access: { global: true, parents: [], template: [] },
33
+ return_type: [],
34
+ properties: [
35
+ {
36
+ name: 'models',
37
+ description: 'a list of user-defined data models (e.g. from GraphQL)',
38
+ return_type: [{ type: 'array', array_value: 'model' }],
39
+ },
40
+ {
41
+ name: 'current_user',
42
+ description: 'the current user',
43
+ return_type: [{ type: 'current_user', name: '' }],
44
+ },
45
+ ],
36
46
  },
37
47
  {
38
- name: 'product',
39
- access: {
40
- global: true,
41
- parents: [],
42
- template: [],
43
- },
44
- return_type: [],
48
+ // 'model' represents a generic user-defined data model in platformOS
49
+ // (e.g. a record returned from a GraphQL query)
50
+ name: 'model',
45
51
  properties: [
46
52
  {
47
- name: 'featured_image',
48
- description: 'ze best image for ze product',
53
+ name: 'thumbnail',
54
+ description: 'a thumbnail image',
49
55
  return_type: [{ type: 'image', name: '' }],
50
56
  },
51
57
  {
52
58
  name: 'images',
53
- description: 'all images for ze product',
59
+ description: 'all images for the model',
54
60
  return_type: [{ type: 'array', array_value: 'image' }],
55
61
  },
56
62
  {
57
63
  name: 'title',
58
- description: 'the title of the product',
64
+ description: 'the title of the model',
59
65
  return_type: [{ type: 'string', name: '' }],
60
66
  },
61
67
  {
62
- name: 'metafields',
68
+ name: 'metadata',
63
69
  return_type: [{ type: 'untyped', name: '' }],
64
70
  },
65
71
  ],
66
72
  },
67
73
  {
68
- name: 'metafield',
74
+ name: 'current_user',
69
75
  properties: [
70
76
  {
71
- name: 'type',
72
- description: 'the type of the metafield',
77
+ name: 'name',
78
+ description: 'the name of the user',
73
79
  return_type: [{ type: 'string', name: '' }],
74
80
  },
75
81
  {
76
- name: 'value',
77
- description: 'the value of the metafield',
82
+ name: 'info',
83
+ description: 'additional info',
78
84
  return_type: [{ type: 'untyped', name: '' }],
79
85
  },
80
86
  ],
@@ -85,17 +91,7 @@ describe('Module: TypeSystem', () => {
85
91
  properties: [], // these should be populated dynamically
86
92
  },
87
93
  {
88
- name: 'predictive_search',
89
- access: { global: false, parents: [], template: [] },
90
- return_type: [],
91
- },
92
- {
93
- name: 'comment',
94
- access: { global: false, parents: [], template: [] },
95
- return_type: [],
96
- },
97
- {
98
- name: 'recommendations',
94
+ name: 'locale',
99
95
  access: { global: false, parents: [], template: [] },
100
96
  return_type: [],
101
97
  },
@@ -104,109 +100,19 @@ describe('Module: TypeSystem', () => {
104
100
  access: { global: false, parents: [], template: [] },
105
101
  return_type: [],
106
102
  },
107
- {
108
- name: 'section',
109
- access: { global: false, parents: [], template: [] },
110
- return_type: [],
111
- properties: [
112
- {
113
- name: 'settings',
114
- return_type: [{ type: 'untyped', name: '' }],
115
- },
116
- ],
117
- },
118
- {
119
- name: 'block',
120
- access: { global: false, parents: [], template: [] },
121
- return_type: [],
122
- properties: [
123
- {
124
- name: 'settings',
125
- return_type: [{ type: 'untyped', name: '' }],
126
- },
127
- ],
128
- },
129
- {
130
- name: 'locale',
131
- access: { global: false, parents: [], template: [] },
132
- return_type: [],
133
- },
134
103
  ];
135
- settingsProvider = vi.fn().mockResolvedValue([]);
136
- typeSystem = new TypeSystem(
137
- {
138
- graphQL: async () => null,
139
- tags: async () => [],
140
- objects: async () => _objects,
141
- liquidDrops: async () => _objects,
142
- filters: async () => [
143
- {
144
- name: 'size',
145
- return_type: [{ type: 'number', name: '' }],
146
- },
147
- ],
148
- systemTranslations: async () => ({}),
149
- },
150
- settingsProvider,
151
- async (_uri: string) => {
152
- return {
153
- article: [],
154
- blog: [],
155
- collection: [],
156
- company: [],
157
- company_location: [],
158
- location: [],
159
- market: [],
160
- order: [
161
- {
162
- key: 'prods',
163
- name: 'products',
164
- namespace: 'related',
165
- description: 'related products',
166
- type: {
167
- category: 'REFERENCE',
168
- name: 'list.product_reference',
169
- },
170
- },
171
- ],
172
- page: [],
173
- product: [
174
- {
175
- key: 'code',
176
- name: 'code',
177
- namespace: 'manufacturer',
178
- description: 'the code provided by the manufacturer',
179
- type: {
180
- category: 'TEXT',
181
- name: 'single_line_text_field',
182
- },
183
- },
184
- {
185
- key: 'id',
186
- name: 'id',
187
- namespace: 'manufacturer',
188
- description: 'the id provided by the manufacturer',
189
- type: {
190
- category: 'INTEGER',
191
- name: 'number_integer',
192
- },
193
- },
194
- {
195
- key: 'is_rare',
196
- name: 'is_rare',
197
- namespace: 'custom',
198
- description: 'is this product rare?',
199
- type: {
200
- category: 'BOOLEAN',
201
- name: 'boolean',
202
- },
203
- },
204
- ],
205
- variant: [],
206
- shop: [],
207
- } as MetafieldDefinitionMap;
208
- },
209
- );
104
+ typeSystem = new TypeSystem({
105
+ graphQL: async () => null,
106
+ tags: async () => [],
107
+ objects: async () => _objects,
108
+ liquidDrops: async () => _objects,
109
+ filters: async () => [
110
+ {
111
+ name: 'size',
112
+ return_type: [{ type: 'number', name: '' }],
113
+ },
114
+ ],
115
+ });
210
116
  });
211
117
 
212
118
  it('should return the type of assign markup nodes (basic test)', async () => {
@@ -240,21 +146,21 @@ describe('Module: TypeSystem', () => {
240
146
  });
241
147
 
242
148
  it('should return the type of array variables', async () => {
243
- const ast = toLiquidHtmlAST(`{% assign x = all_products %}`);
149
+ const ast = toLiquidHtmlAST(`{% assign x = context.models %}`);
244
150
  const xVariable = (ast as any).children[0].markup as AssignMarkup;
245
151
  const inferredType = await typeSystem.inferType(xVariable, ast, 'file:///file.liquid');
246
- expect(inferredType).to.eql({ kind: 'array', valueType: 'product' });
152
+ expect(inferredType).to.eql({ kind: 'array', valueType: 'model' });
247
153
  });
248
154
 
249
155
  it('should return the type of object properties', async () => {
250
- const ast = toLiquidHtmlAST(`{% assign x = all_products[0].featured_image %}`);
156
+ const ast = toLiquidHtmlAST(`{% assign x = context.models[0].thumbnail %}`);
251
157
  const xVariable = (ast as any).children[0].markup as AssignMarkup;
252
158
  const inferredType = await typeSystem.inferType(xVariable, ast, 'file:///file.liquid');
253
159
  expect(inferredType).to.equal('image');
254
160
  });
255
161
 
256
162
  it('should return the type of filtered variables', async () => {
257
- const ast = toLiquidHtmlAST(`{% assign x = product | size %}`);
163
+ const ast = toLiquidHtmlAST(`{% assign x = context | size %}`);
258
164
  const xVariable = (ast as any).children[0].markup as AssignMarkup;
259
165
  const inferredType = await typeSystem.inferType(xVariable, ast, 'file:///file.liquid');
260
166
  expect(inferredType).to.equal('number');
@@ -262,7 +168,7 @@ describe('Module: TypeSystem', () => {
262
168
 
263
169
  describe('when using string builtin methods', () => {
264
170
  it('should return number for size', async () => {
265
- const ast = toLiquidHtmlAST(`{{ product.title.size }}`);
171
+ const ast = toLiquidHtmlAST(`{{ context.current_user.name.size }}`);
266
172
  const xVariable = (ast as any).children[0].markup as LiquidVariable;
267
173
  const inferredType = await typeSystem.inferType(xVariable, ast, 'file:///file.liquid');
268
174
  expect(inferredType).to.equal('number');
@@ -270,7 +176,7 @@ describe('Module: TypeSystem', () => {
270
176
 
271
177
  ['first', 'last'].forEach((method) => {
272
178
  it(`should return string for ${method}`, async () => {
273
- const ast = toLiquidHtmlAST(`{{ product.title.${method} }}`);
179
+ const ast = toLiquidHtmlAST(`{{ context.current_user.name.${method} }}`);
274
180
  const xVariable = (ast as any).children[0].markup as LiquidVariable;
275
181
  const inferredType = await typeSystem.inferType(xVariable, ast, 'file:///file.liquid');
276
182
  expect(inferredType).to.equal('string');
@@ -280,7 +186,7 @@ describe('Module: TypeSystem', () => {
280
186
 
281
187
  describe('when using array builtin methods', () => {
282
188
  it('should return number for size', async () => {
283
- const ast = toLiquidHtmlAST(`{{ product.images.size }}`);
189
+ const ast = toLiquidHtmlAST(`{{ context.models[0].images.size }}`);
284
190
  const xVariable = (ast as any).children[0].markup as LiquidVariable;
285
191
  const inferredType = await typeSystem.inferType(xVariable, ast, 'file:///file.liquid');
286
192
  expect(inferredType).to.equal('number');
@@ -288,7 +194,7 @@ describe('Module: TypeSystem', () => {
288
194
 
289
195
  ['first', 'last'].forEach((method) => {
290
196
  it(`should return the value type of the array for ${method}`, async () => {
291
- const ast = toLiquidHtmlAST(`{{ product.images.${method} }}`);
197
+ const ast = toLiquidHtmlAST(`{{ context.models[0].images.${method} }}`);
292
198
  const xVariable = (ast as any).children[0].markup as LiquidVariable;
293
199
  const inferredType = await typeSystem.inferType(xVariable, ast, 'file:///file.liquid');
294
200
  expect(inferredType).to.equal('image');
@@ -308,7 +214,7 @@ describe('Module: TypeSystem', () => {
308
214
 
309
215
  it('should return the type of the default value lookup', async () => {
310
216
  const ast = toLiquidHtmlAST(`
311
- {% assign d = product.featured_image %}
217
+ {% assign d = context.models[0].thumbnail %}
312
218
  {% assign x = unknown | default: d %}
313
219
  `);
314
220
  const xVariable = (ast as any).children[1].markup as AssignMarkup;
@@ -318,7 +224,7 @@ describe('Module: TypeSystem', () => {
318
224
  });
319
225
 
320
226
  it('should return the type of variables in for loop', async () => {
321
- const ast = toLiquidHtmlAST(`{% for item in all_products %}{{ item }}{% endfor %}`);
227
+ const ast = toLiquidHtmlAST(`{% for item in context.models %}{{ item }}{% endfor %}`);
322
228
  const forLoop = ast.children[0];
323
229
  assert(isNamedLiquidTag(forLoop, NamedTags.for) && forLoop.children?.length === 1);
324
230
  const branch = forLoop.children[0];
@@ -328,150 +234,14 @@ describe('Module: TypeSystem', () => {
328
234
  const variable = variableOutput.markup;
329
235
 
330
236
  const inferredType = await typeSystem.inferType(variable, ast, 'file:///file.liquid');
331
- expect(inferredType).to.equal('product');
237
+ expect(inferredType).to.equal('model');
332
238
  });
333
239
 
334
- it('should patch the properties of settings when a schema is available', async () => {
335
- settingsProvider.mockResolvedValue([
336
- {
337
- name: 'category',
338
- settings: [
339
- {
340
- id: 'slide',
341
- label: 'Slide label',
342
- type: 'checkbox',
343
- },
344
- {
345
- id: 'my_font',
346
- label: 'my font',
347
- type: 'font_picker',
348
- },
349
- ],
350
- },
351
- ] as SettingsSchemaJSONFile);
352
-
353
- const contexts = [
354
- { id: 'slide', expectedType: 'boolean' },
355
- { id: 'my_font', expectedType: 'font' },
356
- ];
357
- for (const { id, expectedType } of contexts) {
358
- const ast = toLiquidHtmlAST(`{{ settings.${id} }}`);
359
- const variableOutput = ast.children[0];
360
- assert(isLiquidVariableOutput(variableOutput));
361
- const inferredType = await typeSystem.inferType(
362
- variableOutput.markup,
363
- ast,
364
- 'file:///file.liquid',
365
- );
366
- expect(inferredType).to.eql(expectedType);
367
- }
368
- });
369
-
370
- it('should support section settings in section files', async () => {
371
- const sourceCode = `
372
- {{ section.settings.my_list }}
373
- {% schema %}
374
- {
375
- "name": "section-settings-example",
376
- "tag": "section",
377
- "settings": [
378
- {
379
- "id": "my_list",
380
- "label": "t:my-setting.label",
381
- "type": "product_list"
382
- }
383
- ]
384
- }
385
- {% endschema %}
386
- `;
387
- const ast = toLiquidHtmlAST(sourceCode);
388
- const variableOutput = ast.children[0];
389
- assert(isLiquidVariableOutput(variableOutput));
390
- const inferredType = await typeSystem.inferType(
391
- variableOutput.markup,
392
- ast,
393
- 'file:///sections/my-section.liquid',
394
- );
395
- expect(inferredType).to.eql({ kind: 'array', valueType: 'product' } as ArrayType);
396
- });
397
-
398
- it('should support block settings in blocks files', async () => {
399
- const sourceCode = `
400
- {{ block.settings.my_list }}
401
- {% schema %}
402
- {
403
- "name": "section-settings-example",
404
- "tag": "section",
405
- "settings": [
406
- {
407
- "id": "my_list",
408
- "label": "t:my-setting.label",
409
- "type": "product_list"
410
- }
411
- ]
412
- }
413
- {% endschema %}
414
- `;
415
- const ast = toLiquidHtmlAST(sourceCode);
416
- const variableOutput = ast.children[0];
417
- assert(isLiquidVariableOutput(variableOutput));
418
- const inferredType = await typeSystem.inferType(
419
- variableOutput.markup,
420
- ast,
421
- 'file:///blocks/my-section.liquid',
422
- );
423
- expect(inferredType).to.eql({ kind: 'array', valueType: 'product' } as ArrayType);
424
- });
425
-
426
- // TODO
427
- it.skip('should support narrowing the type of blocks', async () => {
428
- const sourceCode = `
429
- {% for block in section.blocks %}
430
- {% case block.type %}
431
- {% when 'slide' %}
432
- {{ block.settings.image }}
433
- {% else %}
434
- {% endcase }
435
- {% if block.type == 'slide' %}
436
- {{ block.settings.image }}
437
- {% endif %}
438
- {% endfor %}
439
- {% schema %}
440
- {
441
- "name": "Slideshow",
442
- "tag": "section",
443
- "class": "slideshow",
444
- "settings": [],
445
- "blocks": [
446
- {
447
- "name": "Slide",
448
- "type": "slide",
449
- "settings": [
450
- {
451
- "type": "image_picker",
452
- "id": "image",
453
- "label": "Image"
454
- }
455
- ]
456
- }
457
- ]
458
- }
459
- {% endschema %}
460
- `;
461
- const ast = toLiquidHtmlAST(sourceCode);
462
- });
463
-
464
- it('should support path-contextual variable types', async () => {
240
+ it('should support path-contextual variable types for partials', async () => {
465
241
  let inferredType: string | ArrayType | ShapeType | UnionType;
466
242
  const contexts: [string, string][] = [
467
- ['section', 'sections/my-section.liquid'],
468
- ['comment', 'sections/main-article.liquid'],
469
- ['block', 'blocks/my-block.liquid'],
470
- ['predictive_search', 'sections/predictive-search.liquid'],
471
- ['recommendations', 'sections/recommendations.liquid'],
472
- ['app', 'blocks/recommendations.liquid'],
473
243
  ['app', 'app/views/partials/recommendations.liquid'],
474
- ['locale', 'layout/checkout.liquid'],
244
+ ['app', 'app/lib/helpers/my-helper.liquid'],
475
245
  ];
476
246
  for (const [object, path] of contexts) {
477
247
  const sourceCode = `{{ ${object} }}`;
@@ -518,16 +288,16 @@ describe('Module: TypeSystem', () => {
518
288
  const inferredType = await typeSystem.inferType(
519
289
  variableOutput.markup,
520
290
  ast,
521
- 'file:///snippets/example.liquid',
291
+ 'file:///app/views/partials/example.liquid',
522
292
  );
523
293
  expect(inferredType).to.eql(expectedType);
524
294
  });
525
295
  });
526
296
 
527
- it(`should support complex liquid doc params type: product`, async () => {
297
+ it(`should support complex liquid doc params type: current_user`, async () => {
528
298
  const sourceCode = `
529
299
  {% doc %}
530
- @param {product} data - some data
300
+ @param {current_user} data - the current user object
531
301
  {% enddoc %}
532
302
  {{ data }}
533
303
  `;
@@ -537,15 +307,15 @@ describe('Module: TypeSystem', () => {
537
307
  const inferredType = await typeSystem.inferType(
538
308
  variableOutput.markup,
539
309
  ast,
540
- 'file:///snippets/example.liquid',
310
+ 'file:///app/views/partials/example.liquid',
541
311
  );
542
- expect(inferredType).to.eql('product');
312
+ expect(inferredType).to.eql('current_user');
543
313
  });
544
314
 
545
- it(`should support array liquid doc params type: product[]`, async () => {
315
+ it(`should support array liquid doc params type: current_user[]`, async () => {
546
316
  const sourceCode = `
547
317
  {% doc %}
548
- @param {product[]} data - some data
318
+ @param {current_user[]} data - a list of users
549
319
  {% enddoc %}
550
320
  {{ data }}
551
321
  `;
@@ -555,11 +325,11 @@ describe('Module: TypeSystem', () => {
555
325
  const inferredType = await typeSystem.inferType(
556
326
  variableOutput.markup,
557
327
  ast,
558
- 'file:///snippets/example.liquid',
328
+ 'file:///app/views/partials/example.liquid',
559
329
  );
560
330
  expect(inferredType).to.eql({
561
331
  kind: 'array',
562
- valueType: 'product',
332
+ valueType: 'current_user',
563
333
  });
564
334
  });
565
335
  });
@@ -614,23 +384,7 @@ query {
614
384
  objects: async () => [],
615
385
  liquidDrops: async () => [],
616
386
  filters: async () => [],
617
- systemTranslations: async () => ({}),
618
387
  },
619
- async () => [],
620
- async () => ({
621
- article: [],
622
- blog: [],
623
- collection: [],
624
- company: [],
625
- company_location: [],
626
- location: [],
627
- market: [],
628
- order: [],
629
- page: [],
630
- product: [],
631
- variant: [],
632
- shop: [],
633
- }),
634
388
  fs,
635
389
  documentsLocator,
636
390
  async () => rootUri,
@@ -717,23 +471,7 @@ query {
717
471
  objects: async () => [],
718
472
  liquidDrops: async () => [],
719
473
  filters: async () => [],
720
- systemTranslations: async () => ({}),
721
474
  },
722
- async () => [],
723
- async () => ({
724
- article: [],
725
- blog: [],
726
- collection: [],
727
- company: [],
728
- company_location: [],
729
- location: [],
730
- market: [],
731
- order: [],
732
- page: [],
733
- product: [],
734
- variant: [],
735
- shop: [],
736
- }),
737
475
  fs,
738
476
  documentsLocator,
739
477
  async () => rootUri,
@@ -791,23 +529,7 @@ query {
791
529
  objects: async () => [],
792
530
  liquidDrops: async () => [],
793
531
  filters: async () => [],
794
- systemTranslations: async () => ({}),
795
532
  },
796
- async () => [],
797
- async () => ({
798
- article: [],
799
- blog: [],
800
- collection: [],
801
- company: [],
802
- company_location: [],
803
- location: [],
804
- market: [],
805
- order: [],
806
- page: [],
807
- product: [],
808
- variant: [],
809
- shop: [],
810
- }),
811
533
  fs,
812
534
  documentsLocator,
813
535
  async () => rootUri,
@@ -871,23 +593,7 @@ query {
871
593
  objects: async () => [],
872
594
  liquidDrops: async () => [],
873
595
  filters: async () => [],
874
- systemTranslations: async () => ({}),
875
596
  },
876
- async () => [],
877
- async () => ({
878
- article: [],
879
- blog: [],
880
- collection: [],
881
- company: [],
882
- company_location: [],
883
- location: [],
884
- market: [],
885
- order: [],
886
- page: [],
887
- product: [],
888
- variant: [],
889
- shop: [],
890
- }),
891
597
  fs,
892
598
  documentsLocator,
893
599
  async () => rootUri,
@@ -957,23 +663,7 @@ query {
957
663
  objects: async () => [],
958
664
  liquidDrops: async () => [],
959
665
  filters: async () => [],
960
- systemTranslations: async () => ({}),
961
666
  },
962
- async () => [],
963
- async () => ({
964
- article: [],
965
- blog: [],
966
- collection: [],
967
- company: [],
968
- company_location: [],
969
- location: [],
970
- market: [],
971
- order: [],
972
- page: [],
973
- product: [],
974
- variant: [],
975
- shop: [],
976
- }),
977
667
  fs,
978
668
  documentsLocator,
979
669
  async () => rootUri,
@@ -1018,23 +708,7 @@ query {
1018
708
  objects: async () => [],
1019
709
  liquidDrops: async () => [],
1020
710
  filters: async () => [],
1021
- systemTranslations: async () => ({}),
1022
711
  },
1023
- async () => [],
1024
- async () => ({
1025
- article: [],
1026
- blog: [],
1027
- collection: [],
1028
- company: [],
1029
- company_location: [],
1030
- location: [],
1031
- market: [],
1032
- order: [],
1033
- page: [],
1034
- product: [],
1035
- variant: [],
1036
- shop: [],
1037
- }),
1038
712
  fs,
1039
713
  documentsLocator,
1040
714
  async () => rootUri,
@@ -1066,85 +740,146 @@ query {
1066
740
  });
1067
741
  });
1068
742
 
1069
- describe('metafieldDefinitionsObjectMap', async () => {
1070
- it('should convert metafield definitions into types', async () => {
1071
- const metafieldObjectMap = await typeSystem.metafieldDefinitionsObjectMap(
1072
- 'file:///any/file.liquid',
743
+ describe('JSON literal type inference', () => {
744
+ it('should infer shape from a JSON hash literal', async () => {
745
+ const ast = toLiquidHtmlAST(`{% assign a = {x: 1, y: "hello"} %}{{ a }}`);
746
+ const variableOutput = ast.children[1];
747
+ assert(isLiquidVariableOutput(variableOutput));
748
+ const inferredType = await typeSystem.inferType(
749
+ variableOutput.markup,
750
+ ast,
751
+ 'file:///file.liquid',
1073
752
  );
1074
-
1075
- assert(metafieldObjectMap['product_metafields']);
1076
- assert(metafieldObjectMap['product_metafield_custom']);
1077
- assert(metafieldObjectMap['product_metafield_manufacturer']);
753
+ expect(inferredType).to.have.property('kind', 'shape');
754
+ if (typeof inferredType !== 'string' && inferredType.kind === 'shape') {
755
+ expect(inferredType.shape.kind).to.equal('object');
756
+ expect(inferredType.shape.properties?.get('x')).to.deep.equal({
757
+ kind: 'primitive',
758
+ primitiveType: 'number',
759
+ });
760
+ expect(inferredType.shape.properties?.get('y')).to.deep.equal({
761
+ kind: 'primitive',
762
+ primitiveType: 'string',
763
+ });
764
+ }
1078
765
  });
1079
766
 
1080
- it('should group metafield definitions by namespace', async () => {
1081
- const metafieldObjectMap = await typeSystem.metafieldDefinitionsObjectMap(
1082
- 'file:///any/file.liquid',
767
+ it('should infer an empty object shape from {}', async () => {
768
+ const ast = toLiquidHtmlAST(`{% assign a = {} %}{{ a }}`);
769
+ const variableOutput = ast.children[1];
770
+ assert(isLiquidVariableOutput(variableOutput));
771
+ const inferredType = await typeSystem.inferType(
772
+ variableOutput.markup,
773
+ ast,
774
+ 'file:///file.liquid',
1083
775
  );
1084
- const properties = metafieldObjectMap['product_metafields'].properties;
1085
-
1086
- assert(properties);
1087
- expect(properties).toHaveLength(2);
1088
- expect(properties).toContainEqual(
1089
- expect.objectContaining({
1090
- name: 'custom',
1091
- return_type: [{ type: 'product_metafield_custom', name: '' }],
1092
- }),
776
+ expect(inferredType).to.have.property('kind', 'shape');
777
+ if (typeof inferredType !== 'string' && inferredType.kind === 'shape') {
778
+ expect(inferredType.shape.kind).to.equal('object');
779
+ expect(inferredType.shape.properties?.size).to.equal(0);
780
+ }
781
+ });
782
+
783
+ it('should infer array shape from a JSON array literal', async () => {
784
+ const ast = toLiquidHtmlAST(`{% assign a = [1, 2, 3] %}{{ a }}`);
785
+ const variableOutput = ast.children[1];
786
+ assert(isLiquidVariableOutput(variableOutput));
787
+ const inferredType = await typeSystem.inferType(
788
+ variableOutput.markup,
789
+ ast,
790
+ 'file:///file.liquid',
1093
791
  );
1094
- expect(metafieldObjectMap['product_metafields'].properties).toContainEqual(
1095
- expect.objectContaining({
1096
- name: 'manufacturer',
1097
- return_type: [{ type: 'product_metafield_manufacturer', name: '' }],
1098
- }),
792
+ expect(inferredType).to.have.property('kind', 'shape');
793
+ if (typeof inferredType !== 'string' && inferredType.kind === 'shape') {
794
+ expect(inferredType.shape.kind).to.equal('array');
795
+ expect(inferredType.shape.itemShape).to.deep.equal({
796
+ kind: 'primitive',
797
+ primitiveType: 'number',
798
+ });
799
+ }
800
+ });
801
+
802
+ it('should infer nested object shapes', async () => {
803
+ const ast = toLiquidHtmlAST(`{% assign a = {"nested": {"deep": 42}} %}{{ a.nested.deep }}`);
804
+ const variableOutput = ast.children[1];
805
+ assert(isLiquidVariableOutput(variableOutput));
806
+ const inferredType = await typeSystem.inferType(
807
+ variableOutput.markup,
808
+ ast,
809
+ 'file:///file.liquid',
1099
810
  );
811
+ expect(inferredType).to.equal('number');
812
+ });
1100
813
 
1101
- const manufacturerProperties =
1102
- metafieldObjectMap['product_metafield_manufacturer'].properties;
814
+ it('should produce the same shape as parse_json for equivalent JSON', async () => {
815
+ const astLiteral = toLiquidHtmlAST(`{% assign a = {a: 2} %}{{ a }}`);
816
+ const astParseJson = toLiquidHtmlAST(`{% assign b = '{"a": 2}' | parse_json %}{{ b }}`);
1103
817
 
1104
- assert(manufacturerProperties);
1105
- expect(manufacturerProperties).toHaveLength(2);
818
+ const outputLiteral = astLiteral.children[1];
819
+ const outputParseJson = astParseJson.children[1];
820
+ assert(isLiquidVariableOutput(outputLiteral));
821
+ assert(isLiquidVariableOutput(outputParseJson));
1106
822
 
1107
- expect(manufacturerProperties).toContainEqual(
1108
- expect.objectContaining({
1109
- name: 'code',
1110
- return_type: [{ type: 'metafield_string', name: '' }],
1111
- }),
823
+ const typeLiteral = await typeSystem.inferType(
824
+ outputLiteral.markup,
825
+ astLiteral,
826
+ 'file:///file.liquid',
1112
827
  );
1113
- expect(manufacturerProperties).toContainEqual(
1114
- expect.objectContaining({
1115
- name: 'id',
1116
- return_type: [{ type: 'metafield_number', name: '' }],
1117
- }),
828
+ const typeParseJson = await typeSystem.inferType(
829
+ outputParseJson.markup,
830
+ astParseJson,
831
+ 'file:///file.liquid',
1118
832
  );
1119
833
 
1120
- const customProperties = metafieldObjectMap['product_metafield_custom'].properties;
1121
-
1122
- assert(customProperties);
1123
- expect(customProperties).toHaveLength(1);
1124
-
1125
- expect(customProperties).toContainEqual(
1126
- expect.objectContaining({
1127
- name: 'is_rare',
1128
- return_type: [{ type: 'metafield_boolean', name: '' }],
1129
- }),
1130
- );
834
+ expect(typeLiteral).to.have.property('kind', 'shape');
835
+ expect(typeParseJson).to.have.property('kind', 'shape');
836
+ if (
837
+ typeof typeLiteral !== 'string' &&
838
+ typeLiteral.kind === 'shape' &&
839
+ typeof typeParseJson !== 'string' &&
840
+ typeParseJson.kind === 'shape'
841
+ ) {
842
+ // Both should have an 'a' property with number type
843
+ expect(typeLiteral.shape.properties?.get('a')).to.deep.equal(
844
+ typeParseJson.shape.properties?.get('a'),
845
+ );
846
+ }
1131
847
  });
1132
848
 
1133
- it('should have `metafield_x_array` return_type for array of references', async () => {
1134
- const metafieldObjectMap = await typeSystem.metafieldDefinitionsObjectMap(
1135
- 'file:///any/file.liquid',
849
+ it('should support LHS lookups with assign (assign x["key"] = value)', async () => {
850
+ const ast = toLiquidHtmlAST(
851
+ `{% assign config = {} %}{% assign config["key"] = "value" %}{{ config }}`,
1136
852
  );
1137
- const relatedProperties = metafieldObjectMap['order_metafield_related'].properties;
1138
-
1139
- assert(relatedProperties);
1140
- expect(relatedProperties).toHaveLength(1);
853
+ const variableOutput = ast.children[2];
854
+ assert(isLiquidVariableOutput(variableOutput));
855
+ const inferredType = await typeSystem.inferType(
856
+ variableOutput.markup,
857
+ ast,
858
+ 'file:///file.liquid',
859
+ );
860
+ expect(inferredType).to.have.property('kind', 'shape');
861
+ if (typeof inferredType !== 'string' && inferredType.kind === 'shape') {
862
+ expect(inferredType.shape.properties?.get('key')).to.exist;
863
+ }
864
+ });
1141
865
 
1142
- expect(relatedProperties).toContainEqual(
1143
- expect.objectContaining({
1144
- name: 'prods',
1145
- return_type: [{ type: 'metafield_product_array', name: '' }],
1146
- }),
866
+ it('should support << operator (array append)', async () => {
867
+ const ast = toLiquidHtmlAST(`{% assign arr = [] %}{% assign arr << "item" %}{{ arr }}`);
868
+ const variableOutput = ast.children[2];
869
+ assert(isLiquidVariableOutput(variableOutput));
870
+ const inferredType = await typeSystem.inferType(
871
+ variableOutput.markup,
872
+ ast,
873
+ 'file:///file.liquid',
1147
874
  );
875
+ expect(inferredType).to.have.property('kind', 'shape');
876
+ if (typeof inferredType !== 'string' && inferredType.kind === 'shape') {
877
+ expect(inferredType.shape.kind).to.equal('array');
878
+ expect(inferredType.shape.itemShape).to.deep.equal({
879
+ kind: 'primitive',
880
+ primitiveType: 'string',
881
+ });
882
+ }
1148
883
  });
1149
884
  });
1150
885
  });