Skip to content

Commit

Permalink
fix: stdin urls on the command line (#6345)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason3S authored Oct 11, 2024
1 parent c52ca70 commit abc7548
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 24 deletions.
5 changes: 2 additions & 3 deletions packages/cspell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
"build": "tsc -p . && pnpm run build:api",
"build:api": "rollup -c rollup.config.mjs",
"build:esm": "tsc -p .",
"build:lib": "tsc -b src/lib/tsconfig.json -f",
"build:readme": "pnpm build:readme:help",
"build:readme:help": "pnpm build:readme:help:lint && pnpm build:readme:help:trace && inject-markdown README.md && prettier -w README.md",
"build:readme:help:lint": "./bin.mjs lint --help > static/help-lint.txt",
Expand All @@ -52,8 +51,8 @@
"coverage": "vitest run --coverage",
"test:watch": "vitest",
"test": "vitest run",
"watch": "tsc -b . -w -f",
"compile": "tsc -b . -f",
"watch": "tsc -p . -w",
"compile": "tsc -p .",
"test-watch": "vitest",
"version": "node ./tools/patch-version.mjs && git add .",
"prepublishOnly": "pnpm run clean-build",
Expand Down
5 changes: 3 additions & 2 deletions packages/cspell/src/app/util/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const UTF8 = 'utf8' as const;
export const STDIN = 'stdin' as const;
export const STDINProtocol = 'stdin://' as const;
export const FileProtocol = 'file://' as const;
export const STDINProtocol = 'stdin:' as const;
export const STDINUrlPrefix = 'stdin://' as const;
export const FileUrlPrefix = 'file://' as const;
4 changes: 2 additions & 2 deletions packages/cspell/src/app/util/fileHelper.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as path from 'node:path';
import { fileURLToPath } from 'node:url';
import { fileURLToPath, pathToFileURL } from 'node:url';

import getStdin from 'get-stdin';
import { afterEach, describe, expect, test, vi } from 'vitest';
Expand Down Expand Up @@ -119,7 +119,7 @@ describe('fileHelper', () => {
${'not_found'} | ${__dirname} | ${path.join(__dirname, 'not_found')}
${'not_found'} | ${undefined} | ${path.resolve('not_found')}
${'stdin'} | ${undefined} | ${'stdin://'}
${'stdin://source.ts'} | ${undefined} | ${'stdin://' + path.resolve('source.ts')}
${'stdin://source.ts'} | ${undefined} | ${pathToFileURL('source.ts').href.replace(/^file:/, 'stdin:')}
`('resolveFilename $filename $cwd', async ({ filename, cwd, expected }) => {
expect(resolveFilename(filename, cwd)).toBe(expected);
});
Expand Down
37 changes: 20 additions & 17 deletions packages/cspell/src/app/util/fileHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import { fileToDocument, isBinaryFile as isUriBinaryFile } from 'cspell-lib';
import getStdin from 'get-stdin';

import { asyncAwait, asyncFlatten, asyncMap, asyncPipe, mergeAsyncIterables } from './async.js';
import { FileProtocol, STDIN, STDINProtocol, UTF8 } from './constants.js';
import { FileUrlPrefix, STDIN, STDINProtocol, STDINUrlPrefix, UTF8 } from './constants.js';
import { IOError, toApplicationError, toError } from './errors.js';
import type { GlobOptions } from './glob.js';
import { globP } from './glob.js';
import { readStdin } from './stdin.js';
import { isStdinUrl, resolveStdinUrl } from './stdinUrl.js';
import { clean } from './util.js';

export interface ConfigInfo {
Expand Down Expand Up @@ -67,7 +68,7 @@ export function fileInfoToDocument(
languageId = languageId || undefined;
locale = locale || undefined;

const uri = filenameToUrlString(filename);
const uri = filenameToUrl(filename);

if (uri.href.startsWith(STDINProtocol)) {
return clean({
Expand All @@ -81,18 +82,17 @@ export function fileInfoToDocument(
return fileToDocument(uri.href, text, languageId, locale);
}

export function filenameToUrlString(filename: string, cwd = '.'): URL {
export function filenameToUrl(filename: string, cwd = '.'): URL {
const cwdURL = toFileDirURL(cwd);
if (filename === STDIN) return new URL('stdin:///');
if (filename.startsWith(STDINProtocol)) {
const filePath = filename.slice(STDINProtocol.length);
return toFileURL(filePath, cwdURL);
if (isStdinUrl(filename)) {
return new URL(resolveStdinUrl(filename, cwd));
}
return toFileURL(filename, cwdURL);
}

export function filenameToUri(filename: string, cwd?: string): URL {
return toURL(filenameToUrlString(filename, cwd));
return toURL(filenameToUrl(filename, cwd));
}

export function isBinaryFile(filename: string, cwd?: string): boolean {
Expand All @@ -107,15 +107,15 @@ export interface ReadFileInfoResult extends FileInfo {

export function resolveFilename(filename: string, cwd?: string): string {
cwd = cwd || process.cwd();
if (filename === STDIN) return STDINProtocol;
if (filename.startsWith(FileProtocol)) {
const url = new URL(filename.slice(FileProtocol.length), pathToFileURL(cwd + path.sep));
if (filename === STDIN) return STDINUrlPrefix;
if (filename.startsWith(FileUrlPrefix)) {
const url = new URL(filename.slice(FileUrlPrefix.length), pathToFileURL(cwd + path.sep));
return fileURLToPath(url);
}
const scheme = filename.startsWith(STDINProtocol) ? STDINProtocol : '';
const pathname = filename.slice(scheme.length);

return scheme + path.resolve(cwd, pathname);
if (isStdinUrl(filename)) {
return resolveStdinUrl(filename, cwd);
}
return path.resolve(cwd, filename);
}

export function readFileInfo(
Expand Down Expand Up @@ -149,9 +149,7 @@ export function readFile(filename: string, encoding: BufferEncoding = UTF8): Pro
export async function findFiles(globPatterns: string[], options: GlobOptions): Promise<string[]> {
const stdin: string[] = [];
const globPats = globPatterns.filter((filename) =>
filename !== STDIN && !filename.startsWith(STDINProtocol) && !filename.startsWith(FileProtocol)
? true
: (stdin.push(filename), false),
!isStdin(filename) && !filename.startsWith(FileUrlPrefix) ? true : (stdin.push(filename), false),
);
const globResults = globPats.length ? await globP(globPats, options) : [];
const cwd = options.cwd || process.cwd();
Expand Down Expand Up @@ -205,7 +203,12 @@ export async function readFileListFile(listFile: string): Promise<string[]> {
}
}

function isStdin(filename: string): boolean {
return filename === STDIN || isStdinUrl(filename);
}

export async function isFile(filename: string): Promise<boolean> {
if (isStdin(filename)) return true;
try {
const stat = await fsp.stat(filename);
return stat.isFile();
Expand Down
31 changes: 31 additions & 0 deletions packages/cspell/src/app/util/stdinUrl.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Path from 'node:path';
import { fileURLToPath } from 'node:url';

import { describe, expect, test } from 'vitest';

import { isStdinUrl, resolveStdinUrl } from './stdinUrl.js';

const filenameURL = new URL(import.meta.url);
const __filename = fileURLToPath(import.meta.url);
const __dirname = Path.dirname(__filename);
const dirUrl = new URL('./', import.meta.url);
const stdinUrl = dirUrl.href.replace(/^file:/, 'stdin:');

describe('stdinUrl', () => {
test('isStdinUrl', () => {
expect(isStdinUrl('stdin://')).toBe(true);
expect(isStdinUrl('stdin:')).toBe(true);
expect(isStdinUrl('stdin://foo')).toBe(true);
});

test.each`
url | expected
${'stdin://'} | ${stdinUrl}
${'stdin:package.json'} | ${new URL('package.json', stdinUrl).href}
${'stdin:./package.json'} | ${new URL('package.json', stdinUrl).href}
${'stdin:' + __filename} | ${new URL(filenameURL.pathname, stdinUrl).href}
${'stdin://' + __filename} | ${new URL(filenameURL.pathname, stdinUrl).href}
`('resolveStdinUrl', ({ url, expected }) => {
expect(resolveStdinUrl(url, __dirname)).toBe(expected);
});
});
28 changes: 28 additions & 0 deletions packages/cspell/src/app/util/stdinUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import assert from 'node:assert';
import Path from 'node:path';
import { pathToFileURL } from 'node:url';

import { STDINProtocol } from './constants.js';

export function isStdinUrl(url: string | URL): boolean {
if (url instanceof URL) {
return url.protocol === STDINProtocol;
}
return url.startsWith(STDINProtocol);
}

/**
* Normalize and resolve a stdin url.
* @param url - stdin url to resolve.
* @param cwd - file path to resolve relative paths against.
* @returns
*/
export function resolveStdinUrl(url: string, cwd: string): string {
assert(url.startsWith(STDINProtocol), `Expected url to start with ${STDINProtocol}`);
const path = url
.slice(STDINProtocol.length)
.replace(/^\/\//, '')
.replace(/^\/([a-z]:)/i, '$1');
const fileUrl = pathToFileURL(Path.resolve(cwd, path));
return fileUrl.toString().replace(/^file:/, STDINProtocol) + (path ? '' : '/');
}

0 comments on commit abc7548

Please sign in to comment.