Skip to content

Commit

Permalink
fix: drop node-fetch dependency (#4957)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason3S committed Nov 7, 2023
1 parent 62ed6ed commit 7747571
Show file tree
Hide file tree
Showing 19 changed files with 104 additions and 228 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@
"@rollup/plugin-typescript": "^11.1.5",
"@tsconfig/node18": "^18.2.2",
"@types/node": "^18.18.8",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"@vitest/coverage-istanbul": "^0.34.6",
"conventional-changelog-conventionalcommits": "^7.0.2",
"eslint": "^8.53.0",
Expand Down
4 changes: 1 addition & 3 deletions packages/cspell-io/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,10 @@
"node": ">=18"
},
"devDependencies": {
"@types/node-fetch": "^2.6.9",
"lorem-ipsum": "^2.0.8",
"typescript": "^5.2.2"
},
"dependencies": {
"@cspell/cspell-service-bus": "workspace:*",
"node-fetch": "^2.7.0"
"@cspell/cspell-service-bus": "workspace:*"
}
}
14 changes: 13 additions & 1 deletion packages/cspell-io/src/node/file/FetchError.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,22 @@ describe('FetchError', () => {
${'http://google.com'} | ${403} | ${undefined} | ${oc({ code: 'EACCES', message: 'Permission denied.' })}
${'http://google.com'} | ${403} | ${'Not good'} | ${oc({ code: 'EACCES', message: 'Not good' })}
${'http://google.com'} | ${500} | ${''} | ${oc({ code: 'ECONNREFUSED', message: 'Fatal Error' })}
`('create', ({ url, status, message, expected }) => {
`('create $status $message', ({ url, status, message, expected }) => {
url = toURL(url);
const e = FetchUrlError.create(url, status, message);
expect(e).toEqual(expected);
expect(e.url).toBe(url);
});

test.each`
url | error | expected
${'http://google.com'} | ${new Error('Not good')} | ${oc({ code: undefined, message: 'Not good' })}
${'http://google.com'} | ${Object.assign(new Error('Type Error'), { code: 'ENOENT', message: 'Not found' })} | ${oc({ code: 'ENOENT', message: 'Not found' })}
${'http://google.com'} | ${Object.assign(new Error('Not found'), { cause: { code: 'ENOTFOUND', message: 'Get Address failed.' } })} | ${oc({ code: 'ENOTFOUND', message: 'Get Address failed.' })}
`('fromError $error', ({ url, error, expected }) => {
url = toURL(url);
const e = FetchUrlError.fromError(url, error);
expect(e).toEqual(expected);
expect(e.url).toBe(url);
});
});
33 changes: 33 additions & 0 deletions packages/cspell-io/src/node/file/FetchError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,37 @@ export class FetchUrlError extends Error implements NodeJS.ErrnoException {
return new FetchUrlError(message || 'Permission denied.', 'EACCES', status, url);
return new FetchUrlError(message || 'Fatal Error', 'ECONNREFUSED', status, url);
}

static fromError(url: URL, e: Error): FetchUrlError {
const cause = getCause(e);
if (cause) {
return new FetchUrlError(cause.message, cause.code, undefined, url);
}
if (isNodeError(e)) {
return new FetchUrlError(e.message, e.code, undefined, url);
}
return new FetchUrlError(e.message, undefined, undefined, url);
}
}

export function isNodeError(e: unknown): e is NodeJS.ErrnoException {
if (e instanceof Error && 'code' in e && typeof e.code === 'string') return true;
if (e && typeof e === 'object' && 'code' in e && typeof e.code === 'string') return true;
return false;
}

export function isError(e: unknown): e is Error {
return e instanceof Error;
}

interface ErrorWithOptionalCause extends Error {
cause?: NodeJS.ErrnoException;
}

export function isErrorWithOptionalCause(e: unknown): e is ErrorWithOptionalCause {
return !!e && typeof e === 'object' && 'cause' in e && isNodeError(e.cause);
}

export function getCause(e: unknown): NodeJS.ErrnoException | undefined {
return isErrorWithOptionalCause(e) ? e.cause : undefined;
}
8 changes: 7 additions & 1 deletion packages/cspell-io/src/node/file/fetch.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest';

import { fetch, fetchHead } from './fetch.js';
import { fetchHead, fetchURL } from './fetch.js';

