@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>
100 lines • 4.67 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.contextualizedLabel = exports.fileMatch = exports.TranslationFileContributions = void 0;
const theme_check_common_1 = require("@shopify/theme-check-common");
const translations_1 = require("../translations");
function nodeAtLocation(ast, location) {
return location.reduce((value, segment) => {
var _a;
if (value && typeof value !== 'string') {
switch (value.type) {
case 'Object': {
return (_a = value.children.find((child) => child.key.value === segment)) === null || _a === void 0 ? void 0 : _a.value;
}
case 'Array': {
if (typeof segment !== 'number')
return undefined;
return value.children[segment];
}
case 'Identifier': {
return undefined; // trying to [segment] onto a string or number
}
case 'Literal': {
return undefined; // trying to [segment] onto a string or number
}
case 'Property': {
return undefined; // this shouldn't be happening
}
}
}
}, ast);
}
const nothing = undefined;
class TranslationFileContributions {
constructor(documentManager) {
this.documentManager = documentManager;
this.filePatterns = [/^.*\/locales\/[^\/]*\.json$/];
}
getInfoContribution(uri, location) {
// TODO: This is a hack to get around the fact that the JSON language service
// actually is not typed properly and performs "if-undefined-skip" logic.
// https://github.com/microsoft/vscode-json-languageservice/pull/222
// would fix this, but it's not merged yet.
if (!fileMatch(uri, this.filePatterns))
return nothing;
const doc = this.documentManager.get(uri);
if (!doc || location.length === 0 || doc.type !== theme_check_common_1.SourceCodeType.JSON)
return nothing;
const ast = doc.ast;
if (ast instanceof Error)
return nothing;
const node = nodeAtLocation(ast, location);
switch (true) {
// Because the JSON language service doesn't support composition of hover info,
// We have to hardcode the docs for the translation file schema here.
case ['zero', 'one', 'two', 'few', 'many', 'other'].includes(location.at(-1)): {
if (!node || node.type !== 'Literal' || typeof node.value !== 'string') {
return Promise.resolve([`Pluralized translations should have a string value`]);
}
return Promise.resolve([contextualizedLabel(uri, location.slice(0, -1), node.value)]);
}
case location.at(-1).toString().endsWith('_html'): {
if (!node || node.type !== 'Literal' || typeof node.value !== 'string') {
return Promise.resolve([`Translations ending in '_html' should have a string value`]);
}
return Promise.resolve([
contextualizedLabel(uri, location, node.value),
`The '_html' suffix prevents the HTML content from being escaped.`,
]);
}
default: {
if (!node || node.type !== 'Literal' || typeof node.value !== 'string') {
return Promise.resolve([`Translation group: ${location.join('.')}`]);
}
return Promise.resolve([contextualizedLabel(uri, location, node.value)]);
}
}
}
async collectDefaultCompletions(uri, result) { }
async collectPropertyCompletions(uri, location, currentWord, addValue, isLast, result) { }
async collectValueCompletions(uri, location, propertyKey, result) { }
}
exports.TranslationFileContributions = TranslationFileContributions;
function fileMatch(uri, patterns) {
return patterns.some((pattern) => pattern.test(uri));
}
exports.fileMatch = fileMatch;
function contextualizedLabel(uri, str, value) {
if (uri.includes('.schema')) {
return marked(`"t:${str.join('.')}"`, 'json');
}
else {
const params = (0, translations_1.extractParams)(value);
return marked(`{{ '${str.join('.')}' | t${(0, translations_1.paramsString)(params)} }}`, 'liquid');
}
}
exports.contextualizedLabel = contextualizedLabel;
function marked(value, language = 'liquid') {
return { language, value };
}
//# sourceMappingURL=TranslationFileContributions.js.map
;