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