Skip to content

Commit

Permalink
Modify getLiquidDocDefinitionsForURI to return single LiquidDocDefini…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
jamesmengo committed Jan 14, 2025
1 parent 07c1041 commit 2e8de59
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 88 deletions.
8 changes: 4 additions & 4 deletions packages/theme-check-common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,15 +304,15 @@ export interface LiquidDocParameter {
type?: string;
}

export interface LiquidDocExample {
value: string;
}

export interface LiquidDocDefinition {
name: string;
parameters?: LiquidDocParameter[];
}

export type LiquidDocDefinitionMap = {
[key: string]: LiquidDocDefinition;
};

export type Translations = {
[k in string]: string | Translations;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
LiquidDocDefinitionMap,
LiquidDocDefinition,
MetafieldDefinitionMap,
SourceCodeType,
ThemeDocset,
Expand Down Expand Up @@ -35,7 +35,7 @@ export class HoverProvider {
readonly getLiquidDocDefinitionsForURI: (
uri: string,
snippetName: string,
) => Promise<LiquidDocDefinitionMap>,
) => Promise<LiquidDocDefinition>,
) {
const typeSystem = new TypeSystem(
themeDocset,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { describe, beforeEach, it, expect } from 'vitest';
import { DocumentManager } from '../../documents';
import { HoverProvider } from '../HoverProvider';
import { MetafieldDefinitionMap, LiquidDocDefinitionMap } from '@shopify/theme-check-common';
import { RenderSnippetHoverProvider } from './RenderSnippetHoverProvider';
import { NodeTypes } from '@shopify/liquid-html-parser';
import { LiquidDocDefinition, MetafieldDefinitionMap } from '@shopify/theme-check-common';

describe('Module: RenderSnippetHoverProvider', async () => {
let provider: HoverProvider;
let renderSnippetProvider: RenderSnippetHoverProvider;
let getLiquidDoc: () => Promise<LiquidDocDefinition>;
const mockDefinitions = {
'product-card': {
name: 'product-card',
Expand All @@ -24,9 +22,8 @@ describe('Module: RenderSnippetHoverProvider', async () => {
},
};

beforeEach(async () => {
renderSnippetProvider = new RenderSnippetHoverProvider(async () => mockDefinitions);
provider = new HoverProvider(
const createProvider = (getLiquidDoc: () => Promise<LiquidDocDefinition>) => {
return new HoverProvider(
new DocumentManager(),
{
filters: async () => [],
Expand All @@ -37,31 +34,13 @@ describe('Module: RenderSnippetHoverProvider', async () => {
async (_rootUri: string) => ({} as MetafieldDefinitionMap),
async () => ({}),
async () => [],
async () => mockDefinitions,
getLiquidDoc,
);
});

describe('node type checking', () => {
it('should return null if currentNode is not a String', async () => {
const node = { type: NodeTypes.LiquidTag };
const ancestors = [{ type: NodeTypes.RenderMarkup }];
const result = await renderSnippetProvider.hover(node as any, ancestors as any, {} as any);
expect(result).toBeNull();
});

it('should return null if parent node is missing', async () => {
const node = { type: NodeTypes.String };
const ancestors: any[] = [];
const result = await renderSnippetProvider.hover(node as any, ancestors, {} as any);
expect(result).toBeNull();
});
};

it('should return null if parent is not a RenderMarkup', async () => {
const node = { type: NodeTypes.String };
const ancestors = [{ type: NodeTypes.LiquidTag }];
const result = await renderSnippetProvider.hover(node as any, ancestors as any, {} as any);
expect(result).toBeNull();
});
beforeEach(async () => {
getLiquidDoc = async () => mockDefinitions['product-card'];
provider = createProvider(getLiquidDoc);
});

describe('hover', () => {
Expand All @@ -73,17 +52,9 @@ describe('Module: RenderSnippetHoverProvider', async () => {
});

it('should return snippet documentation without parameters', async () => {
await expect(provider).to.hover(
`{% render 'empty-snip█pet-with-docs' %}`,
'### empty-snippet-with-docs',
);
});

it('should return the snippet name if not LiquidDoc schema is not found', async () => {
await expect(provider).to.hover(
`{% render 'snippet-with█out-docs' %}`,
'### snippet-without-docs',
);
getLiquidDoc = async () => mockDefinitions['empty-snippet'];
provider = createProvider(getLiquidDoc);
await expect(provider).to.hover(`{% render 'empty-sni█ppet' %}`, '### empty-snippet');
});

it('should return nothing if not in render tag', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NodeTypes } from '@shopify/liquid-html-parser';
import {
LiquidHtmlNode,
LiquidDocDefinitionMap,
LiquidDocDefinition,
LiquidDocParameter,
} from '@shopify/theme-check-common';
import { Hover, HoverParams } from 'vscode-languageserver';
Expand All @@ -12,7 +12,7 @@ export class RenderSnippetHoverProvider implements BaseHoverProvider {
private getLiquidDocDefinitionsForURI: (
uri: string,
snippetName: string,
) => Promise<LiquidDocDefinitionMap>,
) => Promise<LiquidDocDefinition>,
) {}

async hover(
Expand All @@ -30,13 +30,12 @@ export class RenderSnippetHoverProvider implements BaseHoverProvider {
}

const snippetName = currentNode.value.replace(/['"]/g, '');
const docDefinitions = await this.getLiquidDocDefinitionsForURI(
const liquidDocDefinition = await this.getLiquidDocDefinitionsForURI(
params.textDocument.uri,
snippetName,
);
const snippetDefinition = docDefinitions[snippetName];

if (!snippetDefinition) {
if (!liquidDocDefinition) {
return {
contents: {
kind: 'markdown',
Expand All @@ -45,14 +44,14 @@ export class RenderSnippetHoverProvider implements BaseHoverProvider {
};
}

const parameterDocs = snippetDefinition.parameters
const parameterDocs = liquidDocDefinition.parameters
?.map(
(param: LiquidDocParameter) =>
`- \`${param.name}\`${param.type ? `: ${param.type}` : ''} - ${param.description || ''}`,
)
.join('\n');

const parts = [`### ${snippetDefinition.name}`];
const parts = [`### ${liquidDocDefinition.name}`];
if (parameterDocs) {
parts.push('', '**Parameters:**', parameterDocs);
}
Expand Down
56 changes: 22 additions & 34 deletions packages/theme-language-server-common/src/server/startServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
findRoot as findConfigFileRoot,
isError,
LiquidDocDefinition,
LiquidDocDefinitionMap,
LiquidDocParameter,
makeFileExists,
makeGetDefaultSchemaTranslations,
Expand Down Expand Up @@ -179,50 +178,39 @@ export function startServer(
const getLiquidDocDefinitionsForURI = async (
uri: string,
snippetName: string,
): Promise<LiquidDocDefinitionMap> => {
): Promise<LiquidDocDefinition> => {
const rootUri = await findThemeRootURI(uri);
const snippetURI = path.join(rootUri, 'snippets', `${snippetName}.liquid`);
const snippet = documentManager.get(snippetURI);

if (!snippet || isError(snippet)) return {};
if (!snippet || isError(snippet)) return { name: snippetName };

if (snippet.type !== SourceCodeType.LiquidHtml) return {};
if (snippet.type !== SourceCodeType.LiquidHtml) return { name: snippetName };

// read the snippet AST
const ast = snippet.ast;
if (isError(ast)) return {};

const docDefinitions = visit<SourceCodeType.LiquidHtml, LiquidDocDefinition>(ast, {
LiquidRawTag: (node, _ancestors) => {
if (node.name === 'doc') {
const body = node.body;
const paramNodes = visit<SourceCodeType.LiquidHtml, LiquidDocParameter>(body, {
LiquidDocParamNode: (node) => {
return [
{
name: node.paramName.value,
description: node.paramDescription?.value,
type: node.paramType?.value,
},
];
},
});
return {
name: snippetName,
description: 'placeholder',
parameters: paramNodes,
};
}
if (isError(ast)) return { name: snippetName };

const liquidDocAnnotations = visit<SourceCodeType.LiquidHtml, LiquidDocParameter>(ast, {
LiquidDocParamNode: (node) => {
return {
name: node.paramName.value,
description: node.paramDescription?.value,
type: node.type,
};
},
});

const returnVal: LiquidDocDefinitionMap = {
[snippetName]: {
name: snippetName,
parameters: docDefinitions[0].parameters,
},
const parameters: LiquidDocParameter[] = [];
liquidDocAnnotations.forEach((annotation) => {
if (annotation.type === 'LiquidDocParamNode') {
parameters.push(annotation);
}
});

return {
name: snippetName,
parameters: parameters,
};
return returnVal;
};

const snippetFilter = ([uri]: FileTuple) => /\.liquid$/.test(uri) && /snippets/.test(uri);
Expand Down

0 comments on commit 2e8de59

Please sign in to comment.