From c29bbcd96b869e976fb60f97509e312317d8fcc7 Mon Sep 17 00:00:00 2001 From: Josh Faigan Date: Mon, 10 Aug 2026 15:23:26 -0400 Subject: [PATCH] feat(language-server): link {% block %} names to blocks/.liquid Adds a documentLink for the block tag's name argument so cmd+click navigates to the block file, matching the existing section behaviour. --- .changeset/document-link-block-tag.md | 6 ++++++ .../documentLinks/DocumentLinksProvider.spec.ts | 16 ++++++++++++++++ .../src/documentLinks/DocumentLinksProvider.ts | 9 +++++++++ 3 files changed, 31 insertions(+) create mode 100644 .changeset/document-link-block-tag.md diff --git a/.changeset/document-link-block-tag.md b/.changeset/document-link-block-tag.md new file mode 100644 index 000000000..613346df6 --- /dev/null +++ b/.changeset/document-link-block-tag.md @@ -0,0 +1,6 @@ +--- +'@shopify/theme-language-server-common': patch +--- + +Add a document link for the `{% block 'name' %}` tag so cmd+click on the block +name navigates to `blocks/.liquid`. diff --git a/packages/theme-language-server-common/src/documentLinks/DocumentLinksProvider.spec.ts b/packages/theme-language-server-common/src/documentLinks/DocumentLinksProvider.spec.ts index e0964f927..235ed1aa7 100644 --- a/packages/theme-language-server-common/src/documentLinks/DocumentLinksProvider.spec.ts +++ b/packages/theme-language-server-common/src/documentLinks/DocumentLinksProvider.spec.ts @@ -43,6 +43,9 @@ describe('DocumentLinksProvider', () => { {% assign x = 'assign.css' | asset_url %} {{ 'asset.js' | asset_url }} {% content_for 'block', type: 'block_name' %} + {% block 'container' %}{% endblock %} + {% block '_private' %}{% endblock %} + {% block 'with_args', block.settings.alignment: 'center' %}{% endblock %} `; documentManager.open(uriString, liquidHtmlContent, 1); @@ -56,6 +59,9 @@ describe('DocumentLinksProvider', () => { 'file:///path/to/project/assets/assign.css', 'file:///path/to/project/assets/asset.js', 'file:///path/to/project/blocks/block_name.liquid', + 'file:///path/to/project/blocks/container.liquid', + 'file:///path/to/project/blocks/_private.liquid', + 'file:///path/to/project/blocks/with_args.liquid', ]; expect(result.length).toBe(expectedUrls.length); @@ -63,4 +69,14 @@ describe('DocumentLinksProvider', () => { expect(result[i].target).toBe(expectedUrls[i]); } }); + + it('should not create a link for the {% partial %} tag', async () => { + uriString = 'file:///path/to/liquid-html-document.liquid'; + rootUri = 'file:///path/to/project'; + + documentManager.open(uriString, `{% partial 'x' %}{% endpartial %}`, 1); + + const result = await documentLinksProvider.documentLinks(uriString); + expect(result).toEqual([]); + }); }); diff --git a/packages/theme-language-server-common/src/documentLinks/DocumentLinksProvider.ts b/packages/theme-language-server-common/src/documentLinks/DocumentLinksProvider.ts index 96bd36e85..911b7de6f 100644 --- a/packages/theme-language-server-common/src/documentLinks/DocumentLinksProvider.ts +++ b/packages/theme-language-server-common/src/documentLinks/DocumentLinksProvider.ts @@ -63,6 +63,15 @@ function documentLinksVisitor( ); } + // {% block 'name' %} + if (node.name === NamedTags.block && typeof node.markup !== 'string') { + const blockName = node.markup.name; + return DocumentLink.create( + range(textDocument, blockName), + Utils.resolvePath(root, 'blocks', blockName.value + '.liquid').toString(), + ); + } + // {% content_for 'block', type: 'block_name' %} if (node.name === NamedTags.content_for && typeof node.markup !== 'string') { const typeArg = node.markup.args.find((arg) => arg.name === 'type');