From 405502b09f7cf26a9699643c8713ba89c1516781 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 26 Jun 2024 16:51:38 -0400 Subject: [PATCH] Fix loading projects on Windows network drives (#996) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Improve support on windows network shares * Don’t use network share paths on Windows Some bugs in enhanced-resolve prevent this from working currently * Update changelog --- .../src/project-locator.ts | 20 ++++++++--- .../src/projects.ts | 4 +-- .../src/util/getModuleDependencies.ts | 2 +- .../src/util/resolveFrom.ts | 10 ++++++ .../tailwindcss-language-server/src/utils.ts | 34 +++++++++++++++++++ packages/vscode-tailwindcss/CHANGELOG.md | 2 +- 6 files changed, 63 insertions(+), 9 deletions(-) diff --git a/packages/tailwindcss-language-server/src/project-locator.ts b/packages/tailwindcss-language-server/src/project-locator.ts index e102b279..6eaf58d6 100644 --- a/packages/tailwindcss-language-server/src/project-locator.ts +++ b/packages/tailwindcss-language-server/src/project-locator.ts @@ -3,7 +3,6 @@ import * as path from 'node:path' import * as fs from 'node:fs/promises' import glob from 'fast-glob' import picomatch from 'picomatch' -import normalizePath from 'normalize-path' import type { Settings } from '@tailwindcss/language-service/src/util/state' import { CONFIG_GLOB, CSS_GLOB } from './lib/constants' import { readCssFile } from './util/css' @@ -14,9 +13,8 @@ import { CacheMap } from './cache-map' import { getPackageRoot } from './util/get-package-root' import resolveFrom from './util/resolveFrom' import { type Feature, supportedFeatures } from '@tailwindcss/language-service/src/features' -import { pathToFileURL } from 'node:url' import { resolveCssImports } from './resolve-css-imports' -import { normalizeDriveLetter } from './utils' +import { normalizeDriveLetter, normalizePath, pathToFileURL } from './utils' export interface ProjectConfig { /** The folder that contains the project */ @@ -244,8 +242,20 @@ export class ProjectLocator { concurrency: Math.max(os.cpus().length, 1), }) - // Resolve symlinks for all found files - files = await Promise.all(files.map(async (file) => normalizePath(await fs.realpath(file)))) + files = await Promise.all( + files.map(async (file) => { + // Resolve symlinks for all found files + let actualPath = await fs.realpath(file) + + // Ignore network paths on Windows. Resolving relative paths on a + // netshare throws in `enhanced-resolve` :/ + if (actualPath.startsWith('\\') && process.platform === 'win32') { + return normalizePath(file) + } + + return normalizePath(actualPath) + }), + ) // Deduplicate the list of files and sort them for deterministic results // across environments diff --git a/packages/tailwindcss-language-server/src/projects.ts b/packages/tailwindcss-language-server/src/projects.ts index bbed4f77..5904ee91 100644 --- a/packages/tailwindcss-language-server/src/projects.ts +++ b/packages/tailwindcss-language-server/src/projects.ts @@ -20,7 +20,6 @@ import { FileChangeType } from 'vscode-languageserver/node' import type { TextDocument } from 'vscode-languageserver-textdocument' import { URI } from 'vscode-uri' import { showError, SilentError } from './util/error' -import normalizePath from 'normalize-path' import * as path from 'path' import * as fs from 'fs' import findUp from 'find-up' @@ -70,14 +69,15 @@ import { clearRequireCache, withFallback, isObject, + pathToFileURL, changeAffectsFile, + normalizePath, } from './utils' import type { DocumentService } from './documents' import type { ProjectConfig } from './project-locator' import { supportedFeatures } from '@tailwindcss/language-service/src/features' import { loadDesignSystem } from './util/v4' import { readCssFile } from './util/css' -import { pathToFileURL } from 'url' const colorNames = Object.keys(namedColors) diff --git a/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts b/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts index fe14c2b7..8b700ee9 100644 --- a/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts +++ b/packages/tailwindcss-language-server/src/util/getModuleDependencies.ts @@ -1,7 +1,7 @@ // https://github.com/tailwindlabs/tailwindcss/blob/bac5ecf0040aa9a788d1b22d706506146ee831ff/src/lib/getModuleDependencies.js import fs from 'fs' import path from 'path' -import normalizePath from 'normalize-path' +import { normalizePath } from '../utils' let jsExtensions = ['.js', '.cjs', '.mjs'] diff --git a/packages/tailwindcss-language-server/src/util/resolveFrom.ts b/packages/tailwindcss-language-server/src/util/resolveFrom.ts index 04a09c1c..8fbc37fe 100644 --- a/packages/tailwindcss-language-server/src/util/resolveFrom.ts +++ b/packages/tailwindcss-language-server/src/util/resolveFrom.ts @@ -1,4 +1,5 @@ import { equal } from '@tailwindcss/language-service/src/util/array' +import * as path from 'node:path' import { createResolver } from './resolve' let pnpApi: any @@ -16,8 +17,17 @@ export function setPnpApi(newPnpApi: any): void { } export default function resolveFrom(from?: string, id?: string): string { + // Network share path on Windows if (id.startsWith('\\\\')) return id + // Normalized network share path on Windows + if (id.startsWith('//') && path.sep === '\\') return id + + // Normalized network share path on Windows + if (from.startsWith('//') && path.sep === '\\') { + from = '\\\\' + from.slice(2) + } + let newExtensions = Object.keys(require.extensions) if (!equal(newExtensions, extensions)) { extensions = newExtensions diff --git a/packages/tailwindcss-language-server/src/utils.ts b/packages/tailwindcss-language-server/src/utils.ts index 58baf74c..8b9d8843 100644 --- a/packages/tailwindcss-language-server/src/utils.ts +++ b/packages/tailwindcss-language-server/src/utils.ts @@ -1,5 +1,8 @@ import Module from 'node:module' import path from 'node:path' +import { URI } from 'vscode-uri' +import normalizePathBase from 'normalize-path' +import { pathToFileURL as pathToFileURLBase } from 'node:url' export function withoutLogs(getter: () => T): T { let fns = { @@ -89,3 +92,34 @@ export function changeAffectsFile(change: string, files: string[]): boolean { } return false } + +export function normalizePath(originalPath: string) { + let normalized = normalizePathBase(originalPath) + + // This is Windows network share but the normalize path had one of the leading + // slashes stripped so we need to add it back + if ( + originalPath.startsWith('\\\\') && + normalized.startsWith('/') && + !normalized.startsWith('//') + ) { + return `/${normalized}` + } + + return normalized +} + +export function pathToFileURL(filepath: string) { + try { + return pathToFileURLBase(filepath) + } catch (err) { + if (process.platform !== 'win32') throw err + + // If `pathToFileURL` failsed on windows it's probably because the path was + // a windows network share path and there were mixed slashes. + // Fix the path and try again. + filepath = URI.file(filepath).fsPath + + return pathToFileURLBase(filepath) + } +} diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index 02f989f4..63742ded 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -2,7 +2,7 @@ ## Prerelease -- Nothing yet! +- Fix loading projects on Windows network drives ([#996](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/996)) ## 0.12.1