describe('fetch', () => {
test('fetch url', async () => {
Expand All @@ -10,6 +10,12 @@ describe('fetch', () => {
expect(await response.text()).toMatch('$schema');
});

test('fetchURL', async () => {
const url = new URL('https://raw.githubusercontent.com/streetsidesoftware/cspell/main/tsconfig.json');
const response = await fetchURL(url);
expect(response).toBeInstanceOf(Buffer);
});

test.each`
url
${'https://raw.githubusercontent.com/streetsidesoftware/cspell/main/packages/cspell-io/samples/cities.txt'}
Expand Down
42 changes: 27 additions & 15 deletions packages/cspell-io/src/node/file/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import type { Headers, RequestInit, Response } from 'node-fetch';
import nodeFetch from 'node-fetch';

import { FetchUrlError } from './FetchError.js';
import { FetchUrlError, isError } from './FetchError.js';

export async function fetchHead(request: string | URL): Promise<Headers> {
const r = await fetch(request, { method: 'HEAD' });
return r.headers;
const url = toURL(request);
try {
const r = await fetch(url, { method: 'HEAD' });
return r.headers;
} catch (e) {
console.warn('fetchHead Error %o', e);
if (isError(e)) {
throw FetchUrlError.fromError(url, e);
}
throw e;
}
}

export async function fetchURL(url: URL): Promise<Buffer> {
const response = await fetch(url);
if (!response.ok) {
throw FetchUrlError.create(url, response.status);
try {
const response = await fetch(url);
if (!response.ok) {
throw FetchUrlError.create(url, response.status);
}
return Buffer.from(await response.arrayBuffer());
} catch (e) {
// console.warn('fetchURL Error %o', e);
if (e instanceof FetchUrlError) throw e;
if (isError(e)) {
throw FetchUrlError.fromError(url, e);
}
throw e;
}
return Buffer.from(await response.arrayBuffer());
}

export function fetch(url: string | URL, init?: RequestInit): Promise<Response> {
/// This is a n issue with how TypeScript handles packages without `type` being set.
// @ts-ignore
return nodeFetch(url, init);
function toURL(url: string | URL): URL {
return typeof url === 'string' ? new URL(url) : url;
}
10 changes: 3 additions & 7 deletions packages/cspell-io/src/node/file/fileReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import * as zlib from 'zlib';
import { decode } from '../../common/encode-decode.js';
import { createDecoderTransformer } from '../../common/transformers.js';
import type { BufferEncoding } from '../../models/BufferEncoding.js';
import { fetch } from './fetch.js';
import { FetchUrlError } from './FetchError.js';
import { fetchURL } from './fetch.js';
import { isFileURL, isSupportedURL, isZipped, toURL } from './util.js';

const defaultEncoding: BufferEncoding = 'utf8';
Expand All @@ -32,11 +31,8 @@ function _readFileText(url: URL, encoding?: BufferEncoding): Promise<string> {
}

async function _fetchTextFromURL(url: URL, encoding?: BufferEncoding): Promise<string> {
const response = await fetch(url);
if (!response.ok) {
throw FetchUrlError.create(url, response.status);
}
return _readText(() => response.body, isZipped(url), encoding);
const buffer = await fetchURL(url);
return _readText(() => Stream.Readable.from(buffer), isZipped(url), encoding);
}

async function _readText(
Expand Down
1 change: 0 additions & 1 deletion packages/cspell-lib/src/lib/Settings/GlobalSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export interface GlobalSettingsWithSource extends Partial<GlobalCSpellSettings>
source: CSpellSettingsWithSourceTrace['source'];
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface GlobalCSpellSettings extends Required<Pick<CSpellSettings, 'import'>> {}

export function getRawGlobalSettings(): GlobalSettingsWithSource {
Expand Down
1 change: 0 additions & 1 deletion packages/cspell-lib/src/lib/textValidation/checkText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ export enum IncludeExcludeFlag {
EXCLUDE = 'E',
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface CheckTextOptions extends DocumentValidatorOptions {}

/**
Expand Down
1 change: 0 additions & 1 deletion packages/cspell-lib/src/lib/util/wordSplitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export interface TextOffsetWithValid extends TextOffset {
isFound: boolean;
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface SplitOptions extends WordBreakOptions {}

export function split(
Expand Down
1 change: 0 additions & 1 deletion packages/cspell-trie-lib/src/lib/TrieNode/trie-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export function countWords(root: TrieNode): number {

function walk(n: TrieNode) {
if (visited.has(n)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return visited.get(n)!;
}

Expand Down
1 change: 0 additions & 1 deletion packages/cspell-trie-lib/src/lib/convertToTrieRefNodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ export function convertToTrieRefNodes(root: TrieNode): IterableIterator<TrieRefN
function* walkByRollup(n: TrieNode): IterableIterator<TrieRefNode> {
if (cached.has(n)) return;
if (n.f && !n.c) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
cached.set(n, cached.get(eow)!);
return;
}
Expand Down
2 changes: 0 additions & 2 deletions packages/cspell-trie-lib/src/lib/utils/secondChanceCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export class SecondChanceCache<Key, Value> {
public has(key: Key) {
if (this.map0.has(key)) return true;
if (this.map1.has(key)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.set(key, this.get1(key)!);
return true;
}
Expand Down Expand Up @@ -47,7 +46,6 @@ export class SecondChanceCache<Key, Value> {

private get1(key: Key): Value | undefined {
if (this.map1.has(key)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const v = this.map1.get(key)!;
this.map1.delete(key);
this.map0.set(key, v);
Expand Down
2 changes: 0 additions & 2 deletions packages/cspell-types/src/features.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-empty-interface */

/**
* These are experimental features and are subject to change or removal without notice.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/hunspell-reader/src/aff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export function processRules(affInfo: AffInfo): Map<string, Rule> {
.map((pfx) => ({ id: pfx.id, type: 'pfx', pfx }));
const flagRules: Sequence<Rule> = GS.sequenceFromObject(affInfo as AffTransformFlags)
.filter(([key, value]) => !!affFlag[key] && !!value)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion

.map(([key, value]) => ({ id: value!, type: 'flag', flags: affFlag[key] }));

const rules = sfxRules
Expand Down

0 comments on commit 7747571

Please sign in to comment.