Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fetch metafield definitions on start-up #597

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/plenty-flowers-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@shopify/theme-language-server-common': minor
'@shopify/theme-language-server-node': minor
---

Fetch metafield definitions on start-up using CLI
28 changes: 28 additions & 0 deletions packages/theme-language-server-common/src/server/startServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
InitializeResult,
ShowDocumentRequest,
TextDocumentSyncKind,
WorkspaceFolder,
} from 'vscode-languageserver';
import { ClientCapabilities } from '../ClientCapabilities';
import { CodeActionKinds, CodeActionsProvider } from '../codeActions';
Expand Down Expand Up @@ -79,6 +80,7 @@ export function startServer(
log = defaultLogger,
jsonValidationSet,
themeDocset: remoteThemeDocset,
fetchMetafieldDefinitionsForURI,
}: Dependencies,
) {
const fs = new CachedFileSystem(injectedFs);
Expand Down Expand Up @@ -241,6 +243,18 @@ export function startServer(
connection,
);

const fetchMetafieldDefinitionsForWorkspaceFolders = async (folders: WorkspaceFolder[]) => {
if (!fetchMetafieldDefinitionsForURI) return;

for (let folder of folders) {
const mode = await getModeForURI(folder.uri);

if (mode === 'theme') {
fetchMetafieldDefinitionsForURI(folder.uri);
}
}
};

connection.onInitialize((params) => {
clientCapabilities.setup(params.capabilities, params.initializationOptions);
jsonLanguageService.setup(params.capabilities);
Expand Down Expand Up @@ -294,6 +308,10 @@ export function startServer(
workDoneProgress: false,
},
workspace: {
workspaceFolders: {
supported: true,
changeNotifications: true,
},
fileOperations: {
didRename: fileOperationRegistrationOptions,
didCreate: fileOperationRegistrationOptions,
Expand Down Expand Up @@ -321,6 +339,16 @@ export function startServer(
},
],
});

connection.workspace.getWorkspaceFolders().then(async (folders) => {
if (!folders) return;

fetchMetafieldDefinitionsForWorkspaceFolders(folders);
});

connection.workspace.onDidChangeWorkspaceFolders(async (params) => {
fetchMetafieldDefinitionsForWorkspaceFolders(params.added);
});
});

connection.onDidChangeConfiguration((_params) => {
Expand Down
11 changes: 10 additions & 1 deletion packages/theme-language-server-common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { URI } from 'vscode-languageserver';

import { WithOptional } from './utils';

export type Dependencies = WithOptional<RequiredDependencies, 'log' | 'getMetafieldDefinitions'>;
export type Dependencies = WithOptional<
RequiredDependencies,
'log' | 'getMetafieldDefinitions' | 'fetchMetafieldDefinitionsForURI'
>;

export interface RequiredDependencies {
/**
Expand Down Expand Up @@ -86,4 +89,10 @@ export interface RequiredDependencies {
* fetching the set of metafield definitions every time.
*/
getMetafieldDefinitions: ThemeCheckDependencies['getMetafieldDefinitions'];

/**
* Fetch Metafield definitions using the CLI provided the URI of the project root.
* This should only be used in node environments; not on the browser.
*/
fetchMetafieldDefinitionsForURI: (uri: URI) => Promise<void>;
}
2 changes: 2 additions & 0 deletions packages/theme-language-server-node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { startServer as startCoreServer } from '@shopify/theme-language-server-c
import { stdin, stdout } from 'node:process';
import { createConnection } from 'vscode-languageserver/node';
import { loadConfig } from './dependencies';
import { fetchMetafieldDefinitionsForURI } from './metafieldDefinitions';

export { NodeFileSystem } from '@shopify/theme-check-node';
export * from '@shopify/theme-language-server-common';
Expand All @@ -21,5 +22,6 @@ export function startServer(connection = getConnection(), fs: AbstractFileSystem
loadConfig,
themeDocset: themeLiquidDocsManager,
jsonValidationSet: themeLiquidDocsManager,
fetchMetafieldDefinitionsForURI,
});
}
41 changes: 41 additions & 0 deletions packages/theme-language-server-node/src/metafieldDefinitions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as child_process from 'child_process';
import { promisify } from 'node:util';

const exec = promisify(child_process.exec);

const isWin = process.platform === 'win32';

const shopifyCliPathPromise = getShopifyCliPath();

export async function fetchMetafieldDefinitionsForURI(uri: string) {
const path = await shopifyCliPathPromise;

if (!path) {
return;
}

try {
await exec(`${path} theme metafields pull`, {
cwd: new URL(uri),
timeout: 10_000,
});
} catch (_) {
// CLI command can break because of incorrect version or not being logged in
// If this fails, the user must fetch their own metafield definitions
}
}

// eslint-disable-next-line no-unused-vars
async function getShopifyCliPath() {
if (isWin) {
const { stdout } = await exec(`where.exe shopify`);
const executables = stdout
.replace(/\r/g, '')
.split('\n')
.filter((exe) => exe.endsWith('bat'));
return executables.length > 0 ? executables[0] : '';
} else {
const { stdout } = await exec(`which shopify`);
return stdout.split('\n')[0].replace('\r', '');
}
}
Loading