@shopify/theme-language-server-common
Version:
<h1 align="center" style="position: relative;" > <br> <img src="https://github.com/Shopify/theme-check-vscode/blob/main/images/shopify_glyph.png?raw=true" alt="logo" width="141" height="160"> <br> Theme Language Server </h1>
118 lines • 5.31 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.findSchemaNode = exports.SchemaTranslationContributions = void 0;
const theme_check_common_1 = require("@shopify/theme-check-common");
const vscode_languageserver_protocol_1 = require("vscode-languageserver-protocol");
const translations_1 = require("../translations");
const visitor_1 = require("../visitor");
const fileMatch_1 = require("./fileMatch");
/**
* This contribution is responsible for providing completions and hover of
* `t:` translations in sections and blocks {% schema %} JSON blobs.
*/
class SchemaTranslationContributions {
constructor(documentManager, getDefaultSchemaTranslations) {
this.documentManager = documentManager;
this.getDefaultSchemaTranslations = getDefaultSchemaTranslations;
this.uriPatterns = [/^.*\/(sections|blocks)\/[^\/]*\.liquid$/];
}
/**
* Because the API for JSONWorkerContribution is slightly weird, we need to
* return undefined (not Promise<undefined>) for this contribution to be
* skipped and fallbacks to go through. It's not typed properly either.
*/
getInfoContribution(uri, location) {
if (!(0, fileMatch_1.uriMatch)(uri, this.uriPatterns))
return undefined;
const doc = this.documentManager.get(uri);
if (!doc ||
location.length === 0 ||
doc.ast instanceof Error ||
doc.type !== theme_check_common_1.SourceCodeType.LiquidHtml) {
return undefined;
}
const schema = findSchemaNode(doc.ast);
if (!schema)
return undefined;
const jsonString = schema.source.slice(schema.blockStartPosition.end, schema.blockEndPosition.start);
const jsonDocument = (0, theme_check_common_1.parseJSON)(jsonString);
if ((0, theme_check_common_1.isError)(jsonDocument))
return undefined;
const label = location.reduce((acc, val) => acc === null || acc === void 0 ? void 0 : acc[val], jsonDocument);
if (!label || typeof label !== 'string' || !label.startsWith('t:'))
return undefined;
return this.getDefaultSchemaTranslations(uri).then((translations) => {
const path = label.slice(2);
const value = (0, translations_1.translationValue)(path, translations);
if (!value)
return undefined;
return [(0, translations_1.renderTranslation)(value)];
});
}
async collectValueCompletions(uri, location, propertyKey, result) {
if (!(0, fileMatch_1.uriMatch)(uri, this.uriPatterns))
return;
const doc = this.documentManager.get(uri);
if (!doc || doc.ast instanceof Error || doc.type !== theme_check_common_1.SourceCodeType.LiquidHtml) {
return;
}
const schema = findSchemaNode(doc.ast);
if (!schema)
return;
const jsonString = schema.source.slice(schema.blockStartPosition.end, schema.blockEndPosition.start);
const jsonDocument = (0, theme_check_common_1.parseJSON)(jsonString);
if (!jsonDocument)
return;
const label = location
.concat(propertyKey)
.reduce((acc, val) => acc === null || acc === void 0 ? void 0 : acc[val], jsonDocument);
if (!label || typeof label !== 'string' || !label.startsWith('t:')) {
return;
}
const items = await this.recommendTranslations(uri, label);
for (const item of items) {
result.add(item);
}
}
// These are only there to satisfy the TS interface
async collectDefaultCompletions(_uri, _result) { }
// prettier-ignore
async collectPropertyCompletions(_uri, _location, _currentWord, _addValue, _isLast, _result) { }
async recommendTranslations(uri, label) {
var _a;
const partial = (_a = /^t:(.*)/.exec(label)) === null || _a === void 0 ? void 0 : _a[1];
if (!partial && partial !== '')
return [];
const translations = await this.getDefaultSchemaTranslations(uri);
// We'll let the frontend do the filtering. But we'll only include shopify
// translations if the shopify prefix is present
const options = (0, translations_1.translationOptions)(translations);
return options.map((option) => {
const tLabel = `t:${option.path.join('.')}`;
return {
label: tLabel,
kind: vscode_languageserver_protocol_1.CompletionItemKind.Value,
filterText: `"${tLabel}"`,
insertText: `"${tLabel}"`,
insertTextFormat: 1,
documentation: {
kind: 'markdown',
value: (0, translations_1.renderTranslation)(option.translation),
},
};
});
}
}
exports.SchemaTranslationContributions = SchemaTranslationContributions;
function findSchemaNode(ast) {
const nodes = (0, visitor_1.visit)(ast, {
LiquidRawTag(node) {
if (node.name === 'schema') {
return node;
}
},
});
return nodes[0];
}
exports.findSchemaNode = findSchemaNode;
//# sourceMappingURL=SchemaTranslationContributions.js.map
;