From 753f5a379687f495258e2848e1f2d6a4686d1149 Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Tue, 12 Jul 2022 17:00:05 -0400 Subject: [PATCH 1/7] Improve astro check --- packages/astro/package.json | 2 +- packages/astro/src/cli/check.ts | 117 ------------------------- packages/astro/src/cli/check/index.ts | 92 ++++++++++++++++++++ packages/astro/src/cli/check/print.ts | 118 ++++++++++++++++++++++++++ packages/astro/src/cli/index.ts | 2 +- pnpm-lock.yaml | 58 ++++++------- 6 files changed, 240 insertions(+), 149 deletions(-) delete mode 100644 packages/astro/src/cli/check.ts create mode 100644 packages/astro/src/cli/check/index.ts create mode 100644 packages/astro/src/cli/check/print.ts diff --git a/packages/astro/package.json b/packages/astro/package.json index 2f3d6205e5dc..b578cc8a04e2 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -83,7 +83,7 @@ }, "dependencies": { "@astrojs/compiler": "^0.18.2", - "@astrojs/language-server": "^0.13.4", + "@astrojs/language-server": "^0.19.4", "@astrojs/markdown-remark": "^0.11.5", "@astrojs/prism": "0.5.0", "@astrojs/telemetry": "^0.3.0", diff --git a/packages/astro/src/cli/check.ts b/packages/astro/src/cli/check.ts deleted file mode 100644 index 65995d0e52a7..000000000000 --- a/packages/astro/src/cli/check.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* eslint-disable no-console */ -import { AstroCheck, DiagnosticSeverity } from '@astrojs/language-server'; -import type { AstroConfig } from '../@types/astro'; - -import glob from 'fast-glob'; -import * as fs from 'fs'; -import { bgWhite, black, bold, cyan, red, yellow } from 'kleur/colors'; -import * as path from 'path'; -import { pathToFileURL } from 'url'; - -async function openAllDocuments( - workspaceUri: URL, - filePathsToIgnore: string[], - checker: AstroCheck -) { - const files = await glob('**/*.astro', { - cwd: workspaceUri.pathname, - ignore: ['node_modules/**'].concat(filePathsToIgnore.map((ignore) => `${ignore}/**`)), - }); - const absFilePaths = files.map((f) => path.resolve(workspaceUri.pathname, f)); - - for (const absFilePath of absFilePaths) { - const text = fs.readFileSync(absFilePath, 'utf-8'); - checker.upsertDocument({ - uri: pathToFileURL(absFilePath).toString(), - text, - }); - } -} - -interface Result { - errors: number; - warnings: number; -} - -function offsetAt({ line, character }: { line: number; character: number }, text: string) { - let i = 0; - let l = 0; - let c = 0; - while (i < text.length) { - if (l === line && c === character) { - break; - } - - let char = text[i]; - switch (char) { - case '\n': { - l++; - c = 0; - break; - } - default: { - c++; - break; - } - } - - i++; - } - - return i; -} - -function generateString(str: string, len: number) { - return Array.from({ length: len }, () => str).join(''); -} - -export async function run() {} - -export async function check(astroConfig: AstroConfig) { - const root = astroConfig.root; - let checker = new AstroCheck(root.toString()); - await openAllDocuments(root, [], checker); - - let diagnostics = await checker.getDiagnostics(); - - let result: Result = { - errors: 0, - warnings: 0, - }; - - diagnostics.forEach((diag) => { - diag.diagnostics.forEach((d) => { - switch (d.severity) { - case DiagnosticSeverity.Error: { - console.error( - `${bold(cyan(path.relative(root.pathname, diag.filePath)))}:${bold( - yellow(d.range.start.line) - )}:${bold(yellow(d.range.start.character))} - ${d.message}` - ); - let startOffset = offsetAt({ line: d.range.start.line, character: 0 }, diag.text); - let endOffset = offsetAt({ line: d.range.start.line + 1, character: 0 }, diag.text); - let str = diag.text.substring(startOffset, endOffset - 1); - const lineNumStr = d.range.start.line.toString(); - const lineNumLen = lineNumStr.length; - console.error(`${bgWhite(black(lineNumStr))} ${str}`); - let tildes = generateString('~', d.range.end.character - d.range.start.character); - let spaces = generateString(' ', d.range.start.character + lineNumLen - 1); - console.error(` ${spaces}${bold(red(tildes))}\n`); - result.errors++; - break; - } - case DiagnosticSeverity.Warning: { - result.warnings++; - break; - } - } - }); - }); - - if (result.errors) { - console.error(`Found ${result.errors} errors.`); - } - - const exitCode = result.errors ? 1 : 0; - return exitCode; -} diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts new file mode 100644 index 000000000000..e88b4d5fefd9 --- /dev/null +++ b/packages/astro/src/cli/check/index.ts @@ -0,0 +1,92 @@ +/* eslint-disable no-console */ +import { AstroCheck, DiagnosticSeverity } from '@astrojs/language-server'; +import type { AstroConfig } from '../../@types/astro'; + +import glob from 'fast-glob'; +import * as fs from 'fs'; +import { bold, dim, red, yellow } from 'kleur/colors'; +import ora from 'ora'; +import * as path from 'path'; +import { fileURLToPath, pathToFileURL } from 'url'; +import { printDiagnostic } from './print.js'; + +interface Result { + errors: number; + // The language server cannot actually return any warnings at the moment, but we'll keep this here for future use + warnings: number; + hints: number; +} + +export async function check(astroConfig: AstroConfig) { + console.log(bold('astro check')); + + const root = astroConfig.root; + + const spinner = ora(` Getting diagnostics in ${fileURLToPath(root)}…`).start(); + + let checker = new AstroCheck(root.toString()); + await openAllDocuments(root, [], checker); + + let diagnostics = await checker.getDiagnostics(); + + spinner.succeed(); + + let result: Result = { + errors: 0, + warnings: 0, + hints: 0, + }; + + diagnostics.forEach((diag) => { + diag.diagnostics.forEach((d) => { + console.error(printDiagnostic(diag.filePath, diag.text, d)); + + switch (d.severity) { + case DiagnosticSeverity.Error: { + result.errors++; + break; + } + case DiagnosticSeverity.Warning: { + result.warnings++; + break; + } + case DiagnosticSeverity.Hint: { + result.hints++; + break; + } + } + }); + }); + + console.log( + [ + bold('Result: '), + bold(red(`${result.errors} ${result.errors === 1 ? 'error' : 'errors'}`)), + bold(yellow(`${result.warnings} ${result.warnings === 1 ? 'warning' : 'warnings'}`)), + dim(`${result.hints} ${result.hints === 1 ? 'hint' : 'hints'}\n`), + ].join(`\n${dim('-')} `) + ); + + const exitCode = result.errors ? 1 : 0; + return exitCode; +} + +async function openAllDocuments( + workspaceUri: URL, + filePathsToIgnore: string[], + checker: AstroCheck +) { + const files = await glob('**/*.astro', { + cwd: workspaceUri.pathname, + ignore: ['node_modules/**'].concat(filePathsToIgnore.map((ignore) => `${ignore}/**`)), + }); + const absFilePaths = files.map((f) => path.resolve(workspaceUri.pathname, f)); + + for (const absFilePath of absFilePaths) { + const text = fs.readFileSync(absFilePath, 'utf-8'); + checker.upsertDocument({ + uri: pathToFileURL(absFilePath).toString(), + text, + }); + } +} diff --git a/packages/astro/src/cli/check/print.ts b/packages/astro/src/cli/check/print.ts new file mode 100644 index 000000000000..e41115f67375 --- /dev/null +++ b/packages/astro/src/cli/check/print.ts @@ -0,0 +1,118 @@ +import { Diagnostic, DiagnosticSeverity, offsetAt } from '@astrojs/language-server'; +import { + bgRed, + bgWhite, + bgYellow, + black, + bold, + cyan, + gray, + red, + white, + yellow +} from 'kleur/colors'; +import stringWidth from 'string-width'; + +export function printDiagnostic(filePath: string, text: string, diag: Diagnostic): string { + let result = []; + + // Lines and characters are 0-indexed, so we need to add 1 to the offset to get the actual line and character + const realStartLine = diag.range.start.line + 1; + const realStartCharacter = diag.range.start.character + 1; + + // IDE friendly path that user can CTRL+Click to open the file at a specific line / character + const IDEFilePath = `${bold(cyan(filePath))}:${bold(yellow(realStartLine))}:${bold( + yellow(realStartCharacter) + )}`; + result.push( + `${IDEFilePath} ${bold(getColorForSeverity(diag, getStringForSeverity(diag)))}: ${diag.message}` + ); + + // Optionally add the before the error to add context if not empty + const previousLine = getLine(diag.range.start.line - 1, text); + if (previousLine) { + result.push(`${getPrintableLineNumber(realStartLine - 1)} ${gray(previousLine)}`); + } + + // Add the line with the error + const str = getLine(diag.range.start.line, text); + const lineNumStr = realStartLine.toString().padStart(2, '0'); + const lineNumLen = lineNumStr.length; + result.push(`${getBackgroundForSeverity(diag, lineNumStr)} ${str}`); + + // Adds tildes under the specific range where the diagnostic is + const tildes = generateString('~', diag.range.end.character - diag.range.start.character); + + // NOTE: This is not perfect, if the line include any characters that is made of multiple characters, for example + // regionals flags, but the terminal can't display it, then the number of spaces will be wrong. Not sure how to fix. + const beforeChars = stringWidth(str.substring(0, diag.range.start.character)); + const spaces = generateString(' ', beforeChars + lineNumLen - 1); + result.push(` ${spaces}${bold(getColorForSeverity(diag, tildes))}`); + + const nextLine = getLine(diag.range.start.line + 1, text); + if (nextLine) { + result.push(`${getPrintableLineNumber(realStartLine + 1)} ${gray(nextLine)}`); + } + + // Force a new line at the end + result.push(''); + + return result.join('\n'); +} + +function generateString(str: string, len: number): string { + return Array.from({ length: len }, () => str).join(''); +} + +function getStringForSeverity(diag: Diagnostic): string { + switch (diag.severity) { + case DiagnosticSeverity.Error: + return 'Error'; + case DiagnosticSeverity.Warning: + return 'Warning'; + case DiagnosticSeverity.Hint: + return 'Hint'; + default: + return 'Unknown'; + } +} + +function getColorForSeverity(diag: Diagnostic, text: string): string { + switch (diag.severity) { + case DiagnosticSeverity.Error: + return red(text); + case DiagnosticSeverity.Warning: + return yellow(text); + case DiagnosticSeverity.Hint: + return gray(text); + default: + return text; + } +} + +function getBackgroundForSeverity(diag: Diagnostic, text: string): string { + switch (diag.severity) { + case DiagnosticSeverity.Error: + return bgRed(white(text)); + case DiagnosticSeverity.Warning: + return bgYellow(white(text)); + case DiagnosticSeverity.Hint: + return bgWhite(black(text)); + default: + return text; + } +} + +function getPrintableLineNumber(line: number): string { + return bgWhite(black(line.toString().padStart(2, '0'))); +} + +function getLine(line: number, text: string): string { + return text + .substring( + offsetAt({ line, character: 0 }, text), + offsetAt({ line, character: Number.MAX_SAFE_INTEGER }, text) + ) + .replace(/\t/g, ' ') + .trimEnd(); +} diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index ed9e83fbfb15..ce588acfa78a 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -15,7 +15,7 @@ import preview from '../core/preview/index.js'; import { ASTRO_VERSION, createSafeError } from '../core/util.js'; import * as event from '../events/index.js'; import { eventConfigError, eventError, telemetry } from '../events/index.js'; -import { check } from './check.js'; +import { check } from './check/index.js'; import { openInBrowser } from './open.js'; import * as telemetryHandler from './telemetry.js'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 872d41ad5df5..deca4f0ed9bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -466,7 +466,7 @@ importers: packages/astro: specifiers: '@astrojs/compiler': ^0.18.2 - '@astrojs/language-server': ^0.13.4 + '@astrojs/language-server': ^0.19.4 '@astrojs/markdown-remark': ^0.11.5 '@astrojs/prism': 0.5.0 '@astrojs/telemetry': ^0.3.0 @@ -546,12 +546,13 @@ importers: strip-ansi: ^7.0.1 supports-esm: ^1.0.0 tsconfig-resolver: ^3.0.1 + utfstring: ^2.0.2 vite: ^2.9.14 yargs-parser: ^21.0.1 zod: ^3.17.3 dependencies: '@astrojs/compiler': 0.18.2 - '@astrojs/language-server': 0.13.4 + '@astrojs/language-server': 0.19.4 '@astrojs/markdown-remark': link:../markdown/remark '@astrojs/prism': link:../astro-prism '@astrojs/telemetry': link:../telemetry @@ -604,6 +605,7 @@ importers: strip-ansi: 7.0.1 supports-esm: 1.0.0 tsconfig-resolver: 3.0.1 + utfstring: 2.0.2 vite: 2.9.14_sass@1.53.0 yargs-parser: 21.0.1 zod: 3.17.3 @@ -2644,18 +2646,19 @@ packages: resolution: {integrity: sha512-R2lOpaif3hDju2/sE6OrKvnTMgrcLRJw+jAVih9pLA2ATgy2EnhYMhflRk1vQ6+YwuhyL6Lj/dRJFXgB7r70eg==} dev: false - /@astrojs/language-server/0.13.4: - resolution: {integrity: sha512-xWtzZMEVsEZkRLlHMKiOoQIXyQwdMkBPHsRcO1IbzpCmaMQGfKKYNANJ1FKZSHsybbXG/BBaB+LqgVPFNFufew==} + /@astrojs/language-server/0.19.4: + resolution: {integrity: sha512-Po+/gLyetY2jka4x3jheQTGtD5hVOm6krGlv39ZdNNlQudcO9YuZhKgDa5BafRJb21DgFcH2BLb6lM7mR/fqHw==} hasBin: true dependencies: '@astrojs/svelte-language-integration': 0.1.6_typescript@4.6.4 + '@astrojs/vue-language-integration': 0.1.1 '@vscode/emmet-helper': 2.8.4 lodash: 4.17.21 source-map: 0.7.4 typescript: 4.6.4 - vscode-css-languageservice: 5.4.2 - vscode-html-languageservice: 4.2.5 - vscode-languageserver: 7.0.0 + vscode-css-languageservice: 6.0.1 + vscode-html-languageservice: 5.0.0 + vscode-languageserver: 8.0.1 vscode-languageserver-protocol: 3.17.1 vscode-languageserver-textdocument: 1.0.5 vscode-languageserver-types: 3.17.1 @@ -2685,6 +2688,13 @@ packages: - typescript dev: false + /@astrojs/vue-language-integration/0.1.1: + resolution: {integrity: sha512-MPnZO41txVXkZWgN6UtI8ysFViBiCurRchsE/eZ2KFyQLQwB0rOk+FN7aeIIKOigV+Kosbwai50beuztkI4v/A==} + dependencies: + '@vue/compiler-sfc': 3.2.37 + '@vue/runtime-core': 3.2.37 + dev: false + /@babel/code-frame/7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -14812,6 +14822,10 @@ packages: resolution: {integrity: sha512-OxVmQLKMQbDZX1m8Ljuf26rzMUJ7lm3cnBAicqrB0qmo1qb/koH7EXayeHiZdiyc6Z0OnaHETW2JCoVHgTnGGA==} dev: true + /utfstring/2.0.2: + resolution: {integrity: sha512-dlLwDU6nUrUVsUbA3bUQ6LzRpt8cmJFNCarbESKFqZGMdivOFmzapOlQq54ifHXB9zgR00lKpcpCo6CITG2bjQ==} + dev: false + /util-deprecate/1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -14954,8 +14968,8 @@ packages: acorn-walk: 8.2.0 dev: true - /vscode-css-languageservice/5.4.2: - resolution: {integrity: sha512-DT7+7vfdT2HDNjDoXWtYJ0lVDdeDEdbMNdK4PKqUl2MS8g7PWt7J5G9B6k9lYox8nOfhCEjLnoNC3UKHHCR1lg==} + /vscode-css-languageservice/6.0.1: + resolution: {integrity: sha512-81n/eeYuJwQdvpoy6IK1258PtPbO720fl13FcJ5YQECPyHMFkmld1qKHwPJkyLbLPfboqJPM53ys4xW8v+iBVw==} dependencies: vscode-languageserver-textdocument: 1.0.5 vscode-languageserver-types: 3.17.1 @@ -14963,8 +14977,8 @@ packages: vscode-uri: 3.0.3 dev: false - /vscode-html-languageservice/4.2.5: - resolution: {integrity: sha512-dbr10KHabB9EaK8lI0XZW7SqOsTfrNyT3Nuj0GoPi4LjGKUmMiLtsqzfedIzRTzqY+w0FiLdh0/kQrnQ0tLxrw==} + /vscode-html-languageservice/5.0.0: + resolution: {integrity: sha512-KJG13z54aLszskp3ETf8b1EKDypr2Sf5RUsfR6OXmKqEl2ZUfyIxsWz4gbJWjPzoJZx/bGH0ZXVwxJ1rg8OKRQ==} dependencies: vscode-languageserver-textdocument: 1.0.5 vscode-languageserver-types: 3.17.1 @@ -14972,23 +14986,11 @@ packages: vscode-uri: 3.0.3 dev: false - /vscode-jsonrpc/6.0.0: - resolution: {integrity: sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==} - engines: {node: '>=8.0.0 || >=10.0.0'} - dev: false - /vscode-jsonrpc/8.0.1: resolution: {integrity: sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ==} engines: {node: '>=14.0.0'} dev: false - /vscode-languageserver-protocol/3.16.0: - resolution: {integrity: sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==} - dependencies: - vscode-jsonrpc: 6.0.0 - vscode-languageserver-types: 3.16.0 - dev: false - /vscode-languageserver-protocol/3.17.1: resolution: {integrity: sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg==} dependencies: @@ -15000,19 +15002,15 @@ packages: resolution: {integrity: sha512-1ah7zyQjKBudnMiHbZmxz5bYNM9KKZYz+5VQLj+yr8l+9w3g+WAhCkUkWbhMEdC5u0ub4Ndiye/fDyS8ghIKQg==} dev: false - /vscode-languageserver-types/3.16.0: - resolution: {integrity: sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==} - dev: false - /vscode-languageserver-types/3.17.1: resolution: {integrity: sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ==} dev: false - /vscode-languageserver/7.0.0: - resolution: {integrity: sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==} + /vscode-languageserver/8.0.1: + resolution: {integrity: sha512-sn7SjBwWm3OlmLtgg7jbM0wBULppyL60rj8K5HF0ny/MzN+GzPBX1kCvYdybhl7UW63V5V5tRVnyB8iwC73lSQ==} hasBin: true dependencies: - vscode-languageserver-protocol: 3.16.0 + vscode-languageserver-protocol: 3.17.1 dev: false /vscode-nls/5.0.1: From 8132127568bfb5e736623fcfa6da1c8bbb6b1d0a Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Tue, 12 Jul 2022 17:11:35 -0400 Subject: [PATCH 2/7] Fix lockfile --- pnpm-lock.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index deca4f0ed9bf..bd16a583ec91 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -546,7 +546,6 @@ importers: strip-ansi: ^7.0.1 supports-esm: ^1.0.0 tsconfig-resolver: ^3.0.1 - utfstring: ^2.0.2 vite: ^2.9.14 yargs-parser: ^21.0.1 zod: ^3.17.3 @@ -605,7 +604,6 @@ importers: strip-ansi: 7.0.1 supports-esm: 1.0.0 tsconfig-resolver: 3.0.1 - utfstring: 2.0.2 vite: 2.9.14_sass@1.53.0 yargs-parser: 21.0.1 zod: 3.17.3 @@ -14822,10 +14820,6 @@ packages: resolution: {integrity: sha512-OxVmQLKMQbDZX1m8Ljuf26rzMUJ7lm3cnBAicqrB0qmo1qb/koH7EXayeHiZdiyc6Z0OnaHETW2JCoVHgTnGGA==} dev: true - /utfstring/2.0.2: - resolution: {integrity: sha512-dlLwDU6nUrUVsUbA3bUQ6LzRpt8cmJFNCarbESKFqZGMdivOFmzapOlQq54ifHXB9zgR00lKpcpCo6CITG2bjQ==} - dev: false - /util-deprecate/1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} From 19a2bfa043c416f66bdf41794870b205840c18b9 Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Wed, 13 Jul 2022 11:19:32 -0400 Subject: [PATCH 3/7] Update to latest language-server version --- packages/astro/package.json | 2 +- pnpm-lock.yaml | 43 +++++-------------------------------- 2 files changed, 6 insertions(+), 39 deletions(-) diff --git a/packages/astro/package.json b/packages/astro/package.json index b578cc8a04e2..a78f399c17ff 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -83,7 +83,7 @@ }, "dependencies": { "@astrojs/compiler": "^0.18.2", - "@astrojs/language-server": "^0.19.4", + "@astrojs/language-server": "^0.20.0", "@astrojs/markdown-remark": "^0.11.5", "@astrojs/prism": "0.5.0", "@astrojs/telemetry": "^0.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd16a583ec91..0d7ddc579272 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -466,7 +466,7 @@ importers: packages/astro: specifiers: '@astrojs/compiler': ^0.18.2 - '@astrojs/language-server': ^0.19.4 + '@astrojs/language-server': ^0.20.0 '@astrojs/markdown-remark': ^0.11.5 '@astrojs/prism': 0.5.0 '@astrojs/telemetry': ^0.3.0 @@ -551,7 +551,7 @@ importers: zod: ^3.17.3 dependencies: '@astrojs/compiler': 0.18.2 - '@astrojs/language-server': 0.19.4 + '@astrojs/language-server': 0.20.0 '@astrojs/markdown-remark': link:../markdown/remark '@astrojs/prism': link:../astro-prism '@astrojs/telemetry': link:../telemetry @@ -2644,14 +2644,11 @@ packages: resolution: {integrity: sha512-R2lOpaif3hDju2/sE6OrKvnTMgrcLRJw+jAVih9pLA2ATgy2EnhYMhflRk1vQ6+YwuhyL6Lj/dRJFXgB7r70eg==} dev: false - /@astrojs/language-server/0.19.4: - resolution: {integrity: sha512-Po+/gLyetY2jka4x3jheQTGtD5hVOm6krGlv39ZdNNlQudcO9YuZhKgDa5BafRJb21DgFcH2BLb6lM7mR/fqHw==} + /@astrojs/language-server/0.20.0: + resolution: {integrity: sha512-A2zWnlZLcDtHISX18+f91pzTfz0SsZVvbcIDPQAVHk5ErpvdGEhJSEHhqY+wif5OXP37l+CVLVSnGzdmiXl5wg==} hasBin: true dependencies: - '@astrojs/svelte-language-integration': 0.1.6_typescript@4.6.4 - '@astrojs/vue-language-integration': 0.1.1 '@vscode/emmet-helper': 2.8.4 - lodash: 4.17.21 source-map: 0.7.4 typescript: 4.6.4 vscode-css-languageservice: 6.0.1 @@ -2677,22 +2674,6 @@ packages: vfile-message: 3.1.2 dev: false - /@astrojs/svelte-language-integration/0.1.6_typescript@4.6.4: - resolution: {integrity: sha512-nqczE674kz7GheKSWQwTOL6+NGHghc4INQox048UyHJRaIKHEbCPyFLDBDVY7QJH0jug1komCJ8OZXUn6Z3eLA==} - dependencies: - svelte: 3.49.0 - svelte2tsx: 0.5.11_ueozcsexptisi2awlbuwt6eqmq - transitivePeerDependencies: - - typescript - dev: false - - /@astrojs/vue-language-integration/0.1.1: - resolution: {integrity: sha512-MPnZO41txVXkZWgN6UtI8ysFViBiCurRchsE/eZ2KFyQLQwB0rOk+FN7aeIIKOigV+Kosbwai50beuztkI4v/A==} - dependencies: - '@vue/compiler-sfc': 3.2.37 - '@vue/runtime-core': 3.2.37 - dev: false - /@babel/code-frame/7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} @@ -11166,6 +11147,7 @@ packages: /lodash/4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true /log-symbols/4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} @@ -14171,21 +14153,6 @@ packages: svelte: 3.49.0 dev: false - /svelte2tsx/0.5.11_ueozcsexptisi2awlbuwt6eqmq: - resolution: {integrity: sha512-Is95G1wqNvEUJZ9DITRS2zfMwVJRZztMduPs1vJJ0cm65WUg/avBl5vBXjHycQL/qmFpaqa3NG4qWnf7bCHPag==} - peerDependencies: - svelte: ^3.24 - typescript: ^4.1.2 - peerDependenciesMeta: - typescript: - optional: true - dependencies: - dedent-js: 1.0.1 - pascal-case: 3.1.2 - svelte: 3.49.0 - typescript: 4.6.4 - dev: false - /tailwindcss/3.1.5: resolution: {integrity: sha512-bC/2dy3dGPqxMWAqFSRgQxVCfmO/31ZbeEp8s9DMDh4zgPZ5WW1gxRJkbBkXcTUIzaSUdhWrcsrSOe32ccgB4w==} engines: {node: '>=12.13.0'} From cb905ba894ccc75fba4f3347245d9da6cfa75eb0 Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Wed, 13 Jul 2022 13:52:31 -0400 Subject: [PATCH 4/7] Add simple tests --- packages/astro/src/cli/check/index.ts | 2 +- packages/astro/test/cli.test.js | 22 +++++++++++++++++++ .../astro-check-errors/astro.config.mjs | 6 +++++ .../fixtures/astro-check-errors/package.json | 8 +++++++ .../astro-check-errors/src/pages/index.astro | 15 +++++++++++++ .../astro-check-no-errors/astro.config.mjs | 6 +++++ .../astro-check-no-errors/package.json | 8 +++++++ .../src/pages/index.astro | 11 ++++++++++ packages/webapi/mod.d.ts | 22 +++++++++---------- 9 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 packages/astro/test/fixtures/astro-check-errors/astro.config.mjs create mode 100644 packages/astro/test/fixtures/astro-check-errors/package.json create mode 100644 packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro create mode 100644 packages/astro/test/fixtures/astro-check-no-errors/astro.config.mjs create mode 100644 packages/astro/test/fixtures/astro-check-no-errors/package.json create mode 100644 packages/astro/test/fixtures/astro-check-no-errors/src/pages/index.astro diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts index e88b4d5fefd9..06e641cd54ee 100644 --- a/packages/astro/src/cli/check/index.ts +++ b/packages/astro/src/cli/check/index.ts @@ -39,7 +39,7 @@ export async function check(astroConfig: AstroConfig) { diagnostics.forEach((diag) => { diag.diagnostics.forEach((d) => { - console.error(printDiagnostic(diag.filePath, diag.text, d)); + console.log(printDiagnostic(diag.filePath, diag.text, d)); switch (d.severity) { case DiagnosticSeverity.Error: { diff --git a/packages/astro/test/cli.test.js b/packages/astro/test/cli.test.js index 4134ee74df4f..2089cfc5421f 100644 --- a/packages/astro/test/cli.test.js +++ b/packages/astro/test/cli.test.js @@ -31,6 +31,28 @@ describe('astro cli', () => { expect(proc.stdout).to.include('Complete'); }); + it('astro check no errors', async () => { + let proc = undefined; + const projectRootURL = new URL('./fixtures/astro-check-no-errors/', import.meta.url); + try { + proc = await cli('check', '--root', fileURLToPath(projectRootURL)); + } catch (err) {} + + expect(proc?.stdout).to.include('0 errors'); + }); + + it('astro check has errors', async () => { + let stdout = undefined; + const projectRootURL = new URL('./fixtures/astro-check-errors/', import.meta.url); + try { + await cli('check', '--root', fileURLToPath(projectRootURL)); + } catch (err) { + stdout = err.toString(); + } + + expect(stdout).to.include('1 error'); + }); + it('astro dev welcome', async () => { const pkgURL = new URL('../package.json', import.meta.url); const pkgVersion = await fs.readFile(pkgURL, 'utf8').then((data) => JSON.parse(data).version); diff --git a/packages/astro/test/fixtures/astro-check-errors/astro.config.mjs b/packages/astro/test/fixtures/astro-check-errors/astro.config.mjs new file mode 100644 index 000000000000..db9a6db87e38 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-errors/astro.config.mjs @@ -0,0 +1,6 @@ +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [], +}); diff --git a/packages/astro/test/fixtures/astro-check-errors/package.json b/packages/astro/test/fixtures/astro-check-errors/package.json new file mode 100644 index 000000000000..30e9b96b99f0 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-errors/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/astro-check-errors", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro b/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro new file mode 100644 index 000000000000..c161df438c6b --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro @@ -0,0 +1,15 @@ +--- + console.log(doesntExist) +--- + + + + + + + Document + + +
Hello, Astro!
+ + diff --git a/packages/astro/test/fixtures/astro-check-no-errors/astro.config.mjs b/packages/astro/test/fixtures/astro-check-no-errors/astro.config.mjs new file mode 100644 index 000000000000..db9a6db87e38 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-no-errors/astro.config.mjs @@ -0,0 +1,6 @@ +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + integrations: [], +}); diff --git a/packages/astro/test/fixtures/astro-check-no-errors/package.json b/packages/astro/test/fixtures/astro-check-no-errors/package.json new file mode 100644 index 000000000000..6e7c91fdc5d0 --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-no-errors/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/astro-check-no-errors", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/astro-check-no-errors/src/pages/index.astro b/packages/astro/test/fixtures/astro-check-no-errors/src/pages/index.astro new file mode 100644 index 000000000000..49d10645690e --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-no-errors/src/pages/index.astro @@ -0,0 +1,11 @@ + + + + + + Document + + +
Hello, Astro!
+ + diff --git a/packages/webapi/mod.d.ts b/packages/webapi/mod.d.ts index e0372100e62e..b385e82a5e29 100644 --- a/packages/webapi/mod.d.ts +++ b/packages/webapi/mod.d.ts @@ -1,12 +1,12 @@ export { pathToPosix } from './lib/utils'; -export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter } from './mod.js'; -export declare const polyfill: { - (target: any, options?: PolyfillOptions): any; - internals(target: any, name: string): any; -}; -interface PolyfillOptions { - exclude?: string | string[]; - override?: Record; -} \ No newline at end of file +export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, } from './mod.js'; +export declare const polyfill: { + (target: any, options?: PolyfillOptions): any; + internals(target: any, name: string): any; +}; +interface PolyfillOptions { + exclude?: string | string[]; + override?: Record; +} \ No newline at end of file From 4a6524ee360d9ea1ff68e5a609fb183c85d99045 Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Wed, 13 Jul 2022 13:53:52 -0400 Subject: [PATCH 5/7] Fix lock file, again --- pnpm-lock.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d7ddc579272..083f52c1bf60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1087,6 +1087,18 @@ importers: '@astrojs/preact': link:../../../../integrations/preact astro: link:../../.. + packages/astro/test/fixtures/astro-check-errors: + specifiers: + astro: workspace:* + dependencies: + astro: link:../../.. + + packages/astro/test/fixtures/astro-check-no-errors: + specifiers: + astro: workspace:* + dependencies: + astro: link:../../.. + packages/astro/test/fixtures/astro-children: specifiers: '@astrojs/preact': workspace:* From 091b09b1df17ecfaee8d0848ec7228266b1bec0d Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Mon, 18 Jul 2022 14:25:43 -0400 Subject: [PATCH 6/7] Fix `astro check` not working on Windows, speeds up tests --- packages/astro/src/cli/check/index.ts | 24 +++++++++++-------- packages/astro/test/cli.test.js | 3 +++ .../astro-check-errors/src/pages/index.astro | 1 + .../fixtures/astro-check-errors/tsconfig.json | 2 ++ .../astro-check-no-errors/tsconfig.json | 2 ++ 5 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 packages/astro/test/fixtures/astro-check-errors/tsconfig.json create mode 100644 packages/astro/test/fixtures/astro-check-no-errors/tsconfig.json diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts index 06e641cd54ee..79571de0fc5e 100644 --- a/packages/astro/src/cli/check/index.ts +++ b/packages/astro/src/cli/check/index.ts @@ -6,7 +6,6 @@ import glob from 'fast-glob'; import * as fs from 'fs'; import { bold, dim, red, yellow } from 'kleur/colors'; import ora from 'ora'; -import * as path from 'path'; import { fileURLToPath, pathToFileURL } from 'url'; import { printDiagnostic } from './print.js'; @@ -22,10 +21,10 @@ export async function check(astroConfig: AstroConfig) { const root = astroConfig.root; - const spinner = ora(` Getting diagnostics in ${fileURLToPath(root)}…`).start(); + const spinner = ora(` Getting diagnostics for Astro files in ${fileURLToPath(root)}…`).start(); let checker = new AstroCheck(root.toString()); - await openAllDocuments(root, [], checker); + const filesCount = await openAllDocuments(root, [], checker); let diagnostics = await checker.getDiagnostics(); @@ -60,7 +59,7 @@ export async function check(astroConfig: AstroConfig) { console.log( [ - bold('Result: '), + bold(`Result (${filesCount} file${filesCount === 1 ? '' : 's'}): `), bold(red(`${result.errors} ${result.errors === 1 ? 'error' : 'errors'}`)), bold(yellow(`${result.warnings} ${result.warnings === 1 ? 'warning' : 'warnings'}`)), dim(`${result.hints} ${result.hints === 1 ? 'hint' : 'hints'}\n`), @@ -71,22 +70,27 @@ export async function check(astroConfig: AstroConfig) { return exitCode; } +/** + * Open all Astro files in the given directory and return the number of files found. + */ async function openAllDocuments( workspaceUri: URL, filePathsToIgnore: string[], checker: AstroCheck -) { +): Promise { const files = await glob('**/*.astro', { - cwd: workspaceUri.pathname, + cwd: fileURLToPath(workspaceUri), ignore: ['node_modules/**'].concat(filePathsToIgnore.map((ignore) => `${ignore}/**`)), + absolute: true, }); - const absFilePaths = files.map((f) => path.resolve(workspaceUri.pathname, f)); - for (const absFilePath of absFilePaths) { - const text = fs.readFileSync(absFilePath, 'utf-8'); + for (const file of files) { + const text = fs.readFileSync(file, 'utf-8'); checker.upsertDocument({ - uri: pathToFileURL(absFilePath).toString(), + uri: pathToFileURL(file).toString(), text, }); } + + return files.length; } diff --git a/packages/astro/test/cli.test.js b/packages/astro/test/cli.test.js index 2089cfc5421f..4f55927bb646 100644 --- a/packages/astro/test/cli.test.js +++ b/packages/astro/test/cli.test.js @@ -44,6 +44,9 @@ describe('astro cli', () => { it('astro check has errors', async () => { let stdout = undefined; const projectRootURL = new URL('./fixtures/astro-check-errors/', import.meta.url); + + // When `astro check` finds errors, it returns an error code. As such, we need to wrap this + // in a try/catch because otherwise Mocha will always report this test as a fail try { await cli('check', '--root', fileURLToPath(projectRootURL)); } catch (err) { diff --git a/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro b/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro index c161df438c6b..956ee0101668 100644 --- a/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro +++ b/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro @@ -2,6 +2,7 @@ console.log(doesntExist) --- + diff --git a/packages/astro/test/fixtures/astro-check-errors/tsconfig.json b/packages/astro/test/fixtures/astro-check-errors/tsconfig.json new file mode 100644 index 000000000000..d64f4787597c --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-errors/tsconfig.json @@ -0,0 +1,2 @@ +// Having a `tsconfig.json`, even empty speeds up the test massively since TypeScript does not have to look for one +{} diff --git a/packages/astro/test/fixtures/astro-check-no-errors/tsconfig.json b/packages/astro/test/fixtures/astro-check-no-errors/tsconfig.json new file mode 100644 index 000000000000..d64f4787597c --- /dev/null +++ b/packages/astro/test/fixtures/astro-check-no-errors/tsconfig.json @@ -0,0 +1,2 @@ +// Having a `tsconfig.json`, even empty speeds up the test massively since TypeScript does not have to look for one +{} From 4c0494ab0d9d63a62f0cc30b06a46a272397c7e0 Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Mon, 18 Jul 2022 15:31:38 -0400 Subject: [PATCH 7/7] Add changeest --- .changeset/rich-bats-tell.md | 18 ++++++++++++++++++ packages/astro/src/cli/check/print.ts | 4 ++-- .../astro-check-errors/src/pages/index.astro | 1 - 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 .changeset/rich-bats-tell.md diff --git a/.changeset/rich-bats-tell.md b/.changeset/rich-bats-tell.md new file mode 100644 index 000000000000..1caaa5124616 --- /dev/null +++ b/.changeset/rich-bats-tell.md @@ -0,0 +1,18 @@ +--- +'astro': patch +--- + +Fixed many long-standing issues with `astro check` + +- Fixed it not working on Windows at all +- Fixed red squiggles not showing in the proper place in certain contexts, notably with strings using non-latin characters +- Fixed IDE links pointing to the wrong line number and character +- Fixed line numbers being off by one +- Fixed IDE links not working when the project wasn't at the root of the folder + +Additionally added some features: + +- Added more pretty colors +- Fixed it not working at all on Windows +- Warnings and hints are now printed alongside errors +- Surrounding lines are now shown when relevant (aka not empty) diff --git a/packages/astro/src/cli/check/print.ts b/packages/astro/src/cli/check/print.ts index e41115f67375..26866c051e51 100644 --- a/packages/astro/src/cli/check/print.ts +++ b/packages/astro/src/cli/check/print.ts @@ -9,7 +9,7 @@ import { gray, red, white, - yellow + yellow, } from 'kleur/colors'; import stringWidth from 'string-width'; @@ -28,7 +28,7 @@ export function printDiagnostic(filePath: string, text: string, diag: Diagnostic `${IDEFilePath} ${bold(getColorForSeverity(diag, getStringForSeverity(diag)))}: ${diag.message}` ); - // Optionally add the before the error to add context if not empty + // Optionally add the line before the error to add context if not empty const previousLine = getLine(diag.range.start.line - 1, text); if (previousLine) { result.push(`${getPrintableLineNumber(realStartLine - 1)} ${gray(previousLine)}`); diff --git a/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro b/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro index 956ee0101668..c161df438c6b 100644 --- a/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro +++ b/packages/astro/test/fixtures/astro-check-errors/src/pages/index.astro @@ -2,7 +2,6 @@ console.log(doesntExist) --- -