@platformos/platformos-language-server-common 0.0.2

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 (711) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +87 -0
  3. package/dist/ClientCapabilities.d.ts +14 -0
  4. package/dist/ClientCapabilities.js +52 -0
  5. package/dist/ClientCapabilities.js.map +1 -0
  6. package/dist/PropertyShapeInference.d.ts +57 -0
  7. package/dist/PropertyShapeInference.js +336 -0
  8. package/dist/PropertyShapeInference.js.map +1 -0
  9. package/dist/TypeSystem.d.ts +94 -0
  10. package/dist/TypeSystem.js +1481 -0
  11. package/dist/TypeSystem.js.map +1 -0
  12. package/dist/VariableShapeExtractor.d.ts +14 -0
  13. package/dist/VariableShapeExtractor.js +283 -0
  14. package/dist/VariableShapeExtractor.js.map +1 -0
  15. package/dist/codeActions/BaseCodeActionsProvider.d.ts +11 -0
  16. package/dist/codeActions/BaseCodeActionsProvider.js +14 -0
  17. package/dist/codeActions/BaseCodeActionsProvider.js.map +1 -0
  18. package/dist/codeActions/CodeActionsProvider.d.ts +9 -0
  19. package/dist/codeActions/CodeActionsProvider.js +22 -0
  20. package/dist/codeActions/CodeActionsProvider.js.map +1 -0
  21. package/dist/codeActions/index.d.ts +1 -0
  22. package/dist/codeActions/index.js +7 -0
  23. package/dist/codeActions/index.js.map +1 -0
  24. package/dist/codeActions/providers/FixAllProvider.d.ts +23 -0
  25. package/dist/codeActions/providers/FixAllProvider.js +52 -0
  26. package/dist/codeActions/providers/FixAllProvider.js.map +1 -0
  27. package/dist/codeActions/providers/FixProvider.d.ts +6 -0
  28. package/dist/codeActions/providers/FixProvider.js +72 -0
  29. package/dist/codeActions/providers/FixProvider.js.map +1 -0
  30. package/dist/codeActions/providers/GenerateDocBlockProvider.d.ts +10 -0
  31. package/dist/codeActions/providers/GenerateDocBlockProvider.js +39 -0
  32. package/dist/codeActions/providers/GenerateDocBlockProvider.js.map +1 -0
  33. package/dist/codeActions/providers/SuggestionProvider.d.ts +6 -0
  34. package/dist/codeActions/providers/SuggestionProvider.js +41 -0
  35. package/dist/codeActions/providers/SuggestionProvider.js.map +1 -0
  36. package/dist/codeActions/providers/index.d.ts +3 -0
  37. package/dist/codeActions/providers/index.js +10 -0
  38. package/dist/codeActions/providers/index.js.map +1 -0
  39. package/dist/codeActions/providers/utils.d.ts +20 -0
  40. package/dist/codeActions/providers/utils.js +29 -0
  41. package/dist/codeActions/providers/utils.js.map +1 -0
  42. package/dist/commands/BaseExecuteCommandProvider.d.ts +13 -0
  43. package/dist/commands/BaseExecuteCommandProvider.js +13 -0
  44. package/dist/commands/BaseExecuteCommandProvider.js.map +1 -0
  45. package/dist/commands/ExecuteCommandProvider.d.ts +11 -0
  46. package/dist/commands/ExecuteCommandProvider.js +30 -0
  47. package/dist/commands/ExecuteCommandProvider.js.map +1 -0
  48. package/dist/commands/index.d.ts +2 -0
  49. package/dist/commands/index.js +9 -0
  50. package/dist/commands/index.js.map +1 -0
  51. package/dist/commands/providers/ApplyFixesProvider.d.ts +19 -0
  52. package/dist/commands/providers/ApplyFixesProvider.js +69 -0
  53. package/dist/commands/providers/ApplyFixesProvider.js.map +1 -0
  54. package/dist/commands/providers/ApplySuggestionProvider.d.ts +19 -0
  55. package/dist/commands/providers/ApplySuggestionProvider.js +73 -0
  56. package/dist/commands/providers/ApplySuggestionProvider.js.map +1 -0
  57. package/dist/commands/providers/GenerateDocBlockCommandProvider.d.ts +19 -0
  58. package/dist/commands/providers/GenerateDocBlockCommandProvider.js +64 -0
  59. package/dist/commands/providers/GenerateDocBlockCommandProvider.js.map +1 -0
  60. package/dist/commands/providers/RunChecksProvider.d.ts +26 -0
  61. package/dist/commands/providers/RunChecksProvider.js +32 -0
  62. package/dist/commands/providers/RunChecksProvider.js.map +1 -0
  63. package/dist/commands/providers/index.d.ts +3 -0
  64. package/dist/commands/providers/index.js +12 -0
  65. package/dist/commands/providers/index.js.map +1 -0
  66. package/dist/completions/CompletionsProvider.d.ts +35 -0
  67. package/dist/completions/CompletionsProvider.js +55 -0
  68. package/dist/completions/CompletionsProvider.js.map +1 -0
  69. package/dist/completions/index.d.ts +1 -0
  70. package/dist/completions/index.js +6 -0
  71. package/dist/completions/index.js.map +1 -0
  72. package/dist/completions/params/LiquidCompletionParams.d.ts +24 -0
  73. package/dist/completions/params/LiquidCompletionParams.js +436 -0
  74. package/dist/completions/params/LiquidCompletionParams.js.map +1 -0
  75. package/dist/completions/params/fix.d.ts +11 -0
  76. package/dist/completions/params/fix.js +238 -0
  77. package/dist/completions/params/fix.js.map +1 -0
  78. package/dist/completions/params/index.d.ts +2 -0
  79. package/dist/completions/params/index.js +8 -0
  80. package/dist/completions/params/index.js.map +1 -0
  81. package/dist/completions/providers/ContentForBlockTypeCompletionProvider.d.ts +8 -0
  82. package/dist/completions/providers/ContentForBlockTypeCompletionProvider.js +36 -0
  83. package/dist/completions/providers/ContentForBlockTypeCompletionProvider.js.map +1 -0
  84. package/dist/completions/providers/ContentForCompletionProvider.d.ts +7 -0
  85. package/dist/completions/providers/ContentForCompletionProvider.js +87 -0
  86. package/dist/completions/providers/ContentForCompletionProvider.js.map +1 -0
  87. package/dist/completions/providers/ContentForParameterCompletionProvider.d.ts +23 -0
  88. package/dist/completions/providers/ContentForParameterCompletionProvider.js +127 -0
  89. package/dist/completions/providers/ContentForParameterCompletionProvider.js.map +1 -0
  90. package/dist/completions/providers/FilterCompletionProvider.d.ts +21 -0
  91. package/dist/completions/providers/FilterCompletionProvider.js +162 -0
  92. package/dist/completions/providers/FilterCompletionProvider.js.map +1 -0
  93. package/dist/completions/providers/FilterNamedParameterCompletionProvider.d.ts +15 -0
  94. package/dist/completions/providers/FilterNamedParameterCompletionProvider.js +86 -0
  95. package/dist/completions/providers/FilterNamedParameterCompletionProvider.js.map +1 -0
  96. package/dist/completions/providers/HtmlAttributeCompletionProvider.d.ts +13 -0
  97. package/dist/completions/providers/HtmlAttributeCompletionProvider.js +83 -0
  98. package/dist/completions/providers/HtmlAttributeCompletionProvider.js.map +1 -0
  99. package/dist/completions/providers/HtmlAttributeValueCompletionProvider.d.ts +7 -0
  100. package/dist/completions/providers/HtmlAttributeValueCompletionProvider.js +53 -0
  101. package/dist/completions/providers/HtmlAttributeValueCompletionProvider.js.map +1 -0
  102. package/dist/completions/providers/HtmlTagCompletionProvider.d.ts +7 -0
  103. package/dist/completions/providers/HtmlTagCompletionProvider.js +90 -0
  104. package/dist/completions/providers/HtmlTagCompletionProvider.js.map +1 -0
  105. package/dist/completions/providers/LiquidDocParamTypeCompletionProvider.d.ts +9 -0
  106. package/dist/completions/providers/LiquidDocParamTypeCompletionProvider.js +56 -0
  107. package/dist/completions/providers/LiquidDocParamTypeCompletionProvider.js.map +1 -0
  108. package/dist/completions/providers/LiquidDocTagCompletionProvider.d.ts +8 -0
  109. package/dist/completions/providers/LiquidDocTagCompletionProvider.js +62 -0
  110. package/dist/completions/providers/LiquidDocTagCompletionProvider.js.map +1 -0
  111. package/dist/completions/providers/LiquidTagsCompletionProvider.d.ts +9 -0
  112. package/dist/completions/providers/LiquidTagsCompletionProvider.js +367 -0
  113. package/dist/completions/providers/LiquidTagsCompletionProvider.js.map +1 -0
  114. package/dist/completions/providers/ObjectAttributeCompletionProvider.d.ts +9 -0
  115. package/dist/completions/providers/ObjectAttributeCompletionProvider.js +71 -0
  116. package/dist/completions/providers/ObjectAttributeCompletionProvider.js.map +1 -0
  117. package/dist/completions/providers/ObjectCompletionProvider.d.ts +9 -0
  118. package/dist/completions/providers/ObjectCompletionProvider.js +35 -0
  119. package/dist/completions/providers/ObjectCompletionProvider.js.map +1 -0
  120. package/dist/completions/providers/PartialCompletionProvider.d.ts +9 -0
  121. package/dist/completions/providers/PartialCompletionProvider.js +34 -0
  122. package/dist/completions/providers/PartialCompletionProvider.js.map +1 -0
  123. package/dist/completions/providers/RenderPartialParameterCompletionProvider.d.ts +10 -0
  124. package/dist/completions/providers/RenderPartialParameterCompletionProvider.js +55 -0
  125. package/dist/completions/providers/RenderPartialParameterCompletionProvider.js.map +1 -0
  126. package/dist/completions/providers/TranslationCompletionProvider.d.ts +11 -0
  127. package/dist/completions/providers/TranslationCompletionProvider.js +78 -0
  128. package/dist/completions/providers/TranslationCompletionProvider.js.map +1 -0
  129. package/dist/completions/providers/common/CompletionItemProperties.d.ts +7 -0
  130. package/dist/completions/providers/common/CompletionItemProperties.js +52 -0
  131. package/dist/completions/providers/common/CompletionItemProperties.js.map +1 -0
  132. package/dist/completions/providers/common/Provider.d.ts +5 -0
  133. package/dist/completions/providers/common/Provider.js +3 -0
  134. package/dist/completions/providers/common/Provider.js.map +1 -0
  135. package/dist/completions/providers/common/index.d.ts +7 -0
  136. package/dist/completions/providers/common/index.js +17 -0
  137. package/dist/completions/providers/common/index.js.map +1 -0
  138. package/dist/completions/providers/data/contentForParameterCompletionOptions.d.ts +7 -0
  139. package/dist/completions/providers/data/contentForParameterCompletionOptions.js +13 -0
  140. package/dist/completions/providers/data/contentForParameterCompletionOptions.js.map +1 -0
  141. package/dist/completions/providers/index.d.ts +17 -0
  142. package/dist/completions/providers/index.js +36 -0
  143. package/dist/completions/providers/index.js.map +1 -0
  144. package/dist/css/CSSLanguageService.d.ts +12 -0
  145. package/dist/css/CSSLanguageService.js +94 -0
  146. package/dist/css/CSSLanguageService.js.map +1 -0
  147. package/dist/css/test/test-helpers.d.ts +4 -0
  148. package/dist/css/test/test-helpers.js +19 -0
  149. package/dist/css/test/test-helpers.js.map +1 -0
  150. package/dist/definitions/BaseDefinitionProvider.d.ts +5 -0
  151. package/dist/definitions/BaseDefinitionProvider.js +3 -0
  152. package/dist/definitions/BaseDefinitionProvider.js.map +1 -0
  153. package/dist/definitions/DefinitionProvider.d.ts +8 -0
  154. package/dist/definitions/DefinitionProvider.js +29 -0
  155. package/dist/definitions/DefinitionProvider.js.map +1 -0
  156. package/dist/definitions/providers/SchemaTranslationStringDefinitionProvider.d.ts +10 -0
  157. package/dist/definitions/providers/SchemaTranslationStringDefinitionProvider.js +55 -0
  158. package/dist/definitions/providers/SchemaTranslationStringDefinitionProvider.js.map +1 -0
  159. package/dist/definitions/providers/TranslationStringDefinitionProvider.d.ts +10 -0
  160. package/dist/definitions/providers/TranslationStringDefinitionProvider.js +48 -0
  161. package/dist/definitions/providers/TranslationStringDefinitionProvider.js.map +1 -0
  162. package/dist/diagnostics/DiagnosticsManager.d.ts +24 -0
  163. package/dist/diagnostics/DiagnosticsManager.js +40 -0
  164. package/dist/diagnostics/DiagnosticsManager.js.map +1 -0
  165. package/dist/diagnostics/index.d.ts +2 -0
  166. package/dist/diagnostics/index.js +8 -0
  167. package/dist/diagnostics/index.js.map +1 -0
  168. package/dist/diagnostics/offenseToDiagnostic.d.ts +4 -0
  169. package/dist/diagnostics/offenseToDiagnostic.js +68 -0
  170. package/dist/diagnostics/offenseToDiagnostic.js.map +1 -0
  171. package/dist/diagnostics/runChecks.d.ts +9 -0
  172. package/dist/diagnostics/runChecks.js +103 -0
  173. package/dist/diagnostics/runChecks.js.map +1 -0
  174. package/dist/docset/HtmlDocset.d.ts +35 -0
  175. package/dist/docset/HtmlDocset.js +39 -0
  176. package/dist/docset/HtmlDocset.js.map +1 -0
  177. package/dist/docset/MarkdownRenderer.d.ts +7 -0
  178. package/dist/docset/MarkdownRenderer.js +125 -0
  179. package/dist/docset/MarkdownRenderer.js.map +1 -0
  180. package/dist/docset/index.d.ts +2 -0
  181. package/dist/docset/index.js +22 -0
  182. package/dist/docset/index.js.map +1 -0
  183. package/dist/documentHighlights/BaseDocumentHighlightsProvider.d.ts +5 -0
  184. package/dist/documentHighlights/BaseDocumentHighlightsProvider.js +3 -0
  185. package/dist/documentHighlights/BaseDocumentHighlightsProvider.js.map +1 -0
  186. package/dist/documentHighlights/DocumentHighlightsProvider.d.ts +22 -0
  187. package/dist/documentHighlights/DocumentHighlightsProvider.js +41 -0
  188. package/dist/documentHighlights/DocumentHighlightsProvider.js.map +1 -0
  189. package/dist/documentHighlights/index.d.ts +1 -0
  190. package/dist/documentHighlights/index.js +7 -0
  191. package/dist/documentHighlights/index.js.map +1 -0
  192. package/dist/documentHighlights/providers/HtmlTagNameDocumentHighlightsProvider.d.ts +11 -0
  193. package/dist/documentHighlights/providers/HtmlTagNameDocumentHighlightsProvider.js +20 -0
  194. package/dist/documentHighlights/providers/HtmlTagNameDocumentHighlightsProvider.js.map +1 -0
  195. package/dist/documentHighlights/providers/LiquidBlockTagDocumentHighlightsProvider.d.ts +11 -0
  196. package/dist/documentHighlights/providers/LiquidBlockTagDocumentHighlightsProvider.js +48 -0
  197. package/dist/documentHighlights/providers/LiquidBlockTagDocumentHighlightsProvider.js.map +1 -0
  198. package/dist/documentHighlights/providers/index.d.ts +2 -0
  199. package/dist/documentHighlights/providers/index.js +8 -0
  200. package/dist/documentHighlights/providers/index.js.map +1 -0
  201. package/dist/documentLinks/DocumentLinksProvider.d.ts +12 -0
  202. package/dist/documentLinks/DocumentLinksProvider.js +78 -0
  203. package/dist/documentLinks/DocumentLinksProvider.js.map +1 -0
  204. package/dist/documentLinks/index.d.ts +1 -0
  205. package/dist/documentLinks/index.js +6 -0
  206. package/dist/documentLinks/index.js.map +1 -0
  207. package/dist/documents/DocumentManager.d.ts +60 -0
  208. package/dist/documents/DocumentManager.js +167 -0
  209. package/dist/documents/DocumentManager.js.map +1 -0
  210. package/dist/documents/index.d.ts +2 -0
  211. package/dist/documents/index.js +21 -0
  212. package/dist/documents/index.js.map +1 -0
  213. package/dist/documents/types.d.ts +39 -0
  214. package/dist/documents/types.js +11 -0
  215. package/dist/documents/types.js.map +1 -0
  216. package/dist/formatting/OnTypeFormattingProvider.d.ts +10 -0
  217. package/dist/formatting/OnTypeFormattingProvider.js +24 -0
  218. package/dist/formatting/OnTypeFormattingProvider.js.map +1 -0
  219. package/dist/formatting/index.d.ts +1 -0
  220. package/dist/formatting/index.js +6 -0
  221. package/dist/formatting/index.js.map +1 -0
  222. package/dist/formatting/providers/BracketsAutoclosingOnTypeFormattingProvider.d.ts +49 -0
  223. package/dist/formatting/providers/BracketsAutoclosingOnTypeFormattingProvider.js +105 -0
  224. package/dist/formatting/providers/BracketsAutoclosingOnTypeFormattingProvider.js.map +1 -0
  225. package/dist/formatting/providers/HtmlElementAutoclosingOnTypeFormattingProvider.d.ts +41 -0
  226. package/dist/formatting/providers/HtmlElementAutoclosingOnTypeFormattingProvider.js +105 -0
  227. package/dist/formatting/providers/HtmlElementAutoclosingOnTypeFormattingProvider.js.map +1 -0
  228. package/dist/formatting/types.d.ts +7 -0
  229. package/dist/formatting/types.js +3 -0
  230. package/dist/formatting/types.js.map +1 -0
  231. package/dist/hover/BaseHoverProvider.d.ts +5 -0
  232. package/dist/hover/BaseHoverProvider.js +3 -0
  233. package/dist/hover/BaseHoverProvider.js.map +1 -0
  234. package/dist/hover/HoverProvider.d.ts +20 -0
  235. package/dist/hover/HoverProvider.js +55 -0
  236. package/dist/hover/HoverProvider.js.map +1 -0
  237. package/dist/hover/index.d.ts +1 -0
  238. package/dist/hover/index.js +6 -0
  239. package/dist/hover/index.js.map +1 -0
  240. package/dist/hover/providers/ContentForArgumentHoverProvider.d.ts +8 -0
  241. package/dist/hover/providers/ContentForArgumentHoverProvider.js +37 -0
  242. package/dist/hover/providers/ContentForArgumentHoverProvider.js.map +1 -0
  243. package/dist/hover/providers/ContentForTypeHoverProvider.d.ts +8 -0
  244. package/dist/hover/providers/ContentForTypeHoverProvider.js +32 -0
  245. package/dist/hover/providers/ContentForTypeHoverProvider.js.map +1 -0
  246. package/dist/hover/providers/HtmlAttributeHoverProvider.d.ts +6 -0
  247. package/dist/hover/providers/HtmlAttributeHoverProvider.js +37 -0
  248. package/dist/hover/providers/HtmlAttributeHoverProvider.js.map +1 -0
  249. package/dist/hover/providers/HtmlAttributeValueHoverProvider.d.ts +6 -0
  250. package/dist/hover/providers/HtmlAttributeValueHoverProvider.js +42 -0
  251. package/dist/hover/providers/HtmlAttributeValueHoverProvider.js.map +1 -0
  252. package/dist/hover/providers/HtmlTagHoverProvider.d.ts +6 -0
  253. package/dist/hover/providers/HtmlTagHoverProvider.js +37 -0
  254. package/dist/hover/providers/HtmlTagHoverProvider.js.map +1 -0
  255. package/dist/hover/providers/LiquidDocTagHoverProvider.d.ts +9 -0
  256. package/dist/hover/providers/LiquidDocTagHoverProvider.js +42 -0
  257. package/dist/hover/providers/LiquidDocTagHoverProvider.js.map +1 -0
  258. package/dist/hover/providers/LiquidFilterArgumentHoverProvider.d.ts +8 -0
  259. package/dist/hover/providers/LiquidFilterArgumentHoverProvider.js +36 -0
  260. package/dist/hover/providers/LiquidFilterArgumentHoverProvider.js.map +1 -0
  261. package/dist/hover/providers/LiquidFilterHoverProvider.d.ts +8 -0
  262. package/dist/hover/providers/LiquidFilterHoverProvider.js +29 -0
  263. package/dist/hover/providers/LiquidFilterHoverProvider.js.map +1 -0
  264. package/dist/hover/providers/LiquidObjectAttributeHoverProvider.d.ts +9 -0
  265. package/dist/hover/providers/LiquidObjectAttributeHoverProvider.js +113 -0
  266. package/dist/hover/providers/LiquidObjectAttributeHoverProvider.js.map +1 -0
  267. package/dist/hover/providers/LiquidObjectHoverProvider.d.ts +9 -0
  268. package/dist/hover/providers/LiquidObjectHoverProvider.js +72 -0
  269. package/dist/hover/providers/LiquidObjectHoverProvider.js.map +1 -0
  270. package/dist/hover/providers/LiquidTagHoverProvider.d.ts +8 -0
  271. package/dist/hover/providers/LiquidTagHoverProvider.js +31 -0
  272. package/dist/hover/providers/LiquidTagHoverProvider.js.map +1 -0
  273. package/dist/hover/providers/RenderPartialHoverProvider.d.ts +8 -0
  274. package/dist/hover/providers/RenderPartialHoverProvider.js +28 -0
  275. package/dist/hover/providers/RenderPartialHoverProvider.js.map +1 -0
  276. package/dist/hover/providers/RenderPartialParameterHoverProvider.d.ts +8 -0
  277. package/dist/hover/providers/RenderPartialParameterHoverProvider.js +33 -0
  278. package/dist/hover/providers/RenderPartialParameterHoverProvider.js.map +1 -0
  279. package/dist/hover/providers/TranslationHoverProvider.d.ts +13 -0
  280. package/dist/hover/providers/TranslationHoverProvider.js +45 -0
  281. package/dist/hover/providers/TranslationHoverProvider.js.map +1 -0
  282. package/dist/hover/providers/index.d.ts +11 -0
  283. package/dist/hover/providers/index.js +26 -0
  284. package/dist/hover/providers/index.js.map +1 -0
  285. package/dist/index.d.ts +8 -0
  286. package/dist/index.js +33 -0
  287. package/dist/index.js.map +1 -0
  288. package/dist/internal-types.d.ts +1 -0
  289. package/dist/internal-types.js +3 -0
  290. package/dist/internal-types.js.map +1 -0
  291. package/dist/json/JSONContributions.d.ts +25 -0
  292. package/dist/json/JSONContributions.js +99 -0
  293. package/dist/json/JSONContributions.js.map +1 -0
  294. package/dist/json/JSONLanguageService.d.ts +27 -0
  295. package/dist/json/JSONLanguageService.js +171 -0
  296. package/dist/json/JSONLanguageService.js.map +1 -0
  297. package/dist/json/RequestContext.d.ts +22 -0
  298. package/dist/json/RequestContext.js +14 -0
  299. package/dist/json/RequestContext.js.map +1 -0
  300. package/dist/json/completions/JSONCompletionProvider.d.ts +30 -0
  301. package/dist/json/completions/JSONCompletionProvider.js +3 -0
  302. package/dist/json/completions/JSONCompletionProvider.js.map +1 -0
  303. package/dist/json/completions/providers/BlockSettingsPropertyCompletionProvider.d.ts +44 -0
  304. package/dist/json/completions/providers/BlockSettingsPropertyCompletionProvider.js +98 -0
  305. package/dist/json/completions/providers/BlockSettingsPropertyCompletionProvider.js.map +1 -0
  306. package/dist/json/completions/providers/BlockTypeCompletionProvider.d.ts +35 -0
  307. package/dist/json/completions/providers/BlockTypeCompletionProvider.js +97 -0
  308. package/dist/json/completions/providers/BlockTypeCompletionProvider.js.map +1 -0
  309. package/dist/json/completions/providers/ReferencedBlockTypeCompletionProvider.d.ts +34 -0
  310. package/dist/json/completions/providers/ReferencedBlockTypeCompletionProvider.js +95 -0
  311. package/dist/json/completions/providers/ReferencedBlockTypeCompletionProvider.js.map +1 -0
  312. package/dist/json/completions/providers/SchemaTranslationCompletionProvider.d.ts +9 -0
  313. package/dist/json/completions/providers/SchemaTranslationCompletionProvider.js +46 -0
  314. package/dist/json/completions/providers/SchemaTranslationCompletionProvider.js.map +1 -0
  315. package/dist/json/completions/providers/SettingsPropertyCompletionProvider.d.ts +33 -0
  316. package/dist/json/completions/providers/SettingsPropertyCompletionProvider.js +64 -0
  317. package/dist/json/completions/providers/SettingsPropertyCompletionProvider.js.map +1 -0
  318. package/dist/json/documentLinks/DocumentLinksProvider.d.ts +6 -0
  319. package/dist/json/documentLinks/DocumentLinksProvider.js +45 -0
  320. package/dist/json/documentLinks/DocumentLinksProvider.js.map +1 -0
  321. package/dist/json/hover/JSONHoverProvider.d.ts +7 -0
  322. package/dist/json/hover/JSONHoverProvider.js +3 -0
  323. package/dist/json/hover/JSONHoverProvider.js.map +1 -0
  324. package/dist/json/hover/providers/BlockSettingsHoverProvider.d.ts +12 -0
  325. package/dist/json/hover/providers/BlockSettingsHoverProvider.js +75 -0
  326. package/dist/json/hover/providers/BlockSettingsHoverProvider.js.map +1 -0
  327. package/dist/json/hover/providers/SchemaTranslationHoverProvider.d.ts +10 -0
  328. package/dist/json/hover/providers/SchemaTranslationHoverProvider.js +36 -0
  329. package/dist/json/hover/providers/SchemaTranslationHoverProvider.js.map +1 -0
  330. package/dist/json/hover/providers/SettingsHoverProvider.d.ts +10 -0
  331. package/dist/json/hover/providers/SettingsHoverProvider.js +62 -0
  332. package/dist/json/hover/providers/SettingsHoverProvider.js.map +1 -0
  333. package/dist/json/hover/providers/TranslationPathHoverProvider.d.ts +9 -0
  334. package/dist/json/hover/providers/TranslationPathHoverProvider.js +65 -0
  335. package/dist/json/hover/providers/TranslationPathHoverProvider.js.map +1 -0
  336. package/dist/json/schemaSettings.d.ts +4 -0
  337. package/dist/json/schemaSettings.js +45 -0
  338. package/dist/json/schemaSettings.js.map +1 -0
  339. package/dist/json/test/test-helpers.d.ts +8 -0
  340. package/dist/json/test/test-helpers.js +42 -0
  341. package/dist/json/test/test-helpers.js.map +1 -0
  342. package/dist/json/utils.d.ts +6 -0
  343. package/dist/json/utils.js +31 -0
  344. package/dist/json/utils.js.map +1 -0
  345. package/dist/linkedEditingRanges/BaseLinkedEditingRangesProvider.d.ts +5 -0
  346. package/dist/linkedEditingRanges/BaseLinkedEditingRangesProvider.js +3 -0
  347. package/dist/linkedEditingRanges/BaseLinkedEditingRangesProvider.js.map +1 -0
  348. package/dist/linkedEditingRanges/LinkedEditingRangesProvider.d.ts +8 -0
  349. package/dist/linkedEditingRanges/LinkedEditingRangesProvider.js +31 -0
  350. package/dist/linkedEditingRanges/LinkedEditingRangesProvider.js.map +1 -0
  351. package/dist/linkedEditingRanges/index.d.ts +1 -0
  352. package/dist/linkedEditingRanges/index.js +6 -0
  353. package/dist/linkedEditingRanges/index.js.map +1 -0
  354. package/dist/linkedEditingRanges/providers/EmptyHtmlTagLinkedRangesProvider.d.ts +9 -0
  355. package/dist/linkedEditingRanges/providers/EmptyHtmlTagLinkedRangesProvider.js +37 -0
  356. package/dist/linkedEditingRanges/providers/EmptyHtmlTagLinkedRangesProvider.js.map +1 -0
  357. package/dist/linkedEditingRanges/providers/HtmlTagNameLinkedRangesProvider.d.ts +12 -0
  358. package/dist/linkedEditingRanges/providers/HtmlTagNameLinkedRangesProvider.js +26 -0
  359. package/dist/linkedEditingRanges/providers/HtmlTagNameLinkedRangesProvider.js.map +1 -0
  360. package/dist/linkedEditingRanges/providers/index.d.ts +2 -0
  361. package/dist/linkedEditingRanges/providers/index.js +8 -0
  362. package/dist/linkedEditingRanges/providers/index.js.map +1 -0
  363. package/dist/linkedEditingRanges/wordPattern.d.ts +1 -0
  364. package/dist/linkedEditingRanges/wordPattern.js +7 -0
  365. package/dist/linkedEditingRanges/wordPattern.js.map +1 -0
  366. package/dist/plugins/css.d.ts +3 -0
  367. package/dist/plugins/css.js +12 -0
  368. package/dist/plugins/css.js.map +1 -0
  369. package/dist/progress.d.ts +42 -0
  370. package/dist/progress.js +74 -0
  371. package/dist/progress.js.map +1 -0
  372. package/dist/rename/BaseRenameProvider.d.ts +6 -0
  373. package/dist/rename/BaseRenameProvider.js +3 -0
  374. package/dist/rename/BaseRenameProvider.js.map +1 -0
  375. package/dist/rename/RenameProvider.d.ts +21 -0
  376. package/dist/rename/RenameProvider.js +58 -0
  377. package/dist/rename/RenameProvider.js.map +1 -0
  378. package/dist/rename/providers/HtmlTagNameRenameProvider.d.ts +10 -0
  379. package/dist/rename/providers/HtmlTagNameRenameProvider.js +39 -0
  380. package/dist/rename/providers/HtmlTagNameRenameProvider.js.map +1 -0
  381. package/dist/rename/providers/LiquidVariableRenameProvider.d.ts +16 -0
  382. package/dist/rename/providers/LiquidVariableRenameProvider.js +194 -0
  383. package/dist/rename/providers/LiquidVariableRenameProvider.js.map +1 -0
  384. package/dist/renamed/BaseRenameHandler.d.ts +4 -0
  385. package/dist/renamed/BaseRenameHandler.js +3 -0
  386. package/dist/renamed/BaseRenameHandler.js.map +1 -0
  387. package/dist/renamed/RenameHandler.d.ts +18 -0
  388. package/dist/renamed/RenameHandler.js +37 -0
  389. package/dist/renamed/RenameHandler.js.map +1 -0
  390. package/dist/renamed/handlers/AssetRenameHandler.d.ts +26 -0
  391. package/dist/renamed/handlers/AssetRenameHandler.js +99 -0
  392. package/dist/renamed/handlers/AssetRenameHandler.js.map +1 -0
  393. package/dist/renamed/handlers/BlockRenameHandler.d.ts +41 -0
  394. package/dist/renamed/handlers/BlockRenameHandler.js +304 -0
  395. package/dist/renamed/handlers/BlockRenameHandler.js.map +1 -0
  396. package/dist/renamed/handlers/PartialRenameHandler.d.ts +26 -0
  397. package/dist/renamed/handlers/PartialRenameHandler.js +99 -0
  398. package/dist/renamed/handlers/PartialRenameHandler.js.map +1 -0
  399. package/dist/renamed/handlers/SectionRenameHandler.d.ts +25 -0
  400. package/dist/renamed/handlers/SectionRenameHandler.js +176 -0
  401. package/dist/renamed/handlers/SectionRenameHandler.js.map +1 -0
  402. package/dist/renamed/handlers/utils.d.ts +3 -0
  403. package/dist/renamed/handlers/utils.js +20 -0
  404. package/dist/renamed/handlers/utils.js.map +1 -0
  405. package/dist/server/CachedFileSystem.d.ts +12 -0
  406. package/dist/server/CachedFileSystem.js +29 -0
  407. package/dist/server/CachedFileSystem.js.map +1 -0
  408. package/dist/server/Configuration.d.ts +25 -0
  409. package/dist/server/Configuration.js +77 -0
  410. package/dist/server/Configuration.js.map +1 -0
  411. package/dist/server/ThemeGraphManager.d.ts +35 -0
  412. package/dist/server/ThemeGraphManager.js +200 -0
  413. package/dist/server/ThemeGraphManager.js.map +1 -0
  414. package/dist/server/index.d.ts +1 -0
  415. package/dist/server/index.js +6 -0
  416. package/dist/server/index.js.map +1 -0
  417. package/dist/server/safe.d.ts +19 -0
  418. package/dist/server/safe.js +33 -0
  419. package/dist/server/safe.js.map +1 -0
  420. package/dist/server/startServer.d.ts +13 -0
  421. package/dist/server/startServer.js +598 -0
  422. package/dist/server/startServer.js.map +1 -0
  423. package/dist/settings/index.d.ts +29 -0
  424. package/dist/settings/index.js +11 -0
  425. package/dist/settings/index.js.map +1 -0
  426. package/dist/test/ApplyEditsAssertion.d.ts +14 -0
  427. package/dist/test/ApplyEditsAssertion.js +19 -0
  428. package/dist/test/ApplyEditsAssertion.js.map +1 -0
  429. package/dist/test/CompletionItemsAssertion.d.ts +25 -0
  430. package/dist/test/CompletionItemsAssertion.js +60 -0
  431. package/dist/test/CompletionItemsAssertion.js.map +1 -0
  432. package/dist/test/HoverAssertion.d.ts +16 -0
  433. package/dist/test/HoverAssertion.js +54 -0
  434. package/dist/test/HoverAssertion.js.map +1 -0
  435. package/dist/test/MockChecks.d.ts +2 -0
  436. package/dist/test/MockChecks.js +30 -0
  437. package/dist/test/MockChecks.js.map +1 -0
  438. package/dist/test/MockConnection.d.ts +44 -0
  439. package/dist/test/MockConnection.js +106 -0
  440. package/dist/test/MockConnection.js.map +1 -0
  441. package/dist/test/test-setup.d.ts +1 -0
  442. package/dist/test/test-setup.js +8 -0
  443. package/dist/test/test-setup.js.map +1 -0
  444. package/dist/translations.d.ts +19 -0
  445. package/dist/translations.js +73 -0
  446. package/dist/translations.js.map +1 -0
  447. package/dist/tsconfig.tsbuildinfo +1 -0
  448. package/dist/types.d.ts +149 -0
  449. package/dist/types.js +63 -0
  450. package/dist/types.js.map +1 -0
  451. package/dist/utils/array.d.ts +1 -0
  452. package/dist/utils/array.js +11 -0
  453. package/dist/utils/array.js.map +1 -0
  454. package/dist/utils/debounce.d.ts +37 -0
  455. package/dist/utils/debounce.js +44 -0
  456. package/dist/utils/debounce.js.map +1 -0
  457. package/dist/utils/htmlTagNames.d.ts +5 -0
  458. package/dist/utils/htmlTagNames.js +42 -0
  459. package/dist/utils/htmlTagNames.js.map +1 -0
  460. package/dist/utils/index.d.ts +5 -0
  461. package/dist/utils/index.js +26 -0
  462. package/dist/utils/index.js.map +1 -0
  463. package/dist/utils/isCovered.d.ts +4 -0
  464. package/dist/utils/isCovered.js +7 -0
  465. package/dist/utils/isCovered.js.map +1 -0
  466. package/dist/utils/liquidDoc.d.ts +22 -0
  467. package/dist/utils/liquidDoc.js +78 -0
  468. package/dist/utils/liquidDoc.js.map +1 -0
  469. package/dist/utils/node.d.ts +24 -0
  470. package/dist/utils/node.js +52 -0
  471. package/dist/utils/node.js.map +1 -0
  472. package/dist/utils/uri.d.ts +12 -0
  473. package/dist/utils/uri.js +30 -0
  474. package/dist/utils/uri.js.map +1 -0
  475. package/dist/version.d.ts +1 -0
  476. package/dist/version.js +9 -0
  477. package/dist/version.js.map +1 -0
  478. package/package.json +40 -0
  479. package/src/ClientCapabilities.ts +63 -0
  480. package/src/PropertyShapeInference.ts +394 -0
  481. package/src/TypeSystem.spec.ts +1150 -0
  482. package/src/TypeSystem.ts +1948 -0
  483. package/src/VariableShapeExtractor.ts +380 -0
  484. package/src/codeActions/BaseCodeActionsProvider.ts +18 -0
  485. package/src/codeActions/CodeActionsProvider.ts +28 -0
  486. package/src/codeActions/index.ts +1 -0
  487. package/src/codeActions/providers/FixAllProvider.spec.ts +115 -0
  488. package/src/codeActions/providers/FixAllProvider.ts +60 -0
  489. package/src/codeActions/providers/FixProvider.spec.ts +330 -0
  490. package/src/codeActions/providers/FixProvider.ts +105 -0
  491. package/src/codeActions/providers/SuggestionProvider.spec.ts +143 -0
  492. package/src/codeActions/providers/SuggestionProvider.ts +75 -0
  493. package/src/codeActions/providers/index.ts +3 -0
  494. package/src/codeActions/providers/utils.ts +47 -0
  495. package/src/commands/BaseExecuteCommandProvider.ts +15 -0
  496. package/src/commands/ExecuteCommandProvider.ts +59 -0
  497. package/src/commands/index.ts +2 -0
  498. package/src/commands/providers/ApplyFixesProvider.spec.ts +133 -0
  499. package/src/commands/providers/ApplyFixesProvider.ts +86 -0
  500. package/src/commands/providers/ApplySuggestionProvider.spec.ts +135 -0
  501. package/src/commands/providers/ApplySuggestionProvider.ts +105 -0
  502. package/src/commands/providers/RunChecksProvider.spec.ts +55 -0
  503. package/src/commands/providers/RunChecksProvider.ts +36 -0
  504. package/src/commands/providers/index.ts +3 -0
  505. package/src/completions/CompletionsProvider.ts +128 -0
  506. package/src/completions/index.ts +1 -0
  507. package/src/completions/params/LiquidCompletionParams.spec.ts +319 -0
  508. package/src/completions/params/LiquidCompletionParams.ts +538 -0
  509. package/src/completions/params/fix.spec.ts +159 -0
  510. package/src/completions/params/fix.ts +269 -0
  511. package/src/completions/params/index.ts +2 -0
  512. package/src/completions/params/testcases.txt +104 -0
  513. package/src/completions/providers/ContentForBlockTypeCompletionProvider.spec.ts +41 -0
  514. package/src/completions/providers/ContentForBlockTypeCompletionProvider.ts +42 -0
  515. package/src/completions/providers/ContentForCompletionProvider.spec.ts +96 -0
  516. package/src/completions/providers/ContentForCompletionProvider.ts +113 -0
  517. package/src/completions/providers/ContentForParameterCompletionProvider.spec.ts +362 -0
  518. package/src/completions/providers/ContentForParameterCompletionProvider.ts +187 -0
  519. package/src/completions/providers/FilterCompletionProvider.spec.ts +377 -0
  520. package/src/completions/providers/FilterCompletionProvider.ts +225 -0
  521. package/src/completions/providers/FilterNamedParameterCompletionProvider.spec.ts +239 -0
  522. package/src/completions/providers/FilterNamedParameterCompletionProvider.ts +121 -0
  523. package/src/completions/providers/HtmlAttributeCompletionProvider.spec.ts +150 -0
  524. package/src/completions/providers/HtmlAttributeCompletionProvider.ts +117 -0
  525. package/src/completions/providers/HtmlAttributeValueCompletionProvider.spec.ts +38 -0
  526. package/src/completions/providers/HtmlAttributeValueCompletionProvider.ts +65 -0
  527. package/src/completions/providers/HtmlTagCompletionProvider.spec.ts +57 -0
  528. package/src/completions/providers/HtmlTagCompletionProvider.ts +119 -0
  529. package/src/completions/providers/LiquidDocParamTypeCompletionProvider.spec.ts +79 -0
  530. package/src/completions/providers/LiquidDocParamTypeCompletionProvider.ts +65 -0
  531. package/src/completions/providers/LiquidDocTagCompletionProvider.spec.ts +144 -0
  532. package/src/completions/providers/LiquidDocTagCompletionProvider.ts +74 -0
  533. package/src/completions/providers/LiquidTagsCompletionProvider.spec.ts +377 -0
  534. package/src/completions/providers/LiquidTagsCompletionProvider.ts +459 -0
  535. package/src/completions/providers/ObjectAttributeCompletionProvider.spec.ts +524 -0
  536. package/src/completions/providers/ObjectAttributeCompletionProvider.ts +95 -0
  537. package/src/completions/providers/ObjectCompletionProvider.spec.ts +232 -0
  538. package/src/completions/providers/ObjectCompletionProvider.ts +44 -0
  539. package/src/completions/providers/PartialCompletionProvider.spec.ts +107 -0
  540. package/src/completions/providers/PartialCompletionProvider.ts +50 -0
  541. package/src/completions/providers/RenderPartialParameterCompletionProvider.spec.ts +91 -0
  542. package/src/completions/providers/RenderPartialParameterCompletionProvider.ts +79 -0
  543. package/src/completions/providers/TranslationCompletionProvider.spec.ts +65 -0
  544. package/src/completions/providers/TranslationCompletionProvider.ts +103 -0
  545. package/src/completions/providers/common/CompletionItemProperties.ts +66 -0
  546. package/src/completions/providers/common/Provider.ts +6 -0
  547. package/src/completions/providers/common/index.ts +18 -0
  548. package/src/completions/providers/data/contentForParameterCompletionOptions.ts +9 -0
  549. package/src/completions/providers/index.ts +20 -0
  550. package/src/css/CSSLanguageService.spec.ts +161 -0
  551. package/src/css/CSSLanguageService.ts +113 -0
  552. package/src/css/test/test-helpers.ts +30 -0
  553. package/src/definitions/BaseDefinitionProvider.ts +10 -0
  554. package/src/definitions/DefinitionProvider.ts +48 -0
  555. package/src/definitions/providers/SchemaTranslationStringDefinitionProvider.spec.ts +96 -0
  556. package/src/definitions/providers/SchemaTranslationStringDefinitionProvider.ts +82 -0
  557. package/src/definitions/providers/TranslationStringDefinitionProvider.spec.ts +77 -0
  558. package/src/definitions/providers/TranslationStringDefinitionProvider.ts +72 -0
  559. package/src/diagnostics/DiagnosticsManager.spec.ts +79 -0
  560. package/src/diagnostics/DiagnosticsManager.ts +58 -0
  561. package/src/diagnostics/index.ts +2 -0
  562. package/src/diagnostics/offenseToDiagnostic.ts +80 -0
  563. package/src/diagnostics/runChecks.spec.ts +285 -0
  564. package/src/diagnostics/runChecks.ts +147 -0
  565. package/src/docset/HtmlDocset.ts +43 -0
  566. package/src/docset/MarkdownRenderer.spec.ts +46 -0
  567. package/src/docset/MarkdownRenderer.ts +179 -0
  568. package/src/docset/index.ts +2 -0
  569. package/src/documentHighlights/BaseDocumentHighlightsProvider.ts +10 -0
  570. package/src/documentHighlights/DocumentHighlightsProvider.ts +54 -0
  571. package/src/documentHighlights/index.ts +1 -0
  572. package/src/documentHighlights/providers/HtmlTagNameDocumentHighlightsProvider.spec.ts +94 -0
  573. package/src/documentHighlights/providers/HtmlTagNameDocumentHighlightsProvider.ts +22 -0
  574. package/src/documentHighlights/providers/LiquidBlockTagDocumentHighlightsProvider.spec.ts +188 -0
  575. package/src/documentHighlights/providers/LiquidBlockTagDocumentHighlightsProvider.ts +73 -0
  576. package/src/documentHighlights/providers/index.ts +2 -0
  577. package/src/documentLinks/DocumentLinksProvider.spec.ts +66 -0
  578. package/src/documentLinks/DocumentLinksProvider.ts +123 -0
  579. package/src/documentLinks/index.ts +1 -0
  580. package/src/documents/DocumentManager.spec.ts +276 -0
  581. package/src/documents/DocumentManager.ts +232 -0
  582. package/src/documents/index.ts +2 -0
  583. package/src/documents/types.ts +55 -0
  584. package/src/formatting/OnTypeFormattingProvider.spec.ts +74 -0
  585. package/src/formatting/OnTypeFormattingProvider.ts +26 -0
  586. package/src/formatting/index.ts +1 -0
  587. package/src/formatting/providers/BracketsAutoclosingOnTypeFormattingProvider.spec.ts +88 -0
  588. package/src/formatting/providers/BracketsAutoclosingOnTypeFormattingProvider.ts +114 -0
  589. package/src/formatting/providers/HtmlElementAutoclosingOnTypeFormattingProvider.spec.ts +183 -0
  590. package/src/formatting/providers/HtmlElementAutoclosingOnTypeFormattingProvider.ts +127 -0
  591. package/src/formatting/types.ts +12 -0
  592. package/src/hover/BaseHoverProvider.ts +10 -0
  593. package/src/hover/HoverProvider.ts +86 -0
  594. package/src/hover/index.ts +1 -0
  595. package/src/hover/providers/ContentForArgumentHoverProvider.spec.ts +76 -0
  596. package/src/hover/providers/ContentForArgumentHoverProvider.ts +56 -0
  597. package/src/hover/providers/ContentForTypeHoverProvider.spec.ts +91 -0
  598. package/src/hover/providers/ContentForTypeHoverProvider.ts +42 -0
  599. package/src/hover/providers/HtmlAttributeHoverProvider.spec.ts +50 -0
  600. package/src/hover/providers/HtmlAttributeHoverProvider.ts +48 -0
  601. package/src/hover/providers/HtmlAttributeValueHoverProvider.spec.ts +38 -0
  602. package/src/hover/providers/HtmlAttributeValueHoverProvider.ts +52 -0
  603. package/src/hover/providers/HtmlTagHoverProvider.spec.ts +39 -0
  604. package/src/hover/providers/HtmlTagHoverProvider.ts +42 -0
  605. package/src/hover/providers/LiquidDocTagHoverProvider.spec.ts +64 -0
  606. package/src/hover/providers/LiquidDocTagHoverProvider.ts +58 -0
  607. package/src/hover/providers/LiquidFilterArgumentHoverProvider.spec.ts +57 -0
  608. package/src/hover/providers/LiquidFilterArgumentHoverProvider.ts +42 -0
  609. package/src/hover/providers/LiquidFilterHoverProvider.spec.ts +50 -0
  610. package/src/hover/providers/LiquidFilterHoverProvider.ts +29 -0
  611. package/src/hover/providers/LiquidObjectAttributeHoverProvider.spec.ts +238 -0
  612. package/src/hover/providers/LiquidObjectAttributeHoverProvider.ts +156 -0
  613. package/src/hover/providers/LiquidObjectHoverProvider.spec.ts +278 -0
  614. package/src/hover/providers/LiquidObjectHoverProvider.ts +95 -0
  615. package/src/hover/providers/LiquidTagHoverProvider.spec.ts +51 -0
  616. package/src/hover/providers/LiquidTagHoverProvider.ts +33 -0
  617. package/src/hover/providers/RenderPartialHoverProvider.spec.ts +85 -0
  618. package/src/hover/providers/RenderPartialHoverProvider.ts +38 -0
  619. package/src/hover/providers/RenderPartialParameterHoverProvider.spec.ts +70 -0
  620. package/src/hover/providers/RenderPartialParameterHoverProvider.ts +47 -0
  621. package/src/hover/providers/TranslationHoverProvider.spec.ts +59 -0
  622. package/src/hover/providers/TranslationHoverProvider.ts +61 -0
  623. package/src/hover/providers/index.ts +11 -0
  624. package/src/index.spec.ts +8 -0
  625. package/src/index.ts +34 -0
  626. package/src/internal-types.ts +1 -0
  627. package/src/json/JSONContributions.ts +150 -0
  628. package/src/json/JSONLanguageService.spec.ts +424 -0
  629. package/src/json/JSONLanguageService.ts +239 -0
  630. package/src/json/RequestContext.ts +35 -0
  631. package/src/json/completions/JSONCompletionProvider.ts +33 -0
  632. package/src/json/completions/providers/BlockSettingsPropertyCompletionProvider.spec.ts +163 -0
  633. package/src/json/completions/providers/BlockSettingsPropertyCompletionProvider.ts +121 -0
  634. package/src/json/completions/providers/BlockTypeCompletionProvider.spec.ts +137 -0
  635. package/src/json/completions/providers/BlockTypeCompletionProvider.ts +108 -0
  636. package/src/json/completions/providers/ReferencedBlockTypeCompletionProvider.spec.ts +132 -0
  637. package/src/json/completions/providers/ReferencedBlockTypeCompletionProvider.ts +120 -0
  638. package/src/json/completions/providers/SchemaTranslationCompletionProvider.ts +51 -0
  639. package/src/json/completions/providers/SettingsPropertyCompletionProvider.spec.ts +211 -0
  640. package/src/json/completions/providers/SettingsPropertyCompletionProvider.ts +75 -0
  641. package/src/json/documentLinks/DocumentLinksProvider.spec.ts +223 -0
  642. package/src/json/documentLinks/DocumentLinksProvider.ts +61 -0
  643. package/src/json/hover/JSONHoverProvider.ts +8 -0
  644. package/src/json/hover/providers/BlockSettingsHoverProvider.spec.ts +292 -0
  645. package/src/json/hover/providers/BlockSettingsHoverProvider.ts +99 -0
  646. package/src/json/hover/providers/SchemaTranslationHoverProvider.ts +35 -0
  647. package/src/json/hover/providers/SettingsHoverProvider.spec.ts +139 -0
  648. package/src/json/hover/providers/SettingsHoverProvider.ts +79 -0
  649. package/src/json/hover/providers/TranslationPathHoverProvider.ts +71 -0
  650. package/src/json/schemaSettings.spec.ts +103 -0
  651. package/src/json/schemaSettings.ts +53 -0
  652. package/src/json/test/test-helpers.ts +68 -0
  653. package/src/json/utils.ts +30 -0
  654. package/src/linkedEditingRanges/BaseLinkedEditingRangesProvider.ts +10 -0
  655. package/src/linkedEditingRanges/LinkedEditingRangesProvider.ts +40 -0
  656. package/src/linkedEditingRanges/index.ts +1 -0
  657. package/src/linkedEditingRanges/providers/EmptyHtmlTagLinkedRangesProvider.spec.ts +74 -0
  658. package/src/linkedEditingRanges/providers/EmptyHtmlTagLinkedRangesProvider.ts +47 -0
  659. package/src/linkedEditingRanges/providers/HtmlTagNameLinkedRangesProvider.spec.ts +102 -0
  660. package/src/linkedEditingRanges/providers/HtmlTagNameLinkedRangesProvider.ts +28 -0
  661. package/src/linkedEditingRanges/providers/index.ts +2 -0
  662. package/src/linkedEditingRanges/wordPattern.ts +3 -0
  663. package/src/plugins/css.ts +12 -0
  664. package/src/progress.ts +83 -0
  665. package/src/rename/BaseRenameProvider.ts +21 -0
  666. package/src/rename/RenameProvider.ts +91 -0
  667. package/src/rename/providers/HtmlTagNameRenameProvider.spec.ts +84 -0
  668. package/src/rename/providers/HtmlTagNameRenameProvider.ts +59 -0
  669. package/src/rename/providers/LiquidVariableRenameProvider.spec.ts +511 -0
  670. package/src/rename/providers/LiquidVariableRenameProvider.ts +300 -0
  671. package/src/renamed/BaseRenameHandler.ts +5 -0
  672. package/src/renamed/RenameHandler.ts +45 -0
  673. package/src/renamed/handlers/AssetRenameHandler.spec.ts +217 -0
  674. package/src/renamed/handlers/AssetRenameHandler.ts +108 -0
  675. package/src/renamed/handlers/BlockRenameHandler.spec.ts +399 -0
  676. package/src/renamed/handlers/BlockRenameHandler.ts +402 -0
  677. package/src/renamed/handlers/PartialRenameHandler.spec.ts +153 -0
  678. package/src/renamed/handlers/PartialRenameHandler.ts +110 -0
  679. package/src/renamed/handlers/SectionRenameHandler.spec.ts +321 -0
  680. package/src/renamed/handlers/SectionRenameHandler.ts +224 -0
  681. package/src/renamed/handlers/utils.ts +22 -0
  682. package/src/server/CachedFileSystem.ts +39 -0
  683. package/src/server/Configuration.ts +89 -0
  684. package/src/server/ThemeGraphManager.ts +265 -0
  685. package/src/server/index.ts +1 -0
  686. package/src/server/safe.ts +30 -0
  687. package/src/server/startServer.spec.ts +423 -0
  688. package/src/server/startServer.ts +771 -0
  689. package/src/settings/index.ts +50 -0
  690. package/src/test/ApplyEditsAssertion.spec.ts +57 -0
  691. package/src/test/ApplyEditsAssertion.ts +34 -0
  692. package/src/test/CompletionItemsAssertion.spec.ts +48 -0
  693. package/src/test/CompletionItemsAssertion.ts +99 -0
  694. package/src/test/HoverAssertion.ts +84 -0
  695. package/src/test/MockChecks.ts +32 -0
  696. package/src/test/MockConnection.ts +158 -0
  697. package/src/test/test-setup.ts +6 -0
  698. package/src/translations.ts +83 -0
  699. package/src/types.ts +173 -0
  700. package/src/utils/array.ts +6 -0
  701. package/src/utils/debounce.ts +60 -0
  702. package/src/utils/htmlTagNames.ts +61 -0
  703. package/src/utils/index.ts +12 -0
  704. package/src/utils/isCovered.ts +3 -0
  705. package/src/utils/liquidDoc.spec.ts +167 -0
  706. package/src/utils/liquidDoc.ts +102 -0
  707. package/src/utils/node.ts +69 -0
  708. package/src/utils/uri.ts +22 -0
  709. package/src/version.ts +3 -0
  710. package/tsconfig.build.json +10 -0
  711. package/tsconfig.json +24 -0
@@ -0,0 +1,1948 @@
1
+ import {
2
+ AssignMarkup,
3
+ ComplexLiquidExpression,
4
+ FunctionMarkup,
5
+ LiquidDocParamNode,
6
+ LiquidExpression,
7
+ LiquidHtmlNode,
8
+ LiquidTag,
9
+ LiquidTagDecrement,
10
+ LiquidTagIncrement,
11
+ LiquidVariable,
12
+ LiquidVariableLookup,
13
+ NamedTags,
14
+ NodeTypes,
15
+ TextNode,
16
+ GraphQLMarkup,
17
+ GraphQLInlineMarkup,
18
+ LiquidString,
19
+ HashAssignMarkup,
20
+ toLiquidHtmlAST,
21
+ } from '@platformos/liquid-html-parser';
22
+ import {
23
+ ArrayReturnType,
24
+ DocsetEntry,
25
+ FilterEntry,
26
+ MetafieldDefinitionMap,
27
+ MetafieldDefinition,
28
+ ObjectEntry,
29
+ ReturnType,
30
+ SourceCodeType,
31
+ ThemeDocset,
32
+ isError,
33
+ parseJSON,
34
+ path,
35
+ FETCHED_METAFIELD_CATEGORIES,
36
+ BasicParamTypes,
37
+ getValidParamTypes,
38
+ parseParamType,
39
+ } from '@platformos/platformos-check-common';
40
+ import {
41
+ GetThemeSettingsSchemaForURI,
42
+ InputSetting,
43
+ isInputSetting,
44
+ isSettingsCategory,
45
+ } from './settings';
46
+ import { findLast, memo } from './utils';
47
+ import { visit } from '@platformos/platformos-check-common';
48
+ import {
49
+ PropertyShape,
50
+ inferShapeFromJSONString,
51
+ inferShapeFromGraphQL,
52
+ lookupPropertyPath,
53
+ shapeToTypeString,
54
+ shapeToDetailString,
55
+ } from './PropertyShapeInference';
56
+ import { AbstractFileSystem, DocumentsLocator } from '@platformos/platformos-common';
57
+ import { URI } from 'vscode-uri';
58
+
59
+ export class TypeSystem {
60
+ private graphqlSchemaCache: string | undefined;
61
+ private graphqlSchemaLoaded = false;
62
+
63
+ constructor(
64
+ private readonly themeDocset: ThemeDocset,
65
+ private readonly getThemeSettingsSchemaForURI: GetThemeSettingsSchemaForURI,
66
+ private readonly getMetafieldDefinitions: (rootUri: string) => Promise<MetafieldDefinitionMap>,
67
+ private readonly fs?: AbstractFileSystem,
68
+ private readonly documentsLocator?: DocumentsLocator,
69
+ private readonly findThemeRootURI?: (uri: string) => Promise<string | null>,
70
+ ) {}
71
+
72
+ private async getGraphQLSchema(): Promise<string | undefined> {
73
+ if (!this.graphqlSchemaLoaded) {
74
+ this.graphqlSchemaCache = (await this.themeDocset.graphQL()) ?? undefined;
75
+ this.graphqlSchemaLoaded = true;
76
+ }
77
+ return this.graphqlSchemaCache;
78
+ }
79
+
80
+ async inferType(
81
+ thing: Identifier | ComplexLiquidExpression | LiquidVariable | AssignMarkup,
82
+ partialAst: LiquidHtmlNode,
83
+ uri: string,
84
+ ): Promise<PseudoType | ArrayType | ShapeType | UnionType> {
85
+ const [objectMap, filtersMap, symbolsTable] = await Promise.all([
86
+ this.objectMap(uri, partialAst),
87
+ this.filtersMap(),
88
+ this.symbolsTable(partialAst, uri),
89
+ ]);
90
+
91
+ return inferType(thing, symbolsTable, objectMap, filtersMap);
92
+ }
93
+
94
+ async availableVariables(
95
+ partialAst: LiquidHtmlNode,
96
+ partial: string,
97
+ node: LiquidVariableLookup,
98
+ uri: string,
99
+ ): Promise<{ entry: DocsetEntry; type: PseudoType | ArrayType | ShapeType | UnionType }[]> {
100
+ const [objectMap, filtersMap, symbolsTable] = await Promise.all([
101
+ this.objectMap(uri, partialAst),
102
+ this.filtersMap(),
103
+ this.symbolsTable(partialAst, uri),
104
+ ]);
105
+
106
+ return Object.entries(symbolsTable)
107
+ .filter(
108
+ ([key, typeRanges]) =>
109
+ key.startsWith(partial) &&
110
+ typeRanges.some((typeRange) => isCorrectTypeRange(typeRange, node)),
111
+ )
112
+ .map(([identifier, typeRanges]) => {
113
+ const typeRange = findLast(typeRanges, (typeRange) => isCorrectTypeRange(typeRange, node))!;
114
+ const type = resolveTypeRangeType(typeRange.type, symbolsTable, objectMap, filtersMap);
115
+ const entryType = isArrayType(type)
116
+ ? type.valueType
117
+ : isShapeType(type) || isUnionType(type)
118
+ ? Untyped
119
+ : type;
120
+ const entry = objectMap[entryType] ?? {};
121
+ return {
122
+ entry: { ...entry, name: identifier },
123
+ type,
124
+ };
125
+ });
126
+ }
127
+
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
+ /**
152
+ * An indexed representation of objects.json by name
153
+ *
154
+ * e.g. objectMap['product'] returns the product ObjectEntry.
155
+ */
156
+ 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;
229
+ };
230
+
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
+ // This is the big one we reuse (memoized)
297
+ private _objectMap = memo(async (): Promise<ObjectMap> => {
298
+ const entries = await this.objectEntries();
299
+ return entries.reduce((map, entry) => {
300
+ map[entry.name] = entry;
301
+ return map;
302
+ }, {} as ObjectMap);
303
+ });
304
+
305
+ /** An indexed representation of filters.json by name */
306
+ public filtersMap = memo(async (): Promise<FiltersMap> => {
307
+ const entries = await this.filterEntries();
308
+ return entries.reduce((map, entry) => {
309
+ map[entry.name] = entry;
310
+ return map;
311
+ }, {} as FiltersMap);
312
+ });
313
+
314
+ public filterEntries = memo(async () => {
315
+ return this.themeDocset.filters();
316
+ });
317
+
318
+ public objectEntries = memo(async () => {
319
+ return this.themeDocset.objects();
320
+ });
321
+
322
+ private async symbolsTable(partialAst: LiquidHtmlNode, uri: string): Promise<SymbolsTable> {
323
+ const [seedSymbolsTable, liquidDrops, graphqlSchema, rootUri, objectMap, filtersMap] =
324
+ await Promise.all([
325
+ this.seedSymbolsTable(uri),
326
+ this.themeDocset.liquidDrops(),
327
+ this.getGraphQLSchema(),
328
+ this.findThemeRootURI?.(uri) ?? null,
329
+ this.objectMap(uri, partialAst),
330
+ this.filtersMap(),
331
+ ]);
332
+ return await buildSymbolsTable(
333
+ partialAst,
334
+ seedSymbolsTable,
335
+ liquidDrops,
336
+ graphqlSchema,
337
+ this.fs,
338
+ this.documentsLocator,
339
+ rootUri ?? undefined,
340
+ undefined, // processingFiles
341
+ objectMap,
342
+ filtersMap,
343
+ );
344
+ }
345
+
346
+ /**
347
+ * The seedSymbolsTable contains all the global variables.
348
+ *
349
+ * This lets us have the ambient type of things first, but if someone
350
+ * reassigns product, then we'll be able to change the type of product on
351
+ * the appropriate range.
352
+ *
353
+ * This is not memo'ed because we would otherwise need to clone the thing.
354
+ */
355
+ private seedSymbolsTable = async (uri: string) => {
356
+ const [globalVariables, contextualVariables] = await Promise.all([
357
+ this.globalVariables(),
358
+ this.contextualVariables(uri),
359
+ ]);
360
+ return globalVariables.concat(contextualVariables).reduce((table, objectEntry) => {
361
+ table[objectEntry.name] ??= [];
362
+ table[objectEntry.name].push({
363
+ identifier: objectEntry.name,
364
+ type: objectEntryType(objectEntry),
365
+ range: [0],
366
+ });
367
+ return table;
368
+ }, {} as SymbolsTable);
369
+ };
370
+
371
+ private globalVariables = memo(async () => {
372
+ const entries = await this.objectEntries();
373
+ return entries.filter(
374
+ (entry) => !entry.access || entry.access.global === true || entry.access.template.length > 0,
375
+ );
376
+ });
377
+
378
+ private contextualVariables = async (uri: string) => {
379
+ const entries = await this.objectEntries();
380
+ const contextualEntries = getContextualEntries(uri);
381
+ return entries.filter((entry) => contextualEntries.includes(entry.name));
382
+ };
383
+ }
384
+
385
+ const SECTION_FILE_REGEX = /sections[\/\\][^.\\\/]*\.liquid$/;
386
+ const BLOCK_FILE_REGEX = /blocks[\/\\][^.\\\/]*\.liquid$/;
387
+ const PARTIAL_FILE_REGEX = /(views[\/\\]partials[\/\\]|[\/\\]lib[\/\\])[^.]*\.liquid$/;
388
+ const LAYOUT_FILE_REGEX = /layout[\/\\]checkout\.liquid$/;
389
+
390
+ function getContextualEntries(uri: string): string[] {
391
+ 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
+ if (PARTIAL_FILE_REGEX.test(normalizedUri)) {
416
+ return ['app'];
417
+ }
418
+ return [];
419
+ }
420
+
421
+ /** An indexed representation on objects.json (by name) */
422
+ type ObjectMap = Record<ObjectEntryName, ObjectEntry>;
423
+
424
+ /** An indexed representation on filters.json (by name) */
425
+ type FiltersMap = Record<FilterEntryName, FilterEntry>;
426
+
427
+ /** An identifier refers to the name of a variable, e.g. `x`, `product`, etc. */
428
+ type Identifier = string;
429
+
430
+ type ObjectEntryName = ObjectEntry['name'];
431
+ type FilterEntryName = FilterEntry['name'];
432
+
433
+ /** Untyped is for declared variables without a type (like `any`) */
434
+ export const Untyped = 'untyped' as const;
435
+ export type Untyped = typeof Untyped;
436
+
437
+ /** Unknown is for variables that don't exist, type would come from context (e.g. snippet var without LiquidDoc) */
438
+ export const Unknown = 'unknown' as const;
439
+ export type Unknown = typeof Untyped;
440
+
441
+ const String = 'string' as const;
442
+ type String = typeof String;
443
+
444
+ /** A pseudo-type is the possible values of an ObjectEntry's return_type.type */
445
+ export type PseudoType = ObjectEntryName | String | Untyped | Unknown | 'number' | 'boolean';
446
+
447
+ /**
448
+ * A variable can have many types in the same file
449
+ *
450
+ * Just think of this:
451
+ *
452
+ * {{ x }} # unknown
453
+ * {% assign x = all_products['cool-handle'] %}
454
+ * {{ x }} # product
455
+ * {% assign x = x.featured_image %}
456
+ * {{ x }} # image
457
+ * [% assign x = x.src %}]
458
+ * {{ x }} # string
459
+ */
460
+ interface TypeRange {
461
+ /** The name of the variable */
462
+ identifier: Identifier;
463
+
464
+ /** The type of the variable */
465
+ type:
466
+ | PseudoType
467
+ | ArrayType
468
+ | ShapeType
469
+ | UnionType
470
+ | LazyVariableType
471
+ | LazyDeconstructedExpression;
472
+
473
+ /**
474
+ * The range may be one of two things:
475
+ * - open ended (till end of file, end === undefined)
476
+ * - closed (inside for loop)
477
+ */
478
+ range: [start: number, end?: number];
479
+ }
480
+
481
+ /** Some things can be an array type (e.g. product.images) */
482
+ export type ArrayType = {
483
+ kind: 'array';
484
+ valueType: PseudoType;
485
+ };
486
+ const arrayType = (valueType: PseudoType): ArrayType => ({
487
+ kind: 'array',
488
+ valueType,
489
+ });
490
+
491
+ /** ShapeType represents inferred types from parse_json, graphql, hash_assign */
492
+ export type ShapeType = {
493
+ kind: 'shape';
494
+ shape: PropertyShape;
495
+ };
496
+ const shapeType = (shape: PropertyShape): ShapeType => ({
497
+ kind: 'shape',
498
+ shape,
499
+ });
500
+
501
+ /** UnionType represents multiple possible types (e.g., from conditional returns) */
502
+ export type UnionType = {
503
+ kind: 'union';
504
+ types: (PseudoType | ArrayType | ShapeType)[];
505
+ };
506
+ const unionType = (types: (PseudoType | ArrayType | ShapeType)[]): UnionType => ({
507
+ kind: 'union',
508
+ types,
509
+ });
510
+
511
+ /**
512
+ * Because a type may depend on another, this represents the type of
513
+ * something as the type of a LiquidVariable chain.
514
+ * {% assign x = y.foo | filter1 | filter2 %}
515
+ */
516
+ type LazyVariableType = {
517
+ kind: NodeTypes.LiquidVariable;
518
+ node: LiquidVariable;
519
+ offset: number;
520
+ };
521
+ const lazyVariable = (node: LiquidVariable, offset: number): LazyVariableType => ({
522
+ kind: NodeTypes.LiquidVariable,
523
+ node,
524
+ offset,
525
+ });
526
+
527
+ /**
528
+ * A thing may be the deconstruction of something else.
529
+ *
530
+ * examples
531
+ * - for thing in (0..2)
532
+ * - for thing in collection
533
+ * - for thing in parent.collection
534
+ * - for thing in 'string?'
535
+ */
536
+ type LazyDeconstructedExpression = {
537
+ kind: 'deconstructed';
538
+ node: LiquidExpression;
539
+ offset: number;
540
+ };
541
+ const LazyDeconstructedExpression = (
542
+ node: LiquidExpression,
543
+ offset: number,
544
+ ): LazyDeconstructedExpression => ({
545
+ kind: 'deconstructed',
546
+ node,
547
+ offset,
548
+ });
549
+
550
+ /**
551
+ * A symbols table is a map of identifiers to TypeRanges.
552
+ *
553
+ * It stores the mapping of variable name to type by position in the file.
554
+ *
555
+ * The ranges are sorted in range.start order.
556
+ */
557
+ type SymbolsTable = Record<Identifier, TypeRange[]>;
558
+
559
+ async function buildSymbolsTable(
560
+ partialAst: LiquidHtmlNode,
561
+ seedSymbolsTable: SymbolsTable,
562
+ liquidDrops: ObjectEntry[],
563
+ graphqlSchema?: string,
564
+ fs?: AbstractFileSystem,
565
+ documentsLocator?: DocumentsLocator,
566
+ rootUri?: string,
567
+ processingFiles?: Set<string>,
568
+ objectMap?: ObjectMap,
569
+ filtersMap?: FiltersMap,
570
+ ): Promise<SymbolsTable> {
571
+ // Track shapes for hash_assign merging
572
+ const variableShapes: Map<string, { shape: PropertyShape; rangeEnd: number }[]> = new Map();
573
+
574
+ const typeRanges = await visit<SourceCodeType.LiquidHtml, TypeRange | TypeRange[]>(partialAst, {
575
+ // {% assign x = foo.x | filter %}
576
+ // {% assign x = '{"a": 1}' | parse_json %}
577
+ 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
+ );
582
+
583
+ if (hasParseJsonFilter) {
584
+ let jsonString: string | undefined;
585
+
586
+ // Check if expression is a direct JSON string
587
+ if (node.value.expression.type === NodeTypes.String) {
588
+ jsonString = node.value.expression.value;
589
+ }
590
+
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;
600
+ }
601
+ }
602
+ }
603
+
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 });
612
+
613
+ return {
614
+ identifier: node.name,
615
+ type: shapeType(shape),
616
+ range: [node.position.end],
617
+ };
618
+ }
619
+ }
620
+ }
621
+
622
+ return {
623
+ identifier: node.name,
624
+ type: lazyVariable(node.value, node.position.start),
625
+ range: [node.position.end],
626
+ };
627
+ },
628
+
629
+ // {% doc %}
630
+ // @param {string} name - your name
631
+ // {% enddoc %}
632
+ async LiquidDocParamNode(node) {
633
+ return {
634
+ identifier: node.paramName.value,
635
+ type: inferLiquidDocParamType(node, liquidDrops),
636
+ range: [node.position.end],
637
+ };
638
+ },
639
+
640
+ // This also covers tablerow
641
+ async ForMarkup(node, ancestors) {
642
+ const parentNode = ancestors.at(-1)! as LiquidTag;
643
+ return {
644
+ identifier: node.variableName,
645
+ type: LazyDeconstructedExpression(node.collection, node.position.start),
646
+ range: [parentNode.blockStartPosition.end, end(parentNode.blockEndPosition?.end)],
647
+ };
648
+ },
649
+
650
+ // {% capture foo %}
651
+ // ...
652
+ // {% endcapture}
653
+ async LiquidTag(node) {
654
+ if (node.name === 'capture' && typeof node.markup !== 'string') {
655
+ return {
656
+ identifier: node.markup.name!,
657
+ type: String,
658
+ range: [node.position.end],
659
+ };
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
+ } else if (['for', 'tablerow'].includes(node.name)) {
667
+ return {
668
+ identifier: node.name + 'loop',
669
+ type: node.name + 'loop',
670
+ range: [node.blockStartPosition.end, end(node.blockEndPosition?.end)],
671
+ };
672
+ } else if (isLiquidTagIncrement(node) || isLiquidTagDecrement(node)) {
673
+ if (node.markup.name === null) return;
674
+ return {
675
+ identifier: node.markup.name,
676
+ type: 'number',
677
+ range: [node.position.start],
678
+ };
679
+ } else if (node.name === 'layout') {
680
+ return {
681
+ identifier: 'none',
682
+ type: 'keyword',
683
+ range: [node.position.start, node.position.end],
684
+ };
685
+ }
686
+ // {% parse_json x %}{"a": 1}{% endparse_json %}
687
+ else if (isLiquidTagParseJson(node)) {
688
+ const variableName = node.markup.name;
689
+ if (variableName && node.children) {
690
+ const textContent = node.children
691
+ .filter((c): c is TextNode => c.type === NodeTypes.TextNode)
692
+ .map((c) => c.value)
693
+ .join('');
694
+ const shape = inferShapeFromJSONString(textContent);
695
+ if (shape) {
696
+ // Track shape for potential hash_assign merging
697
+ if (!variableShapes.has(variableName)) {
698
+ variableShapes.set(variableName, []);
699
+ }
700
+ variableShapes.get(variableName)!.push({
701
+ shape,
702
+ rangeEnd: node.blockEndPosition?.end ?? node.position.end,
703
+ });
704
+
705
+ return {
706
+ identifier: variableName,
707
+ type: shapeType(shape),
708
+ range: [node.blockEndPosition?.end ?? node.position.end],
709
+ };
710
+ }
711
+ }
712
+ }
713
+ // {% graphql result %}...{% endgraphql %} (inline)
714
+ else if (isLiquidTagGraphQL(node) && isGraphQLInlineMarkup(node.markup)) {
715
+ const markup = node.markup;
716
+ if (node.children) {
717
+ const textContent = node.children
718
+ .filter((c): c is TextNode => c.type === NodeTypes.TextNode)
719
+ .map((c) => c.value)
720
+ .join('');
721
+ const shape = inferShapeFromGraphQL(textContent, graphqlSchema);
722
+ if (shape) {
723
+ // Track shape for potential hash_assign merging
724
+ if (!variableShapes.has(markup.name)) {
725
+ variableShapes.set(markup.name, []);
726
+ }
727
+ variableShapes.get(markup.name)!.push({
728
+ shape,
729
+ rangeEnd: node.blockEndPosition?.end ?? node.position.end,
730
+ });
731
+
732
+ return {
733
+ identifier: markup.name,
734
+ type: shapeType(shape),
735
+ range: [node.blockEndPosition?.end ?? node.position.end],
736
+ };
737
+ }
738
+ }
739
+ }
740
+ // {% graphql result = 'file' %} (file-based)
741
+ else if (isLiquidTagGraphQL(node) && isGraphQLFileMarkup(node.markup)) {
742
+ const markup = node.markup;
743
+ if (fs && documentsLocator && rootUri && isLiquidString(markup.graphql)) {
744
+ const graphqlFile = markup.graphql.value;
745
+ try {
746
+ const located = await documentsLocator.locate(
747
+ URI.parse(rootUri),
748
+ 'graphql',
749
+ graphqlFile,
750
+ );
751
+ if (located) {
752
+ const content = await fs.readFile(located);
753
+ const shape = inferShapeFromGraphQL(content, graphqlSchema);
754
+ if (shape) {
755
+ // Track shape for potential hash_assign merging
756
+ if (!variableShapes.has(markup.name)) {
757
+ variableShapes.set(markup.name, []);
758
+ }
759
+ variableShapes.get(markup.name)!.push({
760
+ shape,
761
+ rangeEnd: node.position.end,
762
+ });
763
+
764
+ return {
765
+ identifier: markup.name,
766
+ type: shapeType(shape),
767
+ range: [node.position.end],
768
+ };
769
+ }
770
+ }
771
+ } catch {
772
+ // File read error - skip
773
+ }
774
+ }
775
+ }
776
+ // {% hash_assign x['key'] = value %}
777
+ else if (isLiquidTagHashAssign(node)) {
778
+ const markup = node.markup;
779
+ const variableName = markup.target.name;
780
+ if (!variableName) return;
781
+
782
+ const lookupPath = getHashAssignLookupPath(markup);
783
+
784
+ // Determine value shape - check if value is a JSON string with parse_json filter
785
+ let valueShape: PropertyShape | undefined;
786
+ if (markup.value.expression.type === NodeTypes.String) {
787
+ const hasParseJsonFilter = markup.value.filters.some(
788
+ (f) => f.name === 'parse_json' || f.name === 'to_hash',
789
+ );
790
+ if (hasParseJsonFilter) {
791
+ valueShape = inferShapeFromJSONString(markup.value.expression.value) ?? undefined;
792
+ }
793
+ }
794
+
795
+ // Check for existing type - first in variableShapes, then in seedSymbolsTable
796
+ const existingShapes = variableShapes.get(variableName) || [];
797
+ const existingShapeEntry = findLastApplicableShape(existingShapes, node.position.start);
798
+
799
+ // Check seedSymbolsTable for existing type if not in variableShapes
800
+ let existingType: PseudoType | ArrayType | ShapeType | UnionType | undefined;
801
+ if (!existingShapeEntry && seedSymbolsTable[variableName]) {
802
+ const typeRanges = seedSymbolsTable[variableName];
803
+ // Find the most recent type before this position
804
+ for (const tr of typeRanges) {
805
+ if (tr.range[0] < node.position.start) {
806
+ // Resolve lazy types
807
+ if (typeof tr.type === 'string') {
808
+ existingType = tr.type;
809
+ } else if (
810
+ tr.type.kind === 'shape' ||
811
+ tr.type.kind === 'array' ||
812
+ tr.type.kind === 'union'
813
+ ) {
814
+ existingType = tr.type;
815
+ }
816
+ }
817
+ }
818
+ }
819
+
820
+ // Check if hash_assign is being applied to a non-object type (error case)
821
+ const nonObjectTypes = ['number', 'string', 'boolean'];
822
+ if (!existingShapeEntry && existingType) {
823
+ if (typeof existingType === 'string' && nonObjectTypes.includes(existingType)) {
824
+ // Can't hash_assign to a primitive - this is an error
825
+ // Return undefined to not change the type (let a check rule report the error)
826
+ return;
827
+ }
828
+ if (isArrayType(existingType)) {
829
+ // Can't hash_assign to an array - this is an error
830
+ return;
831
+ }
832
+ }
833
+
834
+ if (lookupPath && lookupPath.length > 0) {
835
+ // Nested property assignment: {% hash_assign a['key'] = value %}
836
+ let baseShape: PropertyShape;
837
+ if (existingShapeEntry) {
838
+ baseShape = existingShapeEntry.shape;
839
+ } else if (existingType && isShapeType(existingType)) {
840
+ baseShape = existingType.shape;
841
+ } else {
842
+ baseShape = { kind: 'object', properties: new Map() };
843
+ }
844
+
845
+ const newShape = mergeNestedPropertyIntoShape(
846
+ baseShape,
847
+ lookupPath,
848
+ valueShape ?? { kind: 'primitive' },
849
+ );
850
+
851
+ // Track the new shape
852
+ if (!variableShapes.has(variableName)) {
853
+ variableShapes.set(variableName, []);
854
+ }
855
+ variableShapes.get(variableName)!.push({ shape: newShape, rangeEnd: node.position.end });
856
+
857
+ return {
858
+ identifier: variableName,
859
+ type: shapeType(newShape),
860
+ range: [node.position.end],
861
+ };
862
+ } else if (valueShape) {
863
+ // Direct assignment: {% hash_assign a = value %} (works like assign)
864
+ if (!variableShapes.has(variableName)) {
865
+ variableShapes.set(variableName, []);
866
+ }
867
+ variableShapes
868
+ .get(variableName)!
869
+ .push({ shape: valueShape, rangeEnd: node.position.end });
870
+
871
+ return {
872
+ identifier: variableName,
873
+ type: shapeType(valueShape),
874
+ range: [node.position.end],
875
+ };
876
+ }
877
+ }
878
+ // {% function result = 'partial/path', args... %}
879
+ else if (isLiquidTagFunction(node)) {
880
+ const markup = node.markup;
881
+ let returnType: PseudoType | ArrayType | ShapeType | UnionType | undefined;
882
+ if (
883
+ fs &&
884
+ documentsLocator &&
885
+ rootUri &&
886
+ objectMap &&
887
+ filtersMap &&
888
+ isLiquidString(markup.partial)
889
+ ) {
890
+ const partialPath = markup.partial.value;
891
+ try {
892
+ returnType = await inferFunctionReturnType(
893
+ partialPath,
894
+ fs,
895
+ documentsLocator,
896
+ rootUri,
897
+ seedSymbolsTable,
898
+ liquidDrops,
899
+ graphqlSchema,
900
+ processingFiles,
901
+ objectMap,
902
+ filtersMap,
903
+ );
904
+ } catch {
905
+ // File read/parse error - returnType stays undefined
906
+ }
907
+ }
908
+
909
+ // Track shape for potential hash_assign merging
910
+ if (returnType && isShapeType(returnType)) {
911
+ if (!variableShapes.has(markup.name)) {
912
+ variableShapes.set(markup.name, []);
913
+ }
914
+ variableShapes.get(markup.name)!.push({
915
+ shape: returnType.shape,
916
+ rangeEnd: node.position.end,
917
+ });
918
+ }
919
+
920
+ // Always add function variable to symbolsTable, using Untyped as fallback
921
+ return {
922
+ identifier: markup.name,
923
+ type: returnType ?? Untyped,
924
+ range: [node.position.end],
925
+ };
926
+ }
927
+ },
928
+ });
929
+
930
+ // Flatten array results (some visitors return TypeRange[])
931
+ const flattenedRanges = typeRanges.flat();
932
+
933
+ return flattenedRanges
934
+ .sort(({ range: [startA] }, { range: [startB] }) => startA - startB)
935
+ .reduce((table, typeRange) => {
936
+ table[typeRange.identifier] ??= [];
937
+ table[typeRange.identifier].push(typeRange);
938
+ return table;
939
+ }, seedSymbolsTable);
940
+ }
941
+
942
+ /**
943
+ * Given a TypeRange['type'] (which may be lazy), resolve its type recursively.
944
+ *
945
+ * The output is a fully resolved PseudoType | ArrayType | ShapeType. Which means we
946
+ * could use it to power completions.
947
+ */
948
+ function resolveTypeRangeType(
949
+ typeRangeType: TypeRange['type'],
950
+ symbolsTable: SymbolsTable,
951
+ objectMap: ObjectMap,
952
+ filtersMap: FiltersMap,
953
+ ): PseudoType | ArrayType | ShapeType | UnionType {
954
+ if (typeof typeRangeType === 'string') {
955
+ return typeRangeType;
956
+ }
957
+
958
+ switch (typeRangeType.kind) {
959
+ case 'array': {
960
+ return typeRangeType;
961
+ }
962
+
963
+ case 'shape': {
964
+ return typeRangeType;
965
+ }
966
+
967
+ case 'union': {
968
+ return typeRangeType;
969
+ }
970
+
971
+ case 'deconstructed': {
972
+ const deconstructedType = inferType(typeRangeType.node, symbolsTable, objectMap, filtersMap);
973
+ if (typeof deconstructedType === 'string') {
974
+ return Untyped;
975
+ } else if (isShapeType(deconstructedType)) {
976
+ // Deconstruct shape array
977
+ if (deconstructedType.shape.kind === 'array' && deconstructedType.shape.itemShape) {
978
+ return shapeType(deconstructedType.shape.itemShape);
979
+ }
980
+ return Untyped;
981
+ } else if (isUnionType(deconstructedType)) {
982
+ return Untyped;
983
+ } else {
984
+ return deconstructedType.valueType;
985
+ }
986
+ }
987
+
988
+ default: {
989
+ return inferType(typeRangeType.node, symbolsTable, objectMap, filtersMap);
990
+ }
991
+ }
992
+ }
993
+
994
+ function inferType(
995
+ thing: Identifier | ComplexLiquidExpression | LiquidVariable | AssignMarkup,
996
+ symbolsTable: SymbolsTable,
997
+ objectMap: ObjectMap,
998
+ filtersMap: FiltersMap,
999
+ ): PseudoType | ArrayType | ShapeType | UnionType {
1000
+ if (typeof thing === 'string') {
1001
+ return objectMap[thing as PseudoType]?.name ?? Untyped;
1002
+ }
1003
+
1004
+ switch (thing.type) {
1005
+ case NodeTypes.Number: {
1006
+ return 'number';
1007
+ }
1008
+
1009
+ case NodeTypes.String: {
1010
+ return 'string';
1011
+ }
1012
+
1013
+ case NodeTypes.LiquidLiteral: {
1014
+ return 'boolean';
1015
+ }
1016
+
1017
+ case NodeTypes.BooleanExpression: {
1018
+ return 'boolean';
1019
+ }
1020
+
1021
+ case NodeTypes.Range: {
1022
+ return arrayType('number');
1023
+ }
1024
+
1025
+ // The type of the assign markup is the type of the right hand side.
1026
+ // {% assign x = y.property | filter1 | filter2 %}
1027
+ case NodeTypes.AssignMarkup: {
1028
+ return inferType(thing.value, symbolsTable, objectMap, filtersMap);
1029
+ }
1030
+
1031
+ // A variable lookup is expression[.lookup]*
1032
+ // {{ y.property }}
1033
+ case NodeTypes.VariableLookup: {
1034
+ return inferLookupType(thing, symbolsTable, objectMap, filtersMap);
1035
+ }
1036
+
1037
+ // A variable is the VariableLookup + Filters
1038
+ // The type is the return value of the last filter
1039
+ // {{ y.property | filter1 | filter2 }}
1040
+ case NodeTypes.LiquidVariable: {
1041
+ if (thing.filters.length > 0) {
1042
+ const lastFilter = thing.filters.at(-1)!;
1043
+ if (lastFilter.name === 'default') {
1044
+ // default filter is a special case, we need to return the type of the expression
1045
+ // instead of the filter.
1046
+ if (lastFilter.args.length > 0 && lastFilter.args[0].type !== NodeTypes.NamedArgument) {
1047
+ return inferType(lastFilter.args[0], symbolsTable, objectMap, filtersMap);
1048
+ }
1049
+ }
1050
+ const filterEntry = filtersMap[lastFilter.name];
1051
+ return filterEntry ? filterEntryReturnType(filterEntry) : Untyped;
1052
+ } else {
1053
+ return inferType(thing.expression, symbolsTable, objectMap, filtersMap);
1054
+ }
1055
+ }
1056
+
1057
+ default: {
1058
+ return Untyped;
1059
+ }
1060
+ }
1061
+ }
1062
+
1063
+ function inferLiquidDocParamType(node: LiquidDocParamNode, liquidDrops: ObjectEntry[]) {
1064
+ const paramTypeValue = node.paramType?.value;
1065
+
1066
+ if (!paramTypeValue) return Untyped;
1067
+
1068
+ const validParamTypes = getValidParamTypes(liquidDrops);
1069
+
1070
+ const parsedParamType = parseParamType(new Set(validParamTypes.keys()), paramTypeValue);
1071
+
1072
+ if (!parsedParamType) return Untyped;
1073
+
1074
+ const [type, isArray] = parsedParamType;
1075
+
1076
+ let transformedParamType;
1077
+
1078
+ // BasicParamTypes.Object does not map to any specific type in the type system.
1079
+ if (type === BasicParamTypes.Object) {
1080
+ transformedParamType = Untyped;
1081
+ } else {
1082
+ transformedParamType = type;
1083
+ }
1084
+
1085
+ if (isArray) {
1086
+ return arrayType(transformedParamType);
1087
+ }
1088
+
1089
+ return transformedParamType;
1090
+ }
1091
+
1092
+ function inferLookupType(
1093
+ thing: LiquidVariableLookup,
1094
+ symbolsTable: SymbolsTable,
1095
+ objectMap: ObjectMap,
1096
+ filtersMap: FiltersMap,
1097
+ ): PseudoType | ArrayType | ShapeType | UnionType {
1098
+ // we return the type of the drop, so a.b.c
1099
+ const node = thing;
1100
+
1101
+ // We don't complete global lookups. It's too much of an edge case.
1102
+ if (node.name === null) return Untyped;
1103
+
1104
+ /**
1105
+ * curr stores the type of the variable lookup starting at the beginning.
1106
+ *
1107
+ * It starts as the type of the top-level identifier, and the we
1108
+ * recursively change it to the return type of the lookups.
1109
+ *
1110
+ * So, for x.images.first.src we do:
1111
+ * - curr = infer type of x | x
1112
+ * - curr = x.images -> ArrayType<image> | x.images
1113
+ * - curr = images.first -> image | x.images.first
1114
+ * - curr = first.src -> string | x.images.first.src
1115
+ *
1116
+ * Once were done iterating, the type of the lookup is curr.
1117
+ */
1118
+ let curr: PseudoType | ArrayType | ShapeType | UnionType = inferIdentifierType(
1119
+ node,
1120
+ symbolsTable,
1121
+ objectMap,
1122
+ filtersMap,
1123
+ );
1124
+
1125
+ for (let lookup of node.lookups) {
1126
+ // Here we redefine curr to be the returnType of the lookup.
1127
+
1128
+ // e.g. images[0] -> image
1129
+ // e.g. images.first -> image
1130
+ // e.g. images.size -> number
1131
+ if (isArrayType(curr)) {
1132
+ curr = inferArrayTypeLookupType(curr, lookup);
1133
+ }
1134
+
1135
+ // Handle ShapeType from parse_json, graphql, hash_assign
1136
+ else if (isShapeType(curr)) {
1137
+ curr = inferShapeTypeLookupType(curr, lookup);
1138
+ }
1139
+
1140
+ // Handle UnionType - for now, treat as Untyped for lookups
1141
+ else if (isUnionType(curr)) {
1142
+ return Untyped;
1143
+ }
1144
+
1145
+ // e.g. product.featured_image -> image
1146
+ // e.g. product.images -> ArrayType<images>
1147
+ // e.g. product.name -> string
1148
+ else {
1149
+ curr = inferPseudoTypePropertyType(curr, lookup, objectMap);
1150
+ }
1151
+
1152
+ // Early return
1153
+ if (curr === Untyped) {
1154
+ return Untyped;
1155
+ }
1156
+ }
1157
+
1158
+ return curr;
1159
+ }
1160
+
1161
+ /**
1162
+ * Given a VariableLookup node, infer the type of its root (position-relative).
1163
+ *
1164
+ * e.g. for the following
1165
+ * {% assign x = product %}
1166
+ * {{ x.images.first }}
1167
+ *
1168
+ * This function infers the type of `x`.
1169
+ */
1170
+ function inferIdentifierType(
1171
+ node: LiquidVariableLookup,
1172
+ symbolsTable: SymbolsTable,
1173
+ objectMap: ObjectMap,
1174
+ filtersMap: FiltersMap,
1175
+ ): PseudoType | ArrayType | ShapeType | UnionType {
1176
+ // The name of a variable
1177
+ const identifier = node.name;
1178
+
1179
+ // We don't complete the global access edge case
1180
+ // e.g. {{ ['all_products'] }}
1181
+ if (!identifier) {
1182
+ return Untyped;
1183
+ }
1184
+
1185
+ const typeRanges = symbolsTable[identifier];
1186
+ if (!typeRanges) {
1187
+ return Unknown;
1188
+ }
1189
+
1190
+ const typeRange = findLast(typeRanges, (tr) => isCorrectTypeRange(tr, node));
1191
+
1192
+ return typeRange
1193
+ ? resolveTypeRangeType(typeRange.type, symbolsTable, objectMap, filtersMap)
1194
+ : Unknown;
1195
+ }
1196
+
1197
+ /**
1198
+ * infers the type of a lookup on an ArrayType
1199
+ * - images[0] becomes 'image'
1200
+ * - images[index] becomes 'image'
1201
+ * - images.first becomes 'image'
1202
+ * - images.last becomes 'image'
1203
+ * - images.size becomes 'number'
1204
+ * - anything else becomes 'untyped'
1205
+ */
1206
+ function inferArrayTypeLookupType(curr: ArrayType, lookup: LiquidExpression) {
1207
+ // images[0]
1208
+ // images[index]
1209
+ if (lookup.type === NodeTypes.Number || lookup.type === NodeTypes.VariableLookup) {
1210
+ return curr.valueType;
1211
+ }
1212
+ // images.first
1213
+ // images.last
1214
+ // images.size
1215
+ // anything else is undef
1216
+ else if (lookup.type === NodeTypes.String) {
1217
+ switch (lookup.value) {
1218
+ case 'first':
1219
+ case 'last': {
1220
+ return curr.valueType;
1221
+ }
1222
+
1223
+ case 'size': {
1224
+ return 'number';
1225
+ }
1226
+
1227
+ default: {
1228
+ return Unknown;
1229
+ }
1230
+ }
1231
+ }
1232
+ // images[true]
1233
+ // images[(0..2)]
1234
+ else {
1235
+ return Untyped;
1236
+ }
1237
+ }
1238
+
1239
+ /**
1240
+ * Infers the type of a lookup on a ShapeType (from parse_json, graphql, hash_assign)
1241
+ */
1242
+ function inferShapeTypeLookupType(
1243
+ curr: ShapeType,
1244
+ lookup: LiquidExpression,
1245
+ ): PseudoType | ArrayType | ShapeType {
1246
+ const shape = curr.shape;
1247
+
1248
+ // Handle array shape lookups
1249
+ if (shape.kind === 'array') {
1250
+ // array[0] or array[variable] -> item type
1251
+ if (lookup.type === NodeTypes.Number || lookup.type === NodeTypes.VariableLookup) {
1252
+ if (shape.itemShape) {
1253
+ return shapeToType(shape.itemShape);
1254
+ }
1255
+ return Untyped;
1256
+ }
1257
+
1258
+ // array.first, array.last, array.size
1259
+ if (lookup.type === NodeTypes.String) {
1260
+ switch (lookup.value) {
1261
+ case 'first':
1262
+ case 'last':
1263
+ if (shape.itemShape) {
1264
+ return shapeToType(shape.itemShape);
1265
+ }
1266
+ return Untyped;
1267
+ case 'size':
1268
+ return 'number';
1269
+ default:
1270
+ return Unknown;
1271
+ }
1272
+ }
1273
+
1274
+ return Untyped;
1275
+ }
1276
+
1277
+ // Handle object shape lookups
1278
+ if (shape.kind === 'object') {
1279
+ // Object lookups must be strings
1280
+ if (lookup.type !== NodeTypes.String) {
1281
+ return Untyped;
1282
+ }
1283
+
1284
+ const propertyName = lookup.value;
1285
+ const propertyShape = shape.properties?.get(propertyName);
1286
+
1287
+ if (propertyShape) {
1288
+ return shapeToType(propertyShape);
1289
+ }
1290
+
1291
+ return Unknown;
1292
+ }
1293
+
1294
+ // Primitive shapes don't support lookups (except string.size, string.first, string.last)
1295
+ if (shape.kind === 'primitive') {
1296
+ if (shape.primitiveType === 'string' && lookup.type === NodeTypes.String) {
1297
+ switch (lookup.value) {
1298
+ case 'first':
1299
+ case 'last':
1300
+ return 'string';
1301
+ case 'size':
1302
+ return 'number';
1303
+ default:
1304
+ return Unknown;
1305
+ }
1306
+ }
1307
+ return Unknown;
1308
+ }
1309
+
1310
+ return Untyped;
1311
+ }
1312
+
1313
+ /**
1314
+ * Convert a PropertyShape to a PseudoType, ArrayType, or ShapeType
1315
+ */
1316
+ function shapeToType(shape: PropertyShape): PseudoType | ArrayType | ShapeType {
1317
+ if (shape.kind === 'primitive') {
1318
+ switch (shape.primitiveType) {
1319
+ case 'string':
1320
+ return 'string';
1321
+ case 'number':
1322
+ return 'number';
1323
+ case 'boolean':
1324
+ return 'boolean';
1325
+ default:
1326
+ return Untyped;
1327
+ }
1328
+ }
1329
+
1330
+ if (shape.kind === 'array') {
1331
+ // If array items are primitives, return ArrayType
1332
+ if (shape.itemShape?.kind === 'primitive') {
1333
+ const primitiveType = shape.itemShape.primitiveType;
1334
+ if (primitiveType === 'string' || primitiveType === 'number' || primitiveType === 'boolean') {
1335
+ return arrayType(primitiveType);
1336
+ }
1337
+ }
1338
+ // Otherwise return ShapeType to preserve nested structure
1339
+ return shapeType(shape);
1340
+ }
1341
+
1342
+ if (shape.kind === 'object') {
1343
+ return shapeType(shape);
1344
+ }
1345
+
1346
+ return Untyped;
1347
+ }
1348
+
1349
+ function inferPseudoTypePropertyType(
1350
+ curr: PseudoType, // settings
1351
+ lookup: LiquidExpression,
1352
+ objectMap: ObjectMap,
1353
+ ) {
1354
+ const parentEntry: ObjectEntry | undefined = objectMap[curr];
1355
+
1356
+ // When doing a non string lookup, we don't really know the type. e.g.
1357
+ // products[0]
1358
+ // products[true]
1359
+ // products[(0..10)]
1360
+ if (lookup.type !== NodeTypes.String) {
1361
+ return Untyped;
1362
+ }
1363
+
1364
+ // When we don't have docs for the parent entry
1365
+ if (!parentEntry) {
1366
+ // It might be that the parent entry is a string.
1367
+ // We do support a couple of properties for those
1368
+ if (curr === 'string') {
1369
+ switch (lookup.value) {
1370
+ // some_string.first
1371
+ // some_string.last
1372
+ case 'first':
1373
+ case 'last':
1374
+ return 'string';
1375
+
1376
+ // some_string.size
1377
+ case 'size':
1378
+ return 'number';
1379
+
1380
+ default: {
1381
+ // For the string type, any property access other than first/last/size
1382
+ // is unknown. This is different from an untyped/any object where any
1383
+ // property access would return untyped.
1384
+ // String is a known type with specific properties, so accessing
1385
+ // undefined properties returns an unknown.
1386
+ return Unknown;
1387
+ }
1388
+ }
1389
+ }
1390
+
1391
+ // Or it might be that the parent entry is untyped, so its subproperty
1392
+ // could also be untyped (kind of like if `foo` is `any`, then `foo.bar` is `any`)
1393
+ return Untyped;
1394
+ }
1395
+
1396
+ const propertyName = lookup.value;
1397
+ const property = parentEntry.properties?.find((property) => property.name === propertyName);
1398
+
1399
+ // When the propety is not known, return Untyped. e.g.
1400
+ // product.foo
1401
+ // product.bar
1402
+ if (!property) {
1403
+ // Debating between returning Untyped or Unknown here
1404
+ // Might be that we have outdated docs. Prob better to return Untyped.
1405
+ return Untyped;
1406
+ }
1407
+
1408
+ // When the property is known & we have docs for it, return its type. e.g.
1409
+ // product.image
1410
+ // product.images
1411
+ return objectEntryType(property);
1412
+ }
1413
+
1414
+ function filterEntryReturnType(entry: FilterEntry): PseudoType | ArrayType {
1415
+ return docsetEntryReturnType(entry, 'string');
1416
+ }
1417
+
1418
+ function objectEntryType(entry: ObjectEntry): PseudoType | ArrayType {
1419
+ return docsetEntryReturnType(entry, entry.name);
1420
+ }
1421
+
1422
+ /**
1423
+ * This function converts the return_type property in one of the .json
1424
+ * files into a PseudoType or ArrayType.
1425
+ */
1426
+ export function docsetEntryReturnType(
1427
+ entry: ObjectEntry | FilterEntry,
1428
+ defaultValue: PseudoType,
1429
+ ): PseudoType | ArrayType {
1430
+ const returnTypes = entry.return_type;
1431
+ if (returnTypes && returnTypes.length > 0) {
1432
+ const returnType = returnTypes[0];
1433
+ if (isArrayReturnType(returnType)) {
1434
+ return arrayType(returnType.array_value);
1435
+ } else {
1436
+ return returnType.type;
1437
+ }
1438
+ }
1439
+
1440
+ return defaultValue;
1441
+ }
1442
+
1443
+ function isArrayReturnType(rt: ReturnType): rt is ArrayReturnType {
1444
+ return rt.type === 'array';
1445
+ }
1446
+
1447
+ export function isArrayType(
1448
+ thing: PseudoType | ArrayType | ShapeType | UnionType,
1449
+ ): thing is ArrayType {
1450
+ return typeof thing !== 'string' && thing.kind === 'array';
1451
+ }
1452
+
1453
+ export function isShapeType(
1454
+ thing: PseudoType | ArrayType | ShapeType | UnionType,
1455
+ ): thing is ShapeType {
1456
+ return typeof thing !== 'string' && thing.kind === 'shape';
1457
+ }
1458
+
1459
+ /** Assumes findLast */
1460
+ function isCorrectTypeRange(typeRange: TypeRange, node: LiquidVariableLookup): boolean {
1461
+ const [start, end] = typeRange.range;
1462
+ if (end && node.position.start > end) return false;
1463
+ return node.position.start > start;
1464
+ }
1465
+
1466
+ function end(offset: number | undefined): number | undefined {
1467
+ if (offset === -1) return undefined;
1468
+ return offset;
1469
+ }
1470
+
1471
+ function isLiquidTagIncrement(node: LiquidTag): node is LiquidTagIncrement {
1472
+ return node.name === NamedTags.increment && typeof node.markup !== 'string';
1473
+ }
1474
+
1475
+ function isLiquidTagDecrement(node: LiquidTag): node is LiquidTagDecrement {
1476
+ return node.name === NamedTags.decrement && typeof node.markup !== 'string';
1477
+ }
1478
+
1479
+ function isLiquidTagParseJson(
1480
+ node: LiquidTag,
1481
+ ): node is LiquidTag & { markup: { name: string }; children: LiquidHtmlNode[] } {
1482
+ return node.name === NamedTags.parse_json && typeof node.markup !== 'string';
1483
+ }
1484
+
1485
+ function isLiquidTagGraphQL(
1486
+ node: LiquidTag,
1487
+ ): node is LiquidTag & { markup: GraphQLMarkup | GraphQLInlineMarkup } {
1488
+ return node.name === NamedTags.graphql && typeof node.markup !== 'string';
1489
+ }
1490
+
1491
+ function isGraphQLInlineMarkup(
1492
+ markup: GraphQLMarkup | GraphQLInlineMarkup,
1493
+ ): markup is GraphQLInlineMarkup {
1494
+ return markup.type === NodeTypes.GraphQLInlineMarkup;
1495
+ }
1496
+
1497
+ function isGraphQLFileMarkup(markup: GraphQLMarkup | GraphQLInlineMarkup): markup is GraphQLMarkup {
1498
+ return markup.type === NodeTypes.GraphQLMarkup;
1499
+ }
1500
+
1501
+ function isLiquidString(node: LiquidString | LiquidVariableLookup): node is LiquidString {
1502
+ return node.type === NodeTypes.String;
1503
+ }
1504
+
1505
+ function isLiquidTagHashAssign(node: LiquidTag): node is LiquidTag & { markup: HashAssignMarkup } {
1506
+ return node.name === NamedTags.hash_assign && typeof node.markup !== 'string';
1507
+ }
1508
+
1509
+ function isLiquidTagFunction(node: LiquidTag): node is LiquidTag & { markup: FunctionMarkup } {
1510
+ return node.name === NamedTags.function && typeof node.markup !== 'string';
1511
+ }
1512
+
1513
+ export function isUnionType(
1514
+ thing: PseudoType | ArrayType | ShapeType | UnionType,
1515
+ ): thing is UnionType {
1516
+ return typeof thing !== 'string' && thing.kind === 'union';
1517
+ }
1518
+
1519
+ /**
1520
+ * Infer the return type of a function partial by analyzing its {% return %} statements.
1521
+ */
1522
+ async function inferFunctionReturnType(
1523
+ partialPath: string,
1524
+ fs: AbstractFileSystem,
1525
+ documentsLocator: DocumentsLocator,
1526
+ rootUri: string,
1527
+ seedSymbolsTable: SymbolsTable,
1528
+ liquidDrops: ObjectEntry[],
1529
+ graphqlSchema: string | undefined,
1530
+ processingFiles: Set<string> | undefined,
1531
+ objectMap: ObjectMap,
1532
+ filtersMap: FiltersMap,
1533
+ ): Promise<PseudoType | ArrayType | ShapeType | UnionType | undefined> {
1534
+ // 1. Locate the file
1535
+ const located = await documentsLocator.locate(URI.parse(rootUri), 'function', partialPath);
1536
+ if (!located) return undefined;
1537
+
1538
+ // 2. Check for circular references
1539
+ const trackingSet = processingFiles ?? new Set<string>();
1540
+ if (trackingSet.has(located)) return Untyped;
1541
+ trackingSet.add(located);
1542
+
1543
+ try {
1544
+ // 3. Read and parse the partial
1545
+ const content = await fs.readFile(located);
1546
+ const partialAst = toLiquidHtmlAST(content);
1547
+
1548
+ // 4. Build symbols table for the partial (recursive)
1549
+ const partialSymbolsTable = await buildSymbolsTable(
1550
+ partialAst,
1551
+ { ...seedSymbolsTable }, // Clone to avoid pollution
1552
+ liquidDrops,
1553
+ graphqlSchema,
1554
+ fs,
1555
+ documentsLocator,
1556
+ rootUri,
1557
+ trackingSet,
1558
+ objectMap,
1559
+ filtersMap,
1560
+ );
1561
+
1562
+ // 5. Find all return statements and infer their types
1563
+ const returnTypes: (PseudoType | ArrayType | ShapeType)[] = [];
1564
+
1565
+ await visit<SourceCodeType.LiquidHtml, void>(partialAst, {
1566
+ async LiquidTag(node) {
1567
+ if (node.name === NamedTags.return && typeof node.markup !== 'string') {
1568
+ // markup is LiquidVariable - infer its type
1569
+ const type = inferType(node.markup, partialSymbolsTable, objectMap, filtersMap);
1570
+ // Flatten union types into individual types
1571
+ if (isUnionType(type)) {
1572
+ returnTypes.push(...type.types);
1573
+ } else {
1574
+ returnTypes.push(type);
1575
+ }
1576
+ }
1577
+ },
1578
+ });
1579
+
1580
+ if (returnTypes.length === 0) return undefined;
1581
+ if (returnTypes.length === 1) return returnTypes[0];
1582
+
1583
+ // Dedupe types (same type appearing multiple times)
1584
+ const uniqueTypes = dedupeTypes(returnTypes);
1585
+ if (uniqueTypes.length === 1) return uniqueTypes[0];
1586
+
1587
+ return unionType(uniqueTypes);
1588
+ } finally {
1589
+ trackingSet.delete(located);
1590
+ }
1591
+ }
1592
+
1593
+ /**
1594
+ * Deduplicate types by comparing their structure.
1595
+ */
1596
+ function dedupeTypes(
1597
+ types: (PseudoType | ArrayType | ShapeType)[],
1598
+ ): (PseudoType | ArrayType | ShapeType)[] {
1599
+ const seen = new Set<string>();
1600
+ const result: (PseudoType | ArrayType | ShapeType)[] = [];
1601
+
1602
+ for (const type of types) {
1603
+ const key = typeToKey(type);
1604
+ if (!seen.has(key)) {
1605
+ seen.add(key);
1606
+ result.push(type);
1607
+ }
1608
+ }
1609
+
1610
+ return result;
1611
+ }
1612
+
1613
+ /**
1614
+ * Convert a type to a string key for deduplication.
1615
+ */
1616
+ function typeToKey(type: PseudoType | ArrayType | ShapeType): string {
1617
+ if (typeof type === 'string') return type;
1618
+ if (type.kind === 'array') return `array:${type.valueType}`;
1619
+ if (type.kind === 'shape') return `shape:${JSON.stringify(shapeToSimpleObject(type.shape))}`;
1620
+ return 'unknown';
1621
+ }
1622
+
1623
+ /**
1624
+ * Convert a PropertyShape to a simple object for JSON serialization.
1625
+ */
1626
+ function shapeToSimpleObject(shape: PropertyShape): unknown {
1627
+ if (shape.kind === 'primitive') {
1628
+ return { kind: 'primitive', type: shape.primitiveType };
1629
+ }
1630
+ if (shape.kind === 'array') {
1631
+ return {
1632
+ kind: 'array',
1633
+ itemShape: shape.itemShape ? shapeToSimpleObject(shape.itemShape) : null,
1634
+ };
1635
+ }
1636
+ if (shape.kind === 'object') {
1637
+ const props: Record<string, unknown> = {};
1638
+ if (shape.properties) {
1639
+ for (const [key, value] of shape.properties) {
1640
+ props[key] = shapeToSimpleObject(value);
1641
+ }
1642
+ }
1643
+ return { kind: 'object', properties: props };
1644
+ }
1645
+ return { kind: 'unknown' };
1646
+ }
1647
+
1648
+ /**
1649
+ * Convert a type to a display string for hover/completions.
1650
+ */
1651
+ export function typeToDisplayString(type: PseudoType | ArrayType | ShapeType | UnionType): string {
1652
+ if (typeof type === 'string') return type;
1653
+ if (type.kind === 'array') return `Array<${type.valueType}>`;
1654
+ if (type.kind === 'shape') return shapeToTypeString(type.shape);
1655
+ if (type.kind === 'union') return type.types.map((t) => typeToDisplayString(t)).join(' | ');
1656
+ return 'unknown';
1657
+ }
1658
+
1659
+ /**
1660
+ * Extract the lookup path from a hash_assign target.
1661
+ * For {% hash_assign a['key1']['key2'] = value %}, returns ['key1', 'key2']
1662
+ */
1663
+ function getHashAssignLookupPath(markup: HashAssignMarkup): string[] | undefined {
1664
+ const path: string[] = [];
1665
+
1666
+ for (const lookup of markup.target.lookups) {
1667
+ if (lookup.type === NodeTypes.String) {
1668
+ path.push(lookup.value);
1669
+ } else if (lookup.type === NodeTypes.Number) {
1670
+ path.push(`${lookup.value}`);
1671
+ } else {
1672
+ // Dynamic lookup - can't determine statically
1673
+ return undefined;
1674
+ }
1675
+ }
1676
+
1677
+ return path.length > 0 ? path : undefined;
1678
+ }
1679
+
1680
+ /**
1681
+ * Merge a nested property into a shape following a path.
1682
+ * For path ['a', 'b'] and valueShape, creates/updates shape.a.b = valueShape
1683
+ */
1684
+ function mergeNestedPropertyIntoShape(
1685
+ shape: PropertyShape,
1686
+ path: string[],
1687
+ valueShape: PropertyShape,
1688
+ ): PropertyShape {
1689
+ if (path.length === 0) {
1690
+ return valueShape;
1691
+ }
1692
+
1693
+ const [key, ...rest] = path;
1694
+
1695
+ if (shape.kind !== 'object') {
1696
+ // Convert to object
1697
+ const properties = new Map<string, PropertyShape>();
1698
+ if (rest.length === 0) {
1699
+ properties.set(key, valueShape);
1700
+ } else {
1701
+ properties.set(
1702
+ key,
1703
+ mergeNestedPropertyIntoShape({ kind: 'object', properties: new Map() }, rest, valueShape),
1704
+ );
1705
+ }
1706
+ return { kind: 'object', properties };
1707
+ }
1708
+
1709
+ const newProperties = new Map(shape.properties);
1710
+ if (rest.length === 0) {
1711
+ newProperties.set(key, valueShape);
1712
+ } else {
1713
+ const existingNested = newProperties.get(key) || { kind: 'object', properties: new Map() };
1714
+ newProperties.set(key, mergeNestedPropertyIntoShape(existingNested, rest, valueShape));
1715
+ }
1716
+ return { kind: 'object', properties: newProperties };
1717
+ }
1718
+
1719
+ /**
1720
+ * Find the last applicable shape for a variable at a given position
1721
+ */
1722
+ function findLastApplicableShape(
1723
+ shapes: { shape: PropertyShape; rangeEnd: number }[],
1724
+ position: number,
1725
+ ): { shape: PropertyShape; rangeEnd: number } | undefined {
1726
+ let result: { shape: PropertyShape; rangeEnd: number } | undefined;
1727
+ for (const entry of shapes) {
1728
+ if (entry.rangeEnd < position) {
1729
+ result = entry;
1730
+ }
1731
+ }
1732
+ return result;
1733
+ }
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
+ }