Skip to content

Commit

Permalink
fix: fallback to bundled Prettier when finding Prettier 2 (#960)
Browse files Browse the repository at this point in the history
* fix: override prettier version in yaml–language–server

* chore: changeset

* chore: lockfile

* feat: more robust package loading
  • Loading branch information
Princesseuh authored Oct 2, 2024
1 parent 706fba9 commit 5a44072
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 68 deletions.
7 changes: 7 additions & 0 deletions .changeset/grumpy-planes-sip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@astrojs/language-server": patch
"@astrojs/check": patch
"astro-vscode": patch
---

Fixes formatting not working by default in certain circumstances
7 changes: 4 additions & 3 deletions packages/language-server/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import type { TypeScriptExtraServiceScript } from '@volar/typescript';
import type ts from 'typescript';
import type { HTMLDocument } from 'vscode-html-languageservice';
import type { URI } from 'vscode-uri';
import { type AstroInstall, getLanguageServerTypesDir } from '../utils.js';
import type { PackageInfo } from '../importPackage.js';
import { getLanguageServerTypesDir } from '../utils.js';
import { astro2tsx } from './astro2tsx';
import type { AstroMetadata } from './parseAstro';
import { getAstroMetadata } from './parseAstro';
Expand All @@ -21,7 +22,7 @@ import { extractScriptTags } from './parseJS.js';
const decoratedHosts = new WeakSet<ts.LanguageServiceHost>();

export function addAstroTypes(
astroInstall: AstroInstall | undefined,
astroInstall: PackageInfo | undefined,
ts: typeof import('typescript'),
host: ts.LanguageServiceHost,
) {
Expand All @@ -41,7 +42,7 @@ export function addAstroTypes(
if (astroInstall) {
addedFileNames.push(
...['./env.d.ts', './astro-jsx.d.ts'].map((filePath) =>
ts.sys.resolvePath(path.resolve(astroInstall.path, filePath)),
ts.sys.resolvePath(path.resolve(astroInstall.directory, filePath)),
),
);

Expand Down
66 changes: 54 additions & 12 deletions packages/language-server/src/importPackage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,48 @@ import type * as svelte from '@astrojs/svelte/dist/editor.cjs';
import type * as vue from '@astrojs/vue/dist/editor.cjs';
import type * as prettier from 'prettier';

type PackageVersion = {
full: string;
major: number;
minor: number;
patch: number;
};

let isTrusted = true;

export function setIsTrusted(_isTrusted: boolean) {
isTrusted = _isTrusted;
}

export type PackageInfo = {
entrypoint: string;
directory: string;
version: PackageVersion;
};

/**
* Get the path of a package's directory from the paths in `fromPath`, if `root` is set to false, it will return the path of the package's entry point
*/
export function getPackagePath(
packageName: string,
fromPath: string[],
root = true,
): string | undefined {
export function getPackageInfo(packageName: string, fromPath: string[]): PackageInfo | undefined {
const paths = [];
if (isTrusted) {
paths.unshift(...fromPath);
}

try {
return root
? dirname(require.resolve(packageName + '/package.json', { paths }))
: require.resolve(packageName, { paths });
const packageJSON = require.resolve(packageName + '/package.json', { paths });
return {
directory: dirname(packageJSON),
entrypoint: require.resolve(packageName, { paths }),
version: parsePackageVersion(require(packageJSON).version),
};
} catch {
return undefined;
}
}

function importEditorIntegration<T>(packageName: string, fromPath: string): T | undefined {
const pkgPath = getPackagePath(packageName, [fromPath]);
const pkgPath = getPackageInfo(packageName, [fromPath])?.directory;

if (pkgPath) {
try {
Expand Down Expand Up @@ -66,17 +78,31 @@ export function importVueIntegration(fromPath: string): typeof vue | undefined {
}

export function importPrettier(fromPath: string): typeof prettier | undefined {
const prettierPkg = getPackagePath('prettier', [fromPath, __dirname]);
let prettierPkg = getPackageInfo('prettier', [fromPath, __dirname]);

if (!prettierPkg) {
return undefined;
}

return require(prettierPkg);
if (prettierPkg.version.major < 3) {
console.error(
`Prettier version ${prettierPkg.version.full} from ${prettierPkg.directory} is not supported, please update to at least version 3.0.0. Falling back to bundled version to ensure formatting works correctly.`,
);

prettierPkg = getPackageInfo('prettier', [__dirname]);
if (!prettierPkg) {
return undefined;
}
}

return require(prettierPkg.entrypoint);
}

export function getPrettierPluginPath(fromPath: string): string | undefined {
const prettierPluginPath = getPackagePath('prettier-plugin-astro', [fromPath, __dirname], false);
const prettierPluginPath = getPackageInfo('prettier-plugin-astro', [
fromPath,
__dirname,
])?.entrypoint;

if (!prettierPluginPath) {
return undefined;
Expand All @@ -94,3 +120,19 @@ export function getWorkspacePnpPath(workspacePath: string): string | null {
return null;
}
}

export function parsePackageVersion(version: string): PackageVersion {
let [major, minor, patch] = version.split('.');

if (patch.includes('-')) {
const patchParts = patch.split('-');
patch = patchParts[0];
}

return {
full: version,
major: Number(major),
minor: Number(minor),
patch: Number(patch),
};
}
63 changes: 10 additions & 53 deletions packages/language-server/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import * as path from 'node:path';
import { getPackagePath } from './importPackage.js';

export interface AstroInstall {
path: string;
version: {
full: string;
major: number;
minor: number;
patch: number;
};
}
import type { PackageInfo } from './importPackage.js';
import { getPackageInfo } from './importPackage.js';

export function getLanguageServerTypesDir(ts: typeof import('typescript')) {
return ts.sys.resolvePath(path.resolve(__dirname, '../types'));
Expand All @@ -21,10 +12,7 @@ export function getAstroInstall(
nearestPackageJson: string | undefined;
readDirectory: typeof import('typescript').sys.readDirectory;
},
): AstroInstall | 'not-an-astro-project' | 'not-found' {
let astroPath;
let version;

): PackageInfo | 'not-an-astro-project' | 'not-found' {
if (checkForAstro && checkForAstro.nearestPackageJson) {
basePaths.push(path.dirname(checkForAstro.nearestPackageJson));

Expand Down Expand Up @@ -53,52 +41,21 @@ export function getAstroInstall(
}
}

try {
astroPath = getPackagePath('astro', basePaths);

if (!astroPath) {
throw Error;
}

version = require(path.resolve(astroPath, 'package.json')).version;
} catch {
// If we couldn't find it inside the workspace's node_modules, it might means we're in the monorepo
try {
astroPath = getPackagePath('./packages/astro', basePaths);
let astroPackage = getPackageInfo('astro', basePaths);

if (!astroPath) {
throw Error;
}
if (!astroPackage) {
// If we couldn't find it inside the workspace's node_modules, it might means we're in the Astro development monorepo
astroPackage = getPackageInfo('./packages/astro', basePaths);

version = require(path.resolve(astroPath, 'package.json')).version;
} catch {
// If we still couldn't find it, it probably just doesn't exist
if (!astroPackage) {
console.error(
`${basePaths[0]} seems to be an Astro project, but we couldn't find Astro or Astro is not installed`,
);

// If we still couldn't find it, it probably just doesn't exist
return 'not-found';
}
}

if (!version) {
return 'not-found';
}

let [major, minor, patch] = version.split('.');

if (patch.includes('-')) {
const patchParts = patch.split('-');
patch = patchParts[0];
}

return {
path: astroPath,
version: {
full: version,
major: Number(major),
minor: Number(minor),
patch: Number(patch),
},
};
return astroPackage;
}

0 comments on commit 5a44072

Please sign in to comment.