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

feat(cli): add gql.tada/ts-plugin to init/doctor #276

Merged
merged 1 commit into from
Apr 28, 2024
Merged
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
5 changes: 5 additions & 0 deletions .changeset/big-ravens-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@gql.tada/cli-utils": minor
---

Add `gql.tada/ts-plugin` to the init and doctor command
47 changes: 29 additions & 18 deletions packages/cli-utils/src/commands/doctor/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const delay = (ms = 700) => {
}
};

const semiverComply = (version: string, compare: string) => {
export const semiverComply = (version: string, compare: string) => {
const match = version.match(/\d+\.\d+\.\d+/);
return match ? semiver(match[0], compare) >= 0 : false;
};
Expand All @@ -37,7 +37,8 @@ const enum Messages {
CHECK_SCHEMA = 'Checking schema',
}

const MINIMUM_VERSIONS = {
export const MINIMUM_VERSIONS = {
typescript_embed_lsp: '5.5.0',
typescript: '4.1.0',
tada: '1.0.0',
lsp: '1.0.0',
Expand Down Expand Up @@ -94,21 +95,29 @@ export async function* run(): AsyncIterable<ComposeInput> {
yield logger.runningTask(Messages.CHECK_DEPENDENCIES);
await delay();

const gqlspVersion = deps.find((x) => x[0] === '@0no-co/graphqlsp');
if (!gqlspVersion) {
yield logger.failedTask(Messages.CHECK_DEPENDENCIES);
throw logger.errorMessage(
`A version of ${logger.code('@0no-co/graphqlsp')} was not found in your dependencies.\n` +
logger.hint(`Is ${logger.code('@0no-co/graphqlsp')} installed?`)
);
} else if (!semiverComply(gqlspVersion[1], MINIMUM_VERSIONS.lsp)) {
yield logger.failedTask(Messages.CHECK_DEPENDENCIES);
throw logger.errorMessage(
`The version of ${logger.code('@0no-co/graphqlsp')} in your dependencies is out of date.\n` +
logger.hint(
`${logger.code('gql.tada')} requires at least ${logger.bold(MINIMUM_VERSIONS.lsp)}`
)
);
const supportsEmbeddedLsp = semiverComply(
typeScriptVersion[1],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since TS is now a peer dependency, we should be able to read this from require('typescript').version. Probably have to try-catch it with a new error, but that should also just give us the raw version.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can do that in a follow up

MINIMUM_VERSIONS.typescript_embed_lsp
);
if (!supportsEmbeddedLsp) {
const gqlspVersion = deps.find((x) => x[0] === '@0no-co/graphqlsp');
if (!gqlspVersion) {
yield logger.failedTask(Messages.CHECK_DEPENDENCIES);
throw logger.errorMessage(
`A version of ${logger.code('@0no-co/graphqlsp')} was not found in your dependencies.\n` +
logger.hint(`Is ${logger.code('@0no-co/graphqlsp')} installed?`)
);
} else if (!semiverComply(gqlspVersion[1], MINIMUM_VERSIONS.lsp)) {
yield logger.failedTask(Messages.CHECK_DEPENDENCIES);
throw logger.errorMessage(
`The version of ${logger.code(
'@0no-co/graphqlsp'
)} in your dependencies is out of date.\n` +
logger.hint(
`${logger.code('gql.tada')} requires at least ${logger.bold(MINIMUM_VERSIONS.lsp)}`
)
);
}
}

const gqlTadaVersion = deps.find((x) => x[0] === 'gql.tada');
Expand Down Expand Up @@ -151,7 +160,9 @@ export async function* run(): AsyncIterable<ComposeInput> {
} catch (error) {
yield logger.failedTask(Messages.CHECK_TSCONFIG);
throw logger.externalError(
`The plugin configuration for ${logger.code('"@0no-co/graphqlsp"')} seems to be invalid.`,
`The plugin configuration for ${logger.code(
supportsEmbeddedLsp ? '"gql.tada/ts-plugin"' : '"@0no-co/graphqlsp"'
)} seems to be invalid.`,
error
);
}
Expand Down
75 changes: 55 additions & 20 deletions packages/cli-utils/src/commands/init/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from 'node:path';
import { execa } from 'execa';

import { readTSConfigFile } from '@gql.tada/internal';
import { MINIMUM_VERSIONS, semiverComply } from '../doctor/runner';

const s = spinner();

Expand Down Expand Up @@ -90,24 +91,51 @@ export async function run(target: string) {
process.exit(0);
}

let supportsEmbeddedLsp = false;
let packageJson: {
dependencies: Record<string, string>;
devDependencies: Record<string, string>;
};

try {
const packageJsonPath = path.resolve(target, 'package.json');
const packageJsonContents = await fs.readFile(packageJsonPath, 'utf-8');
packageJson = JSON.parse(packageJsonContents);
const deps = Object.entries({
...packageJson.dependencies,
...packageJson.devDependencies,
});

const typeScriptVersion = deps.find((x) => x[0] === 'typescript');
if (typeScriptVersion && typeof typeScriptVersion[1] === 'string') {
supportsEmbeddedLsp = semiverComply(
typeScriptVersion[1],
MINIMUM_VERSIONS.typescript_embed_lsp
);
}
} catch (e) {}

if (shouldInstallDependencies) {
s.start('Installing packages.');
await installPackages(getPkgManager(), target);
await installPackages(getPkgManager(), target, !supportsEmbeddedLsp);
s.stop('Installed packages.');
} else {
s.start('Writing to package.json.');
try {
const packageJsonPath = path.resolve(target, 'package.json');
const packageJsonContents = await fs.readFile(packageJsonPath, 'utf-8');
const packageJson = JSON.parse(packageJsonContents);
packageJson = JSON.parse(packageJsonContents);

if (!packageJson.dependencies) packageJson.dependencies = {};
if (!packageJson.dependencies['gql.tada']) {
packageJson.dependencies['gql.tada'] = TADA_VERSION;
}

if (!packageJson.devDependencies) packageJson.devDependencies = {};
if (!packageJson.devDependencies['@0no-co/graphqlsp']) {
packageJson.devDependencies['@0no-co/graphqlsp'] = LSP_VERSION;
if (!supportsEmbeddedLsp) {
if (!packageJson.devDependencies) packageJson.devDependencies = {};
if (!packageJson.devDependencies['@0no-co/graphqlsp']) {
packageJson.devDependencies['@0no-co/graphqlsp'] = LSP_VERSION;
}
}

await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
Expand All @@ -129,7 +157,7 @@ export async function run(target: string) {
...tsConfig.compilerOptions,
plugins: [
{
name: '@0no-co/graphqlsp',
name: supportsEmbeddedLsp ? 'gql.tada/ts-plugin' : '@0no-co/graphqlsp',
schema: isFile ? path.relative(target, schemaLocation) : schemaLocation,
tadaOutputLocation: path.relative(target, tadaLocation),
} as any,
Expand All @@ -143,20 +171,27 @@ export async function run(target: string) {
}

type PackageManager = 'yarn' | 'pnpm' | 'npm';
async function installPackages(packageManager: PackageManager, target: string) {
await execa(
packageManager,
[
// `yarn add` will fail if nothing is provided
packageManager === 'yarn' ? 'add' : 'install',
'-D',
'@0no-co/graphqlsp',
],
{
stdio: 'ignore',
cwd: target,
}
);
async function installPackages(
packageManager: PackageManager,
target: string,
shouldInstallGraphQLSP
) {
if (shouldInstallGraphQLSP) {
await execa(
packageManager,
[
// `yarn add` will fail if nothing is provided
packageManager === 'yarn' ? 'add' : 'install',
'-D',
'@0no-co/graphqlsp',
],
{
stdio: 'ignore',
cwd: target,
}
);
}

await execa(packageManager, [packageManager === 'yarn' ? 'add' : 'install', 'gql.tada'], {
stdio: 'ignore',
cwd: target,
Expand Down
Loading