From 3d4708e42d1ac6520481351ef439771d26dd22d0 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Wed, 15 Nov 2023 09:12:19 +0100 Subject: [PATCH 1/9] refactor: convert cspell-config-lib to ESM --- .eslintrc.js | 13 +----- packages/cspell-config-lib/jest.config.js | 1 - packages/cspell-config-lib/package.json | 11 +++-- .../src/CSpellConfigFile.test.ts | 3 +- .../cspell-config-lib/src/CSpellConfigFile.ts | 2 +- .../src/CSpellConfigFileReaderWriter.test.ts | 28 +++++------ .../src/CSpellConfigFileReaderWriter.ts | 6 +-- .../cspell-config-lib/src/Deserializer.ts | 2 +- .../src/__snapshots__/index.test.ts.snap | 46 +++++++++---------- .../src/createReaderWriter.test.ts | 14 +++--- .../src/createReaderWriter.ts | 10 ++-- .../src/deserializers/cspellJson.test.ts | 8 ++-- .../src/deserializers/cspellJson.ts | 8 ++-- .../src/deserializers/cspellYaml.test.ts | 5 +- .../src/deserializers/cspellYaml.ts | 8 ++-- .../src/deserializers/index.test.ts | 4 +- .../src/deserializers/index.ts | 8 ++-- .../src/deserializers/packageJson.test.ts | 8 ++-- .../src/deserializers/packageJson.ts | 8 ++-- .../src/deserializers/util.test.ts | 4 +- packages/cspell-config-lib/src/index.test.ts | 9 ++-- packages/cspell-config-lib/src/index.ts | 12 ++--- .../src/test-helpers/util.ts | 1 + packages/cspell-config-lib/tsconfig.json | 5 +- 24 files changed, 116 insertions(+), 108 deletions(-) delete mode 100644 packages/cspell-config-lib/jest.config.js diff --git a/.eslintrc.js b/.eslintrc.js index 8da1f377a92..1921f65a22a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -74,17 +74,6 @@ const config = { 'simple-import-sort/exports': 'error', }, }, - { - files: ['**/*.test.ts', '**/*.spec.ts'], - excludedFiles: ['**/cspell-gitignore/**'], - extends: 'plugin:jest/recommended', - env: { - jest: true, - }, - rules: { - 'jest/valid-title': 'warn', - }, - }, { files: ['packages/cspell-pipe/**/*.ts'], extends: ['plugin:unicorn/recommended'], @@ -113,6 +102,8 @@ const config = { '**/test.*', '**/rollup.*', '**/*.spec.*', + '**/test-helpers/**', + '**/test-utils/**', '**/src/test/**', '**/src/perf/**', ], diff --git a/packages/cspell-config-lib/jest.config.js b/packages/cspell-config-lib/jest.config.js deleted file mode 100644 index 990bd442804..00000000000 --- a/packages/cspell-config-lib/jest.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../jest.config'); diff --git a/packages/cspell-config-lib/package.json b/packages/cspell-config-lib/package.json index d7e31700b4a..1eaaac78539 100644 --- a/packages/cspell-config-lib/package.json +++ b/packages/cspell-config-lib/package.json @@ -9,7 +9,10 @@ "author": "Jason Dent ", "homepage": "https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell-config#readme", "license": "MIT", - "main": "dist/index.js", + "type": "module", + "exports": { + ".": "./dist/index.js" + }, "directories": { "dist": "dist" }, @@ -27,9 +30,9 @@ "watch": "tsc -p . -w", "clean": "shx rm -rf dist temp coverage \"*.tsbuildInfo\"", "clean-build": "pnpm run clean && pnpm run build", - "coverage": "jest --coverage", - "test-watch": "jest --watch", - "test": "jest" + "coverage": "vitest --coverage", + "test-watch": "vitest", + "test": "vitest run" }, "repository": { "type": "git", diff --git a/packages/cspell-config-lib/src/CSpellConfigFile.test.ts b/packages/cspell-config-lib/src/CSpellConfigFile.test.ts index 80f0aee927a..35e48cf9430 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFile.test.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFile.test.ts @@ -1,6 +1,7 @@ import { parse, stringify } from 'comment-json'; +import { describe, expect, test } from 'vitest'; -import { __testing__ } from './CSpellConfigFile'; +import { __testing__ } from './CSpellConfigFile.js'; const { addUniqueWordsToListAndSort } = __testing__; diff --git a/packages/cspell-config-lib/src/CSpellConfigFile.ts b/packages/cspell-config-lib/src/CSpellConfigFile.ts index e0e801b2294..c26343b622b 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFile.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFile.ts @@ -1,6 +1,6 @@ import type { CSpellSettings } from '@cspell/cspell-types'; -import type { Serializer } from './Serializer'; +import type { Serializer } from './Serializer.js'; export interface CSpellConfigFile { readonly uri: string; diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts index 0c347c88d7f..17c4176e21e 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts @@ -1,8 +1,10 @@ -import type { CSpellConfigFile } from './CSpellConfigFile'; -import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter'; -import { defaultDeserializers } from './deserializers'; -import type { IO } from './IO'; -import { json } from './test-helpers/util'; +import { describe, expect, test, vi } from 'vitest'; + +import type { CSpellConfigFile } from './CSpellConfigFile.js'; +import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter.js'; +import { defaultDeserializers } from './deserializers/index.js'; +import type { IO } from './IO.js'; +import { json } from './test-helpers/util.js'; const oc = expect.objectContaining; @@ -12,8 +14,8 @@ describe('CSpellConfigFileReaderWriter', () => { ${'file://package.json'} | ${json({ name: 'name' })} | ${oc({ uri: 'file://package.json', settings: {} })} `('readConfig', async ({ uri, content, expected }) => { const io: IO = { - readFile: jest.fn(() => content), - writeFile: jest.fn(), + readFile: vi.fn(() => content), + writeFile: vi.fn(), }; const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); expect(await rw.readConfig(uri)).toEqual(expected); @@ -24,8 +26,8 @@ describe('CSpellConfigFileReaderWriter', () => { ${'file://cspell.js'} | ${''} | ${new Error('Unable to parse config file: "file://cspell.js"')} `('fail readConfig', async ({ uri, content, expected }) => { const io: IO = { - readFile: jest.fn(() => content), - writeFile: jest.fn(), + readFile: vi.fn(() => content), + writeFile: vi.fn(), }; const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); await expect(rw.readConfig(uri)).rejects.toEqual(expected); @@ -36,16 +38,16 @@ describe('CSpellConfigFileReaderWriter', () => { ${'file://cspell.js'} | ${'content'} `('writeConfig', async ({ uri, content }) => { const io: IO = { - readFile: jest.fn(() => content), - writeFile: jest.fn(() => Promise.resolve()), + readFile: vi.fn(() => content), + writeFile: vi.fn(() => Promise.resolve()), }; const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); const cf: CSpellConfigFile = { uri, settings: {}, - serialize: jest.fn(() => content), - addWords: jest.fn(), + serialize: vi.fn(() => content), + addWords: vi.fn(), }; await expect(rw.writeConfig(cf)).resolves.toBeUndefined(); expect(io.writeFile).toHaveBeenCalledWith(uri, content); diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts index c999df56958..31b95170422 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts @@ -1,6 +1,6 @@ -import type { CSpellConfigFile } from './CSpellConfigFile'; -import type { Deserializer, DeserializerNext, DeserializerParams } from './Deserializer'; -import type { IO } from './IO'; +import type { CSpellConfigFile } from './CSpellConfigFile.js'; +import type { Deserializer, DeserializerNext, DeserializerParams } from './Deserializer.js'; +import type { IO } from './IO.js'; export const defaultNextDeserializer: DeserializerNext = (content: DeserializerParams) => { throw new Error(`Unable to parse config file: "${content.uri}"`); diff --git a/packages/cspell-config-lib/src/Deserializer.ts b/packages/cspell-config-lib/src/Deserializer.ts index 4c4fa27d641..7c2e8a5a119 100644 --- a/packages/cspell-config-lib/src/Deserializer.ts +++ b/packages/cspell-config-lib/src/Deserializer.ts @@ -1,4 +1,4 @@ -import type { CSpellConfigFile } from './CSpellConfigFile'; +import type { CSpellConfigFile } from './CSpellConfigFile.js'; export interface DeserializerParams { uri: string; diff --git a/packages/cspell-config-lib/src/__snapshots__/index.test.ts.snap b/packages/cspell-config-lib/src/__snapshots__/index.test.ts.snap index 23b62d9d049..16c13ab98e8 100644 --- a/packages/cspell-config-lib/src/__snapshots__/index.test.ts.snap +++ b/packages/cspell-config-lib/src/__snapshots__/index.test.ts.snap @@ -1,48 +1,48 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`cspell-config edit config 1`] = ` +exports[`cspell-config > edit config 1`] = ` "{ - "name": "test-package", - "cspell": { - "words": [ - "apple", - "banana" + \\"name\\": \\"test-package\\", + \\"cspell\\": { + \\"words\\": [ + \\"apple\\", + \\"banana\\" ] } } " `; -exports[`cspell-config edit config 2`] = ` +exports[`cspell-config > edit config 2`] = ` "{ - "name": "test-package", - "cspell": { - "words": [ - "apple" + \\"name\\": \\"test-package\\", + \\"cspell\\": { + \\"words\\": [ + \\"apple\\" ] } } " `; -exports[`cspell-config edit config 3`] = ` +exports[`cspell-config > edit config 3`] = ` "{ // file version - "version": "0.2", - "words": [ - "angle", // with comment - "apple", - // Before "before" - "before", - "cache", - "zebra" // zebra comment + \\"version\\": \\"0.2\\", + \\"words\\": [ + \\"angle\\", // with comment + \\"apple\\", + // Before \\"before\\" + \\"before\\", + \\"cache\\", + \\"zebra\\" // zebra comment ] } " `; -exports[`cspell-config edit config 4`] = ` -"version: "0.2" +exports[`cspell-config > edit config 4`] = ` +"version: \\"0.2\\" words: - angle - apple diff --git a/packages/cspell-config-lib/src/createReaderWriter.test.ts b/packages/cspell-config-lib/src/createReaderWriter.test.ts index ddf7309de84..cb7766e32c0 100644 --- a/packages/cspell-config-lib/src/createReaderWriter.test.ts +++ b/packages/cspell-config-lib/src/createReaderWriter.test.ts @@ -1,7 +1,9 @@ -import { createReaderWriter } from './createReaderWriter'; -import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter'; -import { defaultDeserializers } from './deserializers'; -import type { IO } from './IO'; +import { describe, expect, test, vi } from 'vitest'; + +import { createReaderWriter } from './createReaderWriter.js'; +import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter.js'; +import { defaultDeserializers } from './deserializers/index.js'; +import type { IO } from './IO.js'; describe('createReaderWriter', () => { test('createReaderWriter default', () => { @@ -10,8 +12,8 @@ describe('createReaderWriter', () => { test('createReaderWriter', () => { const io: IO = { - readFile: jest.fn(), - writeFile: jest.fn(), + readFile: vi.fn(), + writeFile: vi.fn(), }; const rw = createReaderWriter([], io); expect(rw).toBeInstanceOf(CSpellConfigFileReaderWriterImpl); diff --git a/packages/cspell-config-lib/src/createReaderWriter.ts b/packages/cspell-config-lib/src/createReaderWriter.ts index e8d1591397c..d0cc42ed859 100644 --- a/packages/cspell-config-lib/src/createReaderWriter.ts +++ b/packages/cspell-config-lib/src/createReaderWriter.ts @@ -1,10 +1,10 @@ import { promises as fs } from 'fs'; -import type { CSpellConfigFileReaderWriter } from './CSpellConfigFileReaderWriter'; -import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter'; -import type { Deserializer } from './Deserializer'; -import { defaultDeserializers } from './deserializers'; -import type { IO } from './IO'; +import type { CSpellConfigFileReaderWriter } from './CSpellConfigFileReaderWriter.js'; +import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter.js'; +import type { Deserializer } from './Deserializer.js'; +import { defaultDeserializers } from './deserializers/index.js'; +import type { IO } from './IO.js'; const defaultIO: IO = { readFile, diff --git a/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts b/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts index b0b0112d34b..faae7a08921 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts @@ -1,6 +1,8 @@ -import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter'; -import { json } from '../test-helpers/util'; -import { deserializerCSpellJson } from './cspellJson'; +import { describe, expect, test } from 'vitest'; + +import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter.js'; +import { json } from '../test-helpers/util.js'; +import { deserializerCSpellJson } from './cspellJson.js'; const oc = expect.objectContaining; diff --git a/packages/cspell-config-lib/src/deserializers/cspellJson.ts b/packages/cspell-config-lib/src/deserializers/cspellJson.ts index 60dd095b758..d49483557ae 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellJson.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellJson.ts @@ -1,10 +1,10 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import { parse, stringify } from 'comment-json'; -import type { CSpellConfigFile } from '../CSpellConfigFile'; -import { ImplCSpellConfigFile } from '../CSpellConfigFile'; -import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer'; -import { detectIndent } from './util'; +import type { CSpellConfigFile } from '../CSpellConfigFile.js'; +import { ImplCSpellConfigFile } from '../CSpellConfigFile.js'; +import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; +import { detectIndent } from './util.js'; const isSupportedFormat = /\.jsonc?(?=$|[?#])/; diff --git a/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts b/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts index 5041bc3a108..66fa23752a9 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts @@ -1,7 +1,8 @@ +import { describe, expect, test } from 'vitest'; import { stringify } from 'yaml'; -import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter'; -import { deserializerCSpellYaml } from './cspellYaml'; +import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter.js'; +import { deserializerCSpellYaml } from './cspellYaml.js'; const oc = expect.objectContaining; const next = defaultNextDeserializer; diff --git a/packages/cspell-config-lib/src/deserializers/cspellYaml.ts b/packages/cspell-config-lib/src/deserializers/cspellYaml.ts index 352c59207b3..922a23a8c19 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellYaml.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellYaml.ts @@ -1,10 +1,10 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import { parse, stringify } from 'yaml'; -import type { CSpellConfigFile } from '../CSpellConfigFile'; -import { ImplCSpellConfigFile } from '../CSpellConfigFile'; -import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer'; -import { detectIndentAsNum } from './util'; +import type { CSpellConfigFile } from '../CSpellConfigFile.js'; +import { ImplCSpellConfigFile } from '../CSpellConfigFile.js'; +import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; +import { detectIndentAsNum } from './util.js'; const isSupportedFormat = /\.ya?ml(?=$|[?#])/; diff --git a/packages/cspell-config-lib/src/deserializers/index.test.ts b/packages/cspell-config-lib/src/deserializers/index.test.ts index 430b7d82445..e7c1688e7ff 100644 --- a/packages/cspell-config-lib/src/deserializers/index.test.ts +++ b/packages/cspell-config-lib/src/deserializers/index.test.ts @@ -1,4 +1,6 @@ -import { defaultDeserializers } from './index'; +import { describe, expect, test } from 'vitest'; + +import { defaultDeserializers } from './index.js'; describe('index', () => { test('defaultDeserializers', () => { diff --git a/packages/cspell-config-lib/src/deserializers/index.ts b/packages/cspell-config-lib/src/deserializers/index.ts index be0da098ab6..638851c7477 100644 --- a/packages/cspell-config-lib/src/deserializers/index.ts +++ b/packages/cspell-config-lib/src/deserializers/index.ts @@ -1,7 +1,7 @@ -import type { Deserializer } from '../Deserializer'; -import { deserializerCSpellJson } from './cspellJson'; -import { deserializerCSpellYaml } from './cspellYaml'; -import { deserializerPackageJson } from './packageJson'; +import type { Deserializer } from '../Deserializer.js'; +import { deserializerCSpellJson } from './cspellJson.js'; +import { deserializerCSpellYaml } from './cspellYaml.js'; +import { deserializerPackageJson } from './packageJson.js'; export const defaultDeserializers: Deserializer[] = [ deserializerPackageJson, diff --git a/packages/cspell-config-lib/src/deserializers/packageJson.test.ts b/packages/cspell-config-lib/src/deserializers/packageJson.test.ts index 307d12736d9..cfaefb34683 100644 --- a/packages/cspell-config-lib/src/deserializers/packageJson.test.ts +++ b/packages/cspell-config-lib/src/deserializers/packageJson.test.ts @@ -1,6 +1,8 @@ -import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter'; -import { json } from '../test-helpers/util'; -import { deserializerPackageJson } from './packageJson'; +import { describe, expect, test } from 'vitest'; + +import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter.js'; +import { json } from '../test-helpers/util.js'; +import { deserializerPackageJson } from './packageJson.js'; const oc = expect.objectContaining; const next = defaultNextDeserializer; diff --git a/packages/cspell-config-lib/src/deserializers/packageJson.ts b/packages/cspell-config-lib/src/deserializers/packageJson.ts index a9a8309d91c..2ce19e9613d 100644 --- a/packages/cspell-config-lib/src/deserializers/packageJson.ts +++ b/packages/cspell-config-lib/src/deserializers/packageJson.ts @@ -1,9 +1,9 @@ import type { CSpellSettings } from '@cspell/cspell-types'; -import type { CSpellConfigFile } from '../CSpellConfigFile'; -import { ImplCSpellConfigFile } from '../CSpellConfigFile'; -import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer'; -import { detectIndent } from './util'; +import type { CSpellConfigFile } from '../CSpellConfigFile.js'; +import { ImplCSpellConfigFile } from '../CSpellConfigFile.js'; +import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; +import { detectIndent } from './util.js'; const isSupportedFormat = /package\.json(?=$|[?#])/; diff --git a/packages/cspell-config-lib/src/deserializers/util.test.ts b/packages/cspell-config-lib/src/deserializers/util.test.ts index 6e01721ab06..a44fa533a47 100644 --- a/packages/cspell-config-lib/src/deserializers/util.test.ts +++ b/packages/cspell-config-lib/src/deserializers/util.test.ts @@ -1,4 +1,6 @@ -import { detectIndent } from './util'; +import { describe, expect, test } from 'vitest'; + +import { detectIndent } from './util.js'; describe('util', () => { test.each` diff --git a/packages/cspell-config-lib/src/index.test.ts b/packages/cspell-config-lib/src/index.test.ts index 6fc9e26819b..8bbf02ac0a6 100644 --- a/packages/cspell-config-lib/src/index.test.ts +++ b/packages/cspell-config-lib/src/index.test.ts @@ -1,10 +1,11 @@ import { promises as fs } from 'fs'; +import { describe, expect, test } from 'vitest'; import { URI } from 'vscode-uri'; -import * as index from './index'; -import { createReaderWriter } from './index'; -import { fixtures } from './test-helpers/fixtures'; -import { copyFile, tempPath } from './test-helpers/util'; +import * as index from './index.js'; +import { createReaderWriter } from './index.js'; +import { fixtures } from './test-helpers/fixtures.js'; +import { copyFile, tempPath } from './test-helpers/util.js'; describe('index', () => { test('index', () => { diff --git a/packages/cspell-config-lib/src/index.ts b/packages/cspell-config-lib/src/index.ts index e62ec12ce56..a2451e0256a 100644 --- a/packages/cspell-config-lib/src/index.ts +++ b/packages/cspell-config-lib/src/index.ts @@ -1,6 +1,6 @@ -export { createReaderWriter } from './createReaderWriter'; -export type { CSpellConfigFile } from './CSpellConfigFile'; -export type { CSpellConfigFileReaderWriter } from './CSpellConfigFileReaderWriter'; -export type { Deserializer, DeserializerNext, DeserializerParams } from './Deserializer'; -export type { IO } from './IO'; -export type { Serializer } from './Serializer'; +export { createReaderWriter } from './createReaderWriter.js'; +export type { CSpellConfigFile } from './CSpellConfigFile.js'; +export type { CSpellConfigFileReaderWriter } from './CSpellConfigFileReaderWriter.js'; +export type { Deserializer, DeserializerNext, DeserializerParams } from './Deserializer.js'; +export type { IO } from './IO.js'; +export type { Serializer } from './Serializer.js'; diff --git a/packages/cspell-config-lib/src/test-helpers/util.ts b/packages/cspell-config-lib/src/test-helpers/util.ts index 7c999036bdd..13bab5992f1 100644 --- a/packages/cspell-config-lib/src/test-helpers/util.ts +++ b/packages/cspell-config-lib/src/test-helpers/util.ts @@ -1,5 +1,6 @@ import { promises as fs } from 'fs'; import * as path from 'path'; +import { expect } from 'vitest'; export function json(obj: unknown, indent: string | number = 2): string { return JSON.stringify(obj, null, indent) + '\n'; diff --git a/packages/cspell-config-lib/tsconfig.json b/packages/cspell-config-lib/tsconfig.json index e949c67cad1..89f72354670 100644 --- a/packages/cspell-config-lib/tsconfig.json +++ b/packages/cspell-config-lib/tsconfig.json @@ -1,8 +1,7 @@ { - "extends": "../../tsconfig.json", + "extends": "../../tsconfig.esm.json", "compilerOptions": { - "types": ["node", "jest"], - "skipLibCheck": false, + "types": ["node"], "outDir": "dist" }, "include": ["src/**/*.ts", "src/**/*.test.ts"] From e997b868b9bdf3bbd1dc69767055ed80bb74acb8 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Wed, 15 Nov 2023 13:59:45 +0100 Subject: [PATCH 2/9] refactor: Use URL instead of Uri --- packages/cspell-config-lib/package.json | 1 - .../cspell-config-lib/src/CSpellConfigFile.ts | 24 ++++++++++++----- .../src/CSpellConfigFileReaderWriter.test.ts | 18 ++++++------- .../src/CSpellConfigFileReaderWriter.ts | 20 +++++++------- .../cspell-config-lib/src/Deserializer.ts | 8 +++--- packages/cspell-config-lib/src/IO.ts | 6 +++-- .../src/createReaderWriter.ts | 10 +++---- .../src/deserializers/cspellJson.test.ts | 14 +++++----- .../src/deserializers/cspellJson.ts | 19 ++++++++------ .../src/deserializers/cspellYaml.test.ts | 15 ++++++----- .../src/deserializers/cspellYaml.ts | 19 ++++++++------ .../src/deserializers/packageJson.test.ts | 26 ++++++++++--------- .../src/deserializers/packageJson.ts | 16 ++++++------ packages/cspell-config-lib/src/index.test.ts | 8 +++--- packages/cspell-config-lib/src/index.ts | 2 +- packages/cspell-config-lib/src/util/toURL.ts | 3 +++ pnpm-lock.yaml | 3 --- 17 files changed, 118 insertions(+), 94 deletions(-) create mode 100644 packages/cspell-config-lib/src/util/toURL.ts diff --git a/packages/cspell-config-lib/package.json b/packages/cspell-config-lib/package.json index 1eaaac78539..46c264e1678 100644 --- a/packages/cspell-config-lib/package.json +++ b/packages/cspell-config-lib/package.json @@ -47,7 +47,6 @@ "dependencies": { "@cspell/cspell-types": "workspace:*", "comment-json": "^4.2.3", - "vscode-uri": "^3.0.8", "yaml": "^1.10.2" }, "devDependencies": { diff --git a/packages/cspell-config-lib/src/CSpellConfigFile.ts b/packages/cspell-config-lib/src/CSpellConfigFile.ts index c26343b622b..fd3d91eb90a 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFile.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFile.ts @@ -2,19 +2,30 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import type { Serializer } from './Serializer.js'; -export interface CSpellConfigFile { - readonly uri: string; +export interface ICSpellConfigFile { + readonly url: URL; readonly settings: CSpellSettings; - serialize(): string; + readonly readonly?: boolean; + serialize?: () => string; addWords(words: string[]): this; } -export class ImplCSpellConfigFile implements CSpellConfigFile { +export abstract class CSpellConfigFile implements ICSpellConfigFile { + constructor(readonly url: URL) {} + + abstract readonly settings: CSpellSettings; + abstract serialize(): string; + abstract addWords(words: string[]): this; +} + +export class ImplCSpellConfigFile extends CSpellConfigFile { constructor( - readonly uri: string, + readonly url: URL, readonly settings: CSpellSettings, readonly serializer: Serializer, - ) {} + ) { + super(url); + } serialize(): string { return this.serializer(this.settings); @@ -30,6 +41,7 @@ export class ImplCSpellConfigFile implements CSpellConfigFile { /** * Adds words to a list, sorts the list and makes sure it is unique. + * Note: this method is used to try and preserve comments in the config file. * @param list - list to be modified * @param toAdd - words to add */ diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts index 17c4176e21e..6f26de8afe9 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test, vi } from 'vitest'; -import type { CSpellConfigFile } from './CSpellConfigFile.js'; +import type { ICSpellConfigFile } from './CSpellConfigFile.js'; import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter.js'; import { defaultDeserializers } from './deserializers/index.js'; import type { IO } from './IO.js'; @@ -10,8 +10,8 @@ const oc = expect.objectContaining; describe('CSpellConfigFileReaderWriter', () => { test.each` - uri | content | expected - ${'file://package.json'} | ${json({ name: 'name' })} | ${oc({ uri: 'file://package.json', settings: {} })} + uri | content | expected + ${'file:///package.json'} | ${json({ name: 'name' })} | ${oc({ url: new URL('file:///package.json'), settings: {} })} `('readConfig', async ({ uri, content, expected }) => { const io: IO = { readFile: vi.fn(() => content), @@ -22,8 +22,8 @@ describe('CSpellConfigFileReaderWriter', () => { }); test.each` - uri | content | expected - ${'file://cspell.js'} | ${''} | ${new Error('Unable to parse config file: "file://cspell.js"')} + uri | content | expected + ${'file:///cspell.js'} | ${''} | ${new Error('Unable to parse config file: "file:///cspell.js"')} `('fail readConfig', async ({ uri, content, expected }) => { const io: IO = { readFile: vi.fn(() => content), @@ -34,8 +34,8 @@ describe('CSpellConfigFileReaderWriter', () => { }); test.each` - uri | content - ${'file://cspell.js'} | ${'content'} + uri | content + ${'file:///cspell.js'} | ${'content'} `('writeConfig', async ({ uri, content }) => { const io: IO = { readFile: vi.fn(() => content), @@ -43,8 +43,8 @@ describe('CSpellConfigFileReaderWriter', () => { }; const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); - const cf: CSpellConfigFile = { - uri, + const cf: ICSpellConfigFile = { + url: uri, settings: {}, serialize: vi.fn(() => content), addWords: vi.fn(), diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts index 31b95170422..f17b61e13dd 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts @@ -1,16 +1,17 @@ -import type { CSpellConfigFile } from './CSpellConfigFile.js'; +import type { ICSpellConfigFile } from './CSpellConfigFile.js'; import type { Deserializer, DeserializerNext, DeserializerParams } from './Deserializer.js'; import type { IO } from './IO.js'; +import { toURL } from './util/toURL.js'; export const defaultNextDeserializer: DeserializerNext = (content: DeserializerParams) => { - throw new Error(`Unable to parse config file: "${content.uri}"`); + throw new Error(`Unable to parse config file: "${content.url}"`); }; export interface CSpellConfigFileReaderWriter { readonly io: IO; readonly deserializers: Deserializer[]; - readConfig(uri: string): Promise; - writeConfig(configFile: CSpellConfigFile): Promise; + readConfig(uri: URL | string): Promise; + writeConfig(configFile: ICSpellConfigFile): Promise; } export class CSpellConfigFileReaderWriterImpl implements CSpellConfigFileReaderWriter { @@ -19,12 +20,13 @@ export class CSpellConfigFileReaderWriterImpl implements CSpellConfigFileReaderW readonly deserializers: Deserializer[], ) {} - async readConfig(uri: string): Promise { - const content = await this.io.readFile(uri); + async readConfig(uri: URL | string): Promise { + const url = toURL(uri); + const content = await this.io.readFile(url); let next: DeserializerNext = defaultNextDeserializer; - const desContent: DeserializerParams = { uri, content }; + const desContent: DeserializerParams = { url, content }; for (const des of [...this.deserializers].reverse()) { next = curry(des, next); @@ -33,9 +35,9 @@ export class CSpellConfigFileReaderWriterImpl implements CSpellConfigFileReaderW return next(desContent); } - writeConfig(configFile: CSpellConfigFile): Promise { + writeConfig(configFile: ICSpellConfigFile): Promise { const content = configFile.serialize(); - return this.io.writeFile(configFile.uri, content); + return this.io.writeFile(configFile.url, content); } } diff --git a/packages/cspell-config-lib/src/Deserializer.ts b/packages/cspell-config-lib/src/Deserializer.ts index 7c2e8a5a119..91c4f1be6f4 100644 --- a/packages/cspell-config-lib/src/Deserializer.ts +++ b/packages/cspell-config-lib/src/Deserializer.ts @@ -1,17 +1,17 @@ -import type { CSpellConfigFile } from './CSpellConfigFile.js'; +import type { ICSpellConfigFile } from './CSpellConfigFile.js'; export interface DeserializerParams { - uri: string; + url: URL; content: string; } export interface DeserializerNext { - (content: DeserializerParams): CSpellConfigFile; + (content: DeserializerParams): ICSpellConfigFile; } export interface Deserializer { /** * If a Deserializer can handle a given request, it returns a CSpellConfigFile, otherwise it calls `next`. */ - (params: DeserializerParams, next: DeserializerNext): CSpellConfigFile; + (params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile; } diff --git a/packages/cspell-config-lib/src/IO.ts b/packages/cspell-config-lib/src/IO.ts index 3622220e6b0..854211618b5 100644 --- a/packages/cspell-config-lib/src/IO.ts +++ b/packages/cspell-config-lib/src/IO.ts @@ -1,4 +1,6 @@ export interface IO { - readFile(uri: string): Promise; - writeFile(uri: string, content: string): Promise; + readFile(url: URL): Promise; + writeFile(url: URL, content: string): Promise; } + +import.meta.resolve; diff --git a/packages/cspell-config-lib/src/createReaderWriter.ts b/packages/cspell-config-lib/src/createReaderWriter.ts index d0cc42ed859..8279f73177c 100644 --- a/packages/cspell-config-lib/src/createReaderWriter.ts +++ b/packages/cspell-config-lib/src/createReaderWriter.ts @@ -18,12 +18,10 @@ export function createReaderWriter( return new CSpellConfigFileReaderWriterImpl(io, deserializers.concat(defaultDeserializers)); } -function readFile(uriFile: string): Promise { - const uri = new URL(uriFile); - return fs.readFile(uri, 'utf-8'); +function readFile(url: URL): Promise { + return fs.readFile(url, 'utf-8'); } -function writeFile(uriFile: string, content: string): Promise { - const uri = new URL(uriFile); - return fs.writeFile(uri, content); +function writeFile(url: URL, content: string): Promise { + return fs.writeFile(url, content); } diff --git a/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts b/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts index faae7a08921..506789f144c 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts @@ -24,18 +24,18 @@ describe('cspellJson', () => { ${'cspell-ext.json'} | ${'{}'} | ${oc({ settings: {} })} ${'.cspell.json'} | ${'{\n // add words here\n "words":[]}'} | ${oc({ settings: { words: [] } })} `('success $uri', ({ uri, content, expected }) => { - expect(deserializerCSpellJson({ uri, content }, next)).toEqual(expected); + expect(deserializerCSpellJson({ url: new URL(uri, 'file:///'), content }, next)).toEqual(expected); }); test.each` uri | content | expected - ${''} | ${''} | ${'Unable to parse config file: ""'} - ${'cspell.js'} | ${''} | ${'Unable to parse config file: "cspell.js"'} - ${'cspell.yaml'} | ${''} | ${'Unable to parse config file: "cspell.yaml"'} + ${''} | ${''} | ${'Unable to parse config file: "file:///"'} + ${'cspell.js'} | ${''} | ${'Unable to parse config file: "file:///cspell.js"'} + ${'cspell.yaml'} | ${''} | ${'Unable to parse config file: "file:///cspell.yaml"'} ${'cspell.json'} | ${''} | ${'Unexpected end of JSON input'} - ${'cspell.json'} | ${'[]'} | ${'Unable to parse cspell.json'} + ${'cspell.json'} | ${'[]'} | ${'Unable to parse file:///cspell.json'} `('fail $uri', ({ uri, content, expected }) => { - expect(() => deserializerCSpellJson({ uri, content }, next)).toThrow(expected); + expect(() => deserializerCSpellJson({ url: new URL(uri, 'file:///'), content }, next)).toThrow(expected); }); test.each` @@ -44,7 +44,7 @@ describe('cspellJson', () => { ${'cspell.json?x=5'} | ${'{\n "words":[]}'} | ${json({ words: [] }, 2)} ${'cspell.jsonc'} | ${sampleCSpellJson} | ${sampleCSpellJson} `('serialize $uri', ({ uri, content, expected }) => { - const file = deserializerCSpellJson({ uri, content }, next); + const file = deserializerCSpellJson({ url: new URL(uri, 'file:///'), content }, next); expect(file?.serialize()).toEqual(expected); }); }); diff --git a/packages/cspell-config-lib/src/deserializers/cspellJson.ts b/packages/cspell-config-lib/src/deserializers/cspellJson.ts index d49483557ae..c14132524d1 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellJson.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellJson.ts @@ -1,20 +1,18 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import { parse, stringify } from 'comment-json'; -import type { CSpellConfigFile } from '../CSpellConfigFile.js'; +import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; import { ImplCSpellConfigFile } from '../CSpellConfigFile.js'; import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; import { detectIndent } from './util.js'; -const isSupportedFormat = /\.jsonc?(?=$|[?#])/; - -function _deserializerCSpellJson(params: DeserializerParams, next: DeserializerNext): CSpellConfigFile { - const { uri, content } = params; - if (!isSupportedFormat.test(params.uri)) return next(params); +function _deserializerCSpellJson(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { + const { url, content } = params; + if (!isJsonFile(url.pathname)) return next(params); const cspell: CSpellSettings | unknown = parse(content); if (!isCSpellSettings(cspell)) { - throw new Error(`Unable to parse ${uri}`); + throw new Error(`Unable to parse ${url}`); } const indent = detectIndent(content); @@ -23,7 +21,12 @@ function _deserializerCSpellJson(params: DeserializerParams, next: DeserializerN return stringify(settings, null, indent) + '\n'; } - return new ImplCSpellConfigFile(uri, cspell, serialize); + return new ImplCSpellConfigFile(url, cspell, serialize); +} + +function isJsonFile(pathname: string) { + pathname = pathname.toLowerCase(); + return pathname.endsWith('.json') || pathname.endsWith('.jsonc'); } function isCSpellSettings(cfg: unknown): cfg is CSpellSettings { diff --git a/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts b/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts index 66fa23752a9..cdfc7db0df5 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts @@ -3,6 +3,7 @@ import { stringify } from 'yaml'; import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter.js'; import { deserializerCSpellYaml } from './cspellYaml.js'; +import { pathToFileURL } from 'node:url'; const oc = expect.objectContaining; const next = defaultNextDeserializer; @@ -21,18 +22,18 @@ words: ${'cspell-ext.yml'} | ${'---\nversion: "0.2"\n'} | ${oc({ settings: { version: '0.2' } })} ${'.cspell.yml'} | ${'\nwords: []\n'} | ${oc({ settings: { words: [] } })} `('success $uri', ({ uri, content, expected }) => { - expect(deserializerCSpellYaml({ uri, content }, next)).toEqual(expected); + expect(deserializerCSpellYaml({ url: pathToFileURL(uri), content }, next)).toEqual(expected); }); test.each` uri | content | expected - ${''} | ${''} | ${'Unable to parse config file: ""'} - ${'cspell.js'} | ${''} | ${'Unable to parse config file: "cspell.js"'} - ${'cspell.json'} | ${''} | ${'Unable to parse config file: "cspell.json"'} + ${''} | ${''} | ${'Unable to parse config file: "file:///"'} + ${'cspell.js'} | ${''} | ${'Unable to parse config file: "file:///cspell.js"'} + ${'cspell.json'} | ${''} | ${'Unable to parse config file: "file:///cspell.json"'} ${'cspell.yaml'} | ${'"version'} | ${'Missing closing'} - ${'cspell.yaml'} | ${'[]'} | ${'Unable to parse cspell.yaml'} + ${'cspell.yaml'} | ${'[]'} | ${'Unable to parse file:///cspell.yaml'} `('fail $uri', ({ uri, content, expected }) => { - expect(() => deserializerCSpellYaml({ uri, content }, next)).toThrow(expected); + expect(() => deserializerCSpellYaml({ url: new URL(uri, 'file:///'), content }, next)).toThrow(expected); }); test.each` @@ -41,7 +42,7 @@ words: ${'cspell.yaml?x=5'} | ${'{\n "words":[]}'} | ${toYaml({ words: [] }, 2)} ${'cspell.yml'} | ${sampleCSpellYaml} | ${sampleCSpellYaml} `('serialize $uri', ({ uri, content, expected }) => { - const file = deserializerCSpellYaml({ uri, content }, next); + const file = deserializerCSpellYaml({ url: new URL(uri, 'file:///'), content }, next); expect(file?.serialize()).toEqual(expected); }); }); diff --git a/packages/cspell-config-lib/src/deserializers/cspellYaml.ts b/packages/cspell-config-lib/src/deserializers/cspellYaml.ts index 922a23a8c19..423a57d7dd2 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellYaml.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellYaml.ts @@ -1,20 +1,18 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import { parse, stringify } from 'yaml'; -import type { CSpellConfigFile } from '../CSpellConfigFile.js'; +import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; import { ImplCSpellConfigFile } from '../CSpellConfigFile.js'; import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; import { detectIndentAsNum } from './util.js'; -const isSupportedFormat = /\.ya?ml(?=$|[?#])/; - -function _deserializerCSpellYaml(params: DeserializerParams, next: DeserializerNext): CSpellConfigFile { - const { uri, content } = params; - if (!isSupportedFormat.test(uri)) return next(params); +function _deserializerCSpellYaml(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { + const { url, content } = params; + if (!isYamlFile(url.pathname)) return next(params); const cspell = parse(content) || {}; if (!cspell || typeof cspell !== 'object' || Array.isArray(cspell)) { - throw new Error(`Unable to parse ${uri}`); + throw new Error(`Unable to parse ${url}`); } const indent = detectIndentAsNum(content); @@ -23,7 +21,12 @@ function _deserializerCSpellYaml(params: DeserializerParams, next: DeserializerN return stringify(settings, { indent }); } - return new ImplCSpellConfigFile(uri, cspell, serialize); + return new ImplCSpellConfigFile(url, cspell, serialize); +} + +function isYamlFile(pathname: string) { + pathname = pathname.toLowerCase(); + return pathname.endsWith('.yml') || pathname.endsWith('.yaml'); } export const deserializerCSpellYaml: Deserializer = _deserializerCSpellYaml; diff --git a/packages/cspell-config-lib/src/deserializers/packageJson.test.ts b/packages/cspell-config-lib/src/deserializers/packageJson.test.ts index cfaefb34683..f73f31f59dd 100644 --- a/packages/cspell-config-lib/src/deserializers/packageJson.test.ts +++ b/packages/cspell-config-lib/src/deserializers/packageJson.test.ts @@ -1,3 +1,5 @@ +import { pathToFileURL } from 'node:url'; + import { describe, expect, test } from 'vitest'; import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter.js'; @@ -13,20 +15,20 @@ describe('packageJson', () => { ${'package.json'} | ${'{}'} | ${oc({ settings: {} })} ${'package.json?x=5'} | ${'{"cspell":{"words":[]}}'} | ${oc({ settings: { words: [] } })} `('success $uri', ({ uri, content, expected }) => { - expect(deserializerPackageJson({ uri, content }, next)).toEqual(expected); + expect(deserializerPackageJson({ url: new URL(uri, import.meta.url), content }, next)).toEqual(expected); }); test.each` - uri | content | expected - ${''} | ${''} | ${'Unable to parse config file: ""'} - ${'cspell.js'} | ${''} | ${'Unable to parse config file: "cspell.js"'} - ${'cspell.json'} | ${''} | ${'Unable to parse config file: "cspell.json"'} - ${'cspell.yaml'} | ${''} | ${'Unable to parse config file: "cspell.yaml"'} - ${'package.json'} | ${''} | ${'Unexpected end of JSON input'} - ${'package.json'} | ${'[]'} | ${'Unable to parse package.json'} - ${'package.json'} | ${'{"cspell": []}'} | ${'Unable to parse package.json'} - `('fail $uri', ({ uri, content, expected }) => { - expect(() => deserializerPackageJson({ uri, content }, next)).toThrow(expected); + url | content | expected + ${'file:///'} | ${''} | ${'Unable to parse config file: "file:///"'} + ${'file:///cspell.js'} | ${''} | ${'Unable to parse config file: "file:///cspell.js"'} + ${'file:///cspell.json'} | ${''} | ${'Unable to parse config file: "file:///cspell.json"'} + ${'file:///cspell.yaml'} | ${''} | ${'Unable to parse config file: "file:///cspell.yaml"'} + ${'file:///package.json'} | ${''} | ${'Unexpected end of JSON input'} + ${'file:///package.json'} | ${'[]'} | ${'Unable to parse file:///package.json'} + ${'file:///package.json'} | ${'{"cspell": []}'} | ${'Unable to parse file:///package.json'} + `('fail $url', ({ url, content, expected }) => { + expect(() => deserializerPackageJson({ url: new URL(url), content }, next)).toThrow(expected); }); test.each` @@ -35,7 +37,7 @@ describe('packageJson', () => { ${'package.json?x=5'} | ${'{\n "cspell":{"words":[]}}'} | ${json({ cspell: { words: [] } }, 2)} ${'package.json?x=5'} | ${'{\n "cspell":{"words":[]}}'} | ${json({ cspell: { words: [] } }, 2)} `('serialize $uri', ({ uri, content, expected }) => { - const file = deserializerPackageJson({ uri, content }, next); + const file = deserializerPackageJson({ url: new URL(uri, import.meta.url), content }, next); expect(file?.serialize()).toEqual(expected); }); }); diff --git a/packages/cspell-config-lib/src/deserializers/packageJson.ts b/packages/cspell-config-lib/src/deserializers/packageJson.ts index 2ce19e9613d..d4f1b1cd2dd 100644 --- a/packages/cspell-config-lib/src/deserializers/packageJson.ts +++ b/packages/cspell-config-lib/src/deserializers/packageJson.ts @@ -1,24 +1,24 @@ import type { CSpellSettings } from '@cspell/cspell-types'; -import type { CSpellConfigFile } from '../CSpellConfigFile.js'; +import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; import { ImplCSpellConfigFile } from '../CSpellConfigFile.js'; import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; import { detectIndent } from './util.js'; -const isSupportedFormat = /package\.json(?=$|[?#])/; +const isSupportedFormat = /\bpackage\.json$/i; -function _deserializerPackageJson(params: DeserializerParams, next: DeserializerNext): CSpellConfigFile { - const { uri, content } = params; - if (!isSupportedFormat.test(uri)) return next(params); +function _deserializerPackageJson(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { + const { url: url, content } = params; + if (!isSupportedFormat.test(url.pathname)) return next(params); const packageJson = JSON.parse(content); if (!packageJson || typeof packageJson !== 'object' || Array.isArray(packageJson)) { - throw new Error(`Unable to parse ${uri}`); + throw new Error(`Unable to parse ${url}`); } packageJson['cspell'] = packageJson['cspell'] || {}; const cspell = packageJson['cspell']; if (typeof cspell !== 'object' || Array.isArray(cspell)) { - throw new Error(`Unable to parse ${uri}`); + throw new Error(`Unable to parse ${url}`); } const indent = detectIndent(content); @@ -28,7 +28,7 @@ function _deserializerPackageJson(params: DeserializerParams, next: Deserializer return JSON.stringify(packageJson, null, indent) + '\n'; } - return new ImplCSpellConfigFile(uri, cspell, serialize); + return new ImplCSpellConfigFile(url, cspell, serialize); } export const deserializerPackageJson: Deserializer = _deserializerPackageJson; diff --git a/packages/cspell-config-lib/src/index.test.ts b/packages/cspell-config-lib/src/index.test.ts index 8bbf02ac0a6..e8098227b97 100644 --- a/packages/cspell-config-lib/src/index.test.ts +++ b/packages/cspell-config-lib/src/index.test.ts @@ -1,6 +1,8 @@ -import { promises as fs } from 'fs'; +import { promises as fs } from 'node:fs'; +import { resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; + import { describe, expect, test } from 'vitest'; -import { URI } from 'vscode-uri'; import * as index from './index.js'; import { createReaderWriter } from './index.js'; @@ -31,7 +33,7 @@ describe('cspell-config', () => { const tempFile = tempPath(fixture); await copyFile(fixtureFile, tempFile); const rw = createReaderWriter(); - const uri = URI.file(tempFile).toString(); + const uri = pathToFileURL(resolve(tempFile)); const cfg = await rw.readConfig(uri); cfg.addWords(addWords); await rw.writeConfig(cfg); diff --git a/packages/cspell-config-lib/src/index.ts b/packages/cspell-config-lib/src/index.ts index a2451e0256a..8a60200598a 100644 --- a/packages/cspell-config-lib/src/index.ts +++ b/packages/cspell-config-lib/src/index.ts @@ -1,5 +1,5 @@ export { createReaderWriter } from './createReaderWriter.js'; -export type { CSpellConfigFile } from './CSpellConfigFile.js'; +export type { ICSpellConfigFile as CSpellConfigFile } from './CSpellConfigFile.js'; export type { CSpellConfigFileReaderWriter } from './CSpellConfigFileReaderWriter.js'; export type { Deserializer, DeserializerNext, DeserializerParams } from './Deserializer.js'; export type { IO } from './IO.js'; diff --git a/packages/cspell-config-lib/src/util/toURL.ts b/packages/cspell-config-lib/src/util/toURL.ts new file mode 100644 index 00000000000..60829ee9579 --- /dev/null +++ b/packages/cspell-config-lib/src/util/toURL.ts @@ -0,0 +1,3 @@ +export function toURL(url: string | URL): URL { + return typeof url === 'string' ? new URL(url) : url; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2120b48c983..c63ad4d954f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -443,9 +443,6 @@ importers: comment-json: specifier: ^4.2.3 version: 4.2.3 - vscode-uri: - specifier: ^3.0.8 - version: 3.0.8 yaml: specifier: ^1.10.2 version: 1.10.2 From b062e13aa8aa759fc7aa921d45943e1ac247fce7 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Thu, 16 Nov 2023 09:17:20 +0100 Subject: [PATCH 3/9] refactor: Move each config file type into its own class. --- .../cspell-config-lib/src/CSpellConfigFile.ts | 11 ++++-- .../src/CSpellConfigFileJson.ts | 36 ++++++++++++++++++ .../src/CSpellConfigFilePackageJson.ts | 38 +++++++++++++++++++ .../src/CSpellConfigFileYaml.ts | 34 +++++++++++++++++ .../src/ConfigReadWriteHandler.ts | 12 ++++++ .../cspell-config-lib/src/Deserializer.ts | 6 +-- packages/cspell-config-lib/src/TextFile.ts | 4 ++ .../src/deserializers/cspellJson.ts | 26 ++----------- .../src/deserializers/cspellYaml.ts | 22 ++--------- .../src/deserializers/packageJson.ts | 27 ++----------- 10 files changed, 143 insertions(+), 73 deletions(-) create mode 100644 packages/cspell-config-lib/src/CSpellConfigFileJson.ts create mode 100644 packages/cspell-config-lib/src/CSpellConfigFilePackageJson.ts create mode 100644 packages/cspell-config-lib/src/CSpellConfigFileYaml.ts create mode 100644 packages/cspell-config-lib/src/ConfigReadWriteHandler.ts create mode 100644 packages/cspell-config-lib/src/TextFile.ts diff --git a/packages/cspell-config-lib/src/CSpellConfigFile.ts b/packages/cspell-config-lib/src/CSpellConfigFile.ts index fd3d91eb90a..2f38e7ce12f 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFile.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFile.ts @@ -2,11 +2,15 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import type { Serializer } from './Serializer.js'; +export interface CSpellConfigFileReference { + readonly url: URL; +} + export interface ICSpellConfigFile { readonly url: URL; readonly settings: CSpellSettings; readonly readonly?: boolean; - serialize?: () => string; + serialize: () => string; addWords(words: string[]): this; } @@ -18,11 +22,12 @@ export abstract class CSpellConfigFile implements ICSpellConfigFile { abstract addWords(words: string[]): this; } -export class ImplCSpellConfigFile extends CSpellConfigFile { +export abstract class ImplCSpellConfigFile extends CSpellConfigFile { + abstract readonly serializer: Serializer; + constructor( readonly url: URL, readonly settings: CSpellSettings, - readonly serializer: Serializer, ) { super(url); } diff --git a/packages/cspell-config-lib/src/CSpellConfigFileJson.ts b/packages/cspell-config-lib/src/CSpellConfigFileJson.ts new file mode 100644 index 00000000000..0a4368a6c86 --- /dev/null +++ b/packages/cspell-config-lib/src/CSpellConfigFileJson.ts @@ -0,0 +1,36 @@ +import type { CSpellSettings } from '@cspell/cspell-types'; +import { parse, stringify } from 'comment-json'; + +import { ImplCSpellConfigFile } from './CSpellConfigFile.js'; +import { detectIndent } from './deserializers/util.js'; +import type { Serializer } from './Serializer.js'; +import type { TextFile } from './TextFile.js'; + +export class CSpellConfigFileJson extends ImplCSpellConfigFile { + constructor( + readonly url: URL, + readonly settings: CSpellSettings, + readonly serializer: Serializer, + ) { + super(url, settings); + } +} + +export function parseCSpellConfigFileJson(file: TextFile): CSpellConfigFileJson { + const cspell: CSpellSettings | unknown = parse(file.content); + if (!isCSpellSettings(cspell)) { + throw new Error(`Unable to parse ${file.url}`); + } + + const indent = detectIndent(file.content); + + function serialize(settings: CSpellSettings) { + return stringify(settings, null, indent) + '\n'; + } + + return new CSpellConfigFileJson(file.url, cspell, serialize); +} + +function isCSpellSettings(cfg: unknown): cfg is CSpellSettings { + return !(!cfg || typeof cfg !== 'object' || Array.isArray(cfg)); +} diff --git a/packages/cspell-config-lib/src/CSpellConfigFilePackageJson.ts b/packages/cspell-config-lib/src/CSpellConfigFilePackageJson.ts new file mode 100644 index 00000000000..e63fbd3d8f1 --- /dev/null +++ b/packages/cspell-config-lib/src/CSpellConfigFilePackageJson.ts @@ -0,0 +1,38 @@ +import type { CSpellSettings } from '@cspell/cspell-types'; + +import { ImplCSpellConfigFile } from './CSpellConfigFile.js'; +import { detectIndent } from './deserializers/util.js'; +import type { Serializer } from './Serializer.js'; +import type { TextFile } from './TextFile.js'; + +export class CSpellConfigFilePackageJson extends ImplCSpellConfigFile { + constructor( + readonly url: URL, + readonly settings: CSpellSettings, + readonly serializer: Serializer, + ) { + super(url, settings); + } +} + +export function parseCSpellConfigFilePackageJson(file: TextFile): CSpellConfigFilePackageJson { + const { url, content } = file; + const packageJson = JSON.parse(content); + if (!packageJson || typeof packageJson !== 'object' || Array.isArray(packageJson)) { + throw new Error(`Unable to parse ${url}`); + } + packageJson['cspell'] = packageJson['cspell'] || {}; + const cspell = packageJson['cspell']; + if (typeof cspell !== 'object' || Array.isArray(cspell)) { + throw new Error(`Unable to parse ${url}`); + } + + const indent = detectIndent(content); + + function serialize(settings: CSpellSettings) { + packageJson['cspell'] = settings; + return JSON.stringify(packageJson, null, indent) + '\n'; + } + + return new CSpellConfigFilePackageJson(url, cspell, serialize); +} diff --git a/packages/cspell-config-lib/src/CSpellConfigFileYaml.ts b/packages/cspell-config-lib/src/CSpellConfigFileYaml.ts new file mode 100644 index 00000000000..831f7ca9273 --- /dev/null +++ b/packages/cspell-config-lib/src/CSpellConfigFileYaml.ts @@ -0,0 +1,34 @@ +import type { CSpellSettings } from '@cspell/cspell-types'; +import { parse, stringify } from 'yaml'; + +import { ImplCSpellConfigFile } from './CSpellConfigFile.js'; +import { detectIndentAsNum } from './deserializers/util.js'; +import type { Serializer } from './Serializer.js'; +import type { TextFile } from './TextFile.js'; + +export class CSpellConfigFileYaml extends ImplCSpellConfigFile { + constructor( + readonly url: URL, + readonly settings: CSpellSettings, + readonly serializer: Serializer, + ) { + super(url, settings); + } +} + +export function parseCSpellConfigFileYaml(file: TextFile): CSpellConfigFileYaml { + const { url, content } = file; + + const cspell = parse(content) || {}; + if (!cspell || typeof cspell !== 'object' || Array.isArray(cspell)) { + throw new Error(`Unable to parse ${url}`); + } + + const indent = detectIndentAsNum(content); + + function serialize(settings: CSpellSettings) { + return stringify(settings, { indent }); + } + + return new CSpellConfigFileYaml(url, cspell, serialize); +} diff --git a/packages/cspell-config-lib/src/ConfigReadWriteHandler.ts b/packages/cspell-config-lib/src/ConfigReadWriteHandler.ts new file mode 100644 index 00000000000..06e96807ae5 --- /dev/null +++ b/packages/cspell-config-lib/src/ConfigReadWriteHandler.ts @@ -0,0 +1,12 @@ +import type { CSpellConfigFileReference, ICSpellConfigFile } from './CSpellConfigFile.js'; + +export interface ConfigReadWriteHandler { + read( + ref: CSpellConfigFileReference, + next: (ref: CSpellConfigFileReference) => Promise, + ): Promise; + write?: ( + configFile: ICSpellConfigFile, + next: (configFile: ICSpellConfigFile) => Promise, + ) => Promise; +} diff --git a/packages/cspell-config-lib/src/Deserializer.ts b/packages/cspell-config-lib/src/Deserializer.ts index 91c4f1be6f4..cbb53420d3f 100644 --- a/packages/cspell-config-lib/src/Deserializer.ts +++ b/packages/cspell-config-lib/src/Deserializer.ts @@ -1,9 +1,7 @@ import type { ICSpellConfigFile } from './CSpellConfigFile.js'; +import type { TextFile } from './TextFile.js'; -export interface DeserializerParams { - url: URL; - content: string; -} +export interface DeserializerParams extends TextFile {} export interface DeserializerNext { (content: DeserializerParams): ICSpellConfigFile; diff --git a/packages/cspell-config-lib/src/TextFile.ts b/packages/cspell-config-lib/src/TextFile.ts new file mode 100644 index 00000000000..7a42ee331d3 --- /dev/null +++ b/packages/cspell-config-lib/src/TextFile.ts @@ -0,0 +1,4 @@ +export interface TextFile { + url: URL; + content: string; +} diff --git a/packages/cspell-config-lib/src/deserializers/cspellJson.ts b/packages/cspell-config-lib/src/deserializers/cspellJson.ts index c14132524d1..3dc166a7baa 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellJson.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellJson.ts @@ -1,27 +1,11 @@ -import type { CSpellSettings } from '@cspell/cspell-types'; -import { parse, stringify } from 'comment-json'; - import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; -import { ImplCSpellConfigFile } from '../CSpellConfigFile.js'; +import { parseCSpellConfigFileJson } from '../CSpellConfigFileJson.js'; import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; -import { detectIndent } from './util.js'; function _deserializerCSpellJson(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { - const { url, content } = params; - if (!isJsonFile(url.pathname)) return next(params); - - const cspell: CSpellSettings | unknown = parse(content); - if (!isCSpellSettings(cspell)) { - throw new Error(`Unable to parse ${url}`); - } - - const indent = detectIndent(content); + if (!isJsonFile(params.url.pathname)) return next(params); - function serialize(settings: CSpellSettings) { - return stringify(settings, null, indent) + '\n'; - } - - return new ImplCSpellConfigFile(url, cspell, serialize); + return parseCSpellConfigFileJson(params); } function isJsonFile(pathname: string) { @@ -29,8 +13,4 @@ function isJsonFile(pathname: string) { return pathname.endsWith('.json') || pathname.endsWith('.jsonc'); } -function isCSpellSettings(cfg: unknown): cfg is CSpellSettings { - return !(!cfg || typeof cfg !== 'object' || Array.isArray(cfg)); -} - export const deserializerCSpellJson: Deserializer = _deserializerCSpellJson; diff --git a/packages/cspell-config-lib/src/deserializers/cspellYaml.ts b/packages/cspell-config-lib/src/deserializers/cspellYaml.ts index 423a57d7dd2..c787c6a6642 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellYaml.ts +++ b/packages/cspell-config-lib/src/deserializers/cspellYaml.ts @@ -1,27 +1,11 @@ -import type { CSpellSettings } from '@cspell/cspell-types'; -import { parse, stringify } from 'yaml'; - import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; -import { ImplCSpellConfigFile } from '../CSpellConfigFile.js'; +import { parseCSpellConfigFileYaml } from '../CSpellConfigFileYaml.js'; import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; -import { detectIndentAsNum } from './util.js'; function _deserializerCSpellYaml(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { - const { url, content } = params; - if (!isYamlFile(url.pathname)) return next(params); - - const cspell = parse(content) || {}; - if (!cspell || typeof cspell !== 'object' || Array.isArray(cspell)) { - throw new Error(`Unable to parse ${url}`); - } - - const indent = detectIndentAsNum(content); - - function serialize(settings: CSpellSettings) { - return stringify(settings, { indent }); - } + if (!isYamlFile(params.url.pathname)) return next(params); - return new ImplCSpellConfigFile(url, cspell, serialize); + return parseCSpellConfigFileYaml(params); } function isYamlFile(pathname: string) { diff --git a/packages/cspell-config-lib/src/deserializers/packageJson.ts b/packages/cspell-config-lib/src/deserializers/packageJson.ts index d4f1b1cd2dd..74004ee363a 100644 --- a/packages/cspell-config-lib/src/deserializers/packageJson.ts +++ b/packages/cspell-config-lib/src/deserializers/packageJson.ts @@ -1,34 +1,13 @@ -import type { CSpellSettings } from '@cspell/cspell-types'; - import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; -import { ImplCSpellConfigFile } from '../CSpellConfigFile.js'; +import { parseCSpellConfigFilePackageJson } from '../CSpellConfigFilePackageJson.js'; import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; -import { detectIndent } from './util.js'; const isSupportedFormat = /\bpackage\.json$/i; function _deserializerPackageJson(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { - const { url: url, content } = params; - if (!isSupportedFormat.test(url.pathname)) return next(params); - - const packageJson = JSON.parse(content); - if (!packageJson || typeof packageJson !== 'object' || Array.isArray(packageJson)) { - throw new Error(`Unable to parse ${url}`); - } - packageJson['cspell'] = packageJson['cspell'] || {}; - const cspell = packageJson['cspell']; - if (typeof cspell !== 'object' || Array.isArray(cspell)) { - throw new Error(`Unable to parse ${url}`); - } - - const indent = detectIndent(content); - - function serialize(settings: CSpellSettings) { - packageJson['cspell'] = settings; - return JSON.stringify(packageJson, null, indent) + '\n'; - } + if (!isSupportedFormat.test(params.url.pathname)) return next(params); - return new ImplCSpellConfigFile(url, cspell, serialize); + return parseCSpellConfigFilePackageJson(params); } export const deserializerPackageJson: Deserializer = _deserializerPackageJson; From ba07d122aab352996b184e598369f5e862d719cf Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Thu, 16 Nov 2023 10:44:18 +0100 Subject: [PATCH 4/9] refactor: rename middleware --- .../cspell-config-lib/src/CSpellConfigFile.ts | 11 ------ .../src/CSpellConfigFileJson.ts | 10 ++++-- .../src/CSpellConfigFilePackageJson.ts | 10 ++++-- .../src/CSpellConfigFileReaderWriter.test.ts | 17 +++------ .../src/CSpellConfigFileReaderWriter.ts | 35 ++++++++++++------- .../src/CSpellConfigFileYaml.ts | 10 ++++-- .../cspell-config-lib/src/Deserializer.ts | 15 -------- packages/cspell-config-lib/src/Serializer.ts | 34 ++++++++++++++++-- .../src/createReaderWriter.test.ts | 4 +-- .../src/createReaderWriter.ts | 6 ++-- packages/cspell-config-lib/src/defaultNext.ts | 10 ++++++ .../src/deserializers/cspellJson.ts | 16 --------- .../src/deserializers/cspellYaml.ts | 16 --------- .../src/deserializers/index.ts | 10 ------ .../src/deserializers/packageJson.ts | 13 ------- packages/cspell-config-lib/src/index.test.ts | 4 ++- packages/cspell-config-lib/src/index.ts | 16 +++++++-- .../cspellJson.test.ts | 27 ++++++++++---- .../src/serializers/cspellJson.ts | 21 +++++++++++ .../cspellYaml.test.ts | 30 +++++++++++----- .../src/serializers/cspellYaml.ts | 21 +++++++++++ .../index.test.ts | 0 .../src/serializers/index.ts | 10 ++++++ .../packageJson.test.ts | 26 +++++++++----- .../src/serializers/packageJson.ts | 18 ++++++++++ .../util.test.ts | 0 .../{deserializers => serializers}/util.ts | 0 27 files changed, 242 insertions(+), 148 deletions(-) delete mode 100644 packages/cspell-config-lib/src/Deserializer.ts create mode 100644 packages/cspell-config-lib/src/defaultNext.ts delete mode 100644 packages/cspell-config-lib/src/deserializers/cspellJson.ts delete mode 100644 packages/cspell-config-lib/src/deserializers/cspellYaml.ts delete mode 100644 packages/cspell-config-lib/src/deserializers/index.ts delete mode 100644 packages/cspell-config-lib/src/deserializers/packageJson.ts rename packages/cspell-config-lib/src/{deserializers => serializers}/cspellJson.test.ts (60%) create mode 100644 packages/cspell-config-lib/src/serializers/cspellJson.ts rename packages/cspell-config-lib/src/{deserializers => serializers}/cspellYaml.test.ts (64%) create mode 100644 packages/cspell-config-lib/src/serializers/cspellYaml.ts rename packages/cspell-config-lib/src/{deserializers => serializers}/index.test.ts (100%) create mode 100644 packages/cspell-config-lib/src/serializers/index.ts rename packages/cspell-config-lib/src/{deserializers => serializers}/packageJson.test.ts (63%) create mode 100644 packages/cspell-config-lib/src/serializers/packageJson.ts rename packages/cspell-config-lib/src/{deserializers => serializers}/util.test.ts (100%) rename packages/cspell-config-lib/src/{deserializers => serializers}/util.ts (100%) diff --git a/packages/cspell-config-lib/src/CSpellConfigFile.ts b/packages/cspell-config-lib/src/CSpellConfigFile.ts index 2f38e7ce12f..1564ced2128 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFile.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFile.ts @@ -1,7 +1,5 @@ import type { CSpellSettings } from '@cspell/cspell-types'; -import type { Serializer } from './Serializer.js'; - export interface CSpellConfigFileReference { readonly url: URL; } @@ -10,21 +8,16 @@ export interface ICSpellConfigFile { readonly url: URL; readonly settings: CSpellSettings; readonly readonly?: boolean; - serialize: () => string; - addWords(words: string[]): this; } export abstract class CSpellConfigFile implements ICSpellConfigFile { constructor(readonly url: URL) {} abstract readonly settings: CSpellSettings; - abstract serialize(): string; abstract addWords(words: string[]): this; } export abstract class ImplCSpellConfigFile extends CSpellConfigFile { - abstract readonly serializer: Serializer; - constructor( readonly url: URL, readonly settings: CSpellSettings, @@ -32,10 +25,6 @@ export abstract class ImplCSpellConfigFile extends CSpellConfigFile { super(url); } - serialize(): string { - return this.serializer(this.settings); - } - addWords(words: string[]): this { const w = this.settings.words || []; this.settings.words = w; diff --git a/packages/cspell-config-lib/src/CSpellConfigFileJson.ts b/packages/cspell-config-lib/src/CSpellConfigFileJson.ts index 0a4368a6c86..63c58829a74 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileJson.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileJson.ts @@ -2,18 +2,22 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import { parse, stringify } from 'comment-json'; import { ImplCSpellConfigFile } from './CSpellConfigFile.js'; -import { detectIndent } from './deserializers/util.js'; -import type { Serializer } from './Serializer.js'; +import type { SerializeSettingsFn } from './Serializer.js'; +import { detectIndent } from './serializers/util.js'; import type { TextFile } from './TextFile.js'; export class CSpellConfigFileJson extends ImplCSpellConfigFile { constructor( readonly url: URL, readonly settings: CSpellSettings, - readonly serializer: Serializer, + readonly serializer: SerializeSettingsFn, ) { super(url, settings); } + + serialize() { + return this.serializer(this.settings); + } } export function parseCSpellConfigFileJson(file: TextFile): CSpellConfigFileJson { diff --git a/packages/cspell-config-lib/src/CSpellConfigFilePackageJson.ts b/packages/cspell-config-lib/src/CSpellConfigFilePackageJson.ts index e63fbd3d8f1..8b87bd6cbfb 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFilePackageJson.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFilePackageJson.ts @@ -1,18 +1,22 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import { ImplCSpellConfigFile } from './CSpellConfigFile.js'; -import { detectIndent } from './deserializers/util.js'; -import type { Serializer } from './Serializer.js'; +import type { SerializeSettingsFn } from './Serializer.js'; +import { detectIndent } from './serializers/util.js'; import type { TextFile } from './TextFile.js'; export class CSpellConfigFilePackageJson extends ImplCSpellConfigFile { constructor( readonly url: URL, readonly settings: CSpellSettings, - readonly serializer: Serializer, + readonly serializer: SerializeSettingsFn, ) { super(url, settings); } + + serialize() { + return this.serializer(this.settings); + } } export function parseCSpellConfigFilePackageJson(file: TextFile): CSpellConfigFilePackageJson { diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts index 6f26de8afe9..87a1faf8b5c 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts @@ -1,9 +1,8 @@ import { describe, expect, test, vi } from 'vitest'; -import type { ICSpellConfigFile } from './CSpellConfigFile.js'; import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter.js'; -import { defaultDeserializers } from './deserializers/index.js'; import type { IO } from './IO.js'; +import { defaultDeserializers } from './serializers/index.js'; import { json } from './test-helpers/util.js'; const oc = expect.objectContaining; @@ -34,8 +33,8 @@ describe('CSpellConfigFileReaderWriter', () => { }); test.each` - uri | content - ${'file:///cspell.js'} | ${'content'} + uri | content + ${'file:///cspell.json'} | ${'{}\n'} `('writeConfig', async ({ uri, content }) => { const io: IO = { readFile: vi.fn(() => content), @@ -43,14 +42,8 @@ describe('CSpellConfigFileReaderWriter', () => { }; const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); - const cf: ICSpellConfigFile = { - url: uri, - settings: {}, - serialize: vi.fn(() => content), - addWords: vi.fn(), - }; + const cf = await rw.readConfig(uri); await expect(rw.writeConfig(cf)).resolves.toBeUndefined(); - expect(io.writeFile).toHaveBeenCalledWith(uri, content); - expect(cf.serialize).toHaveBeenCalledTimes(1); + expect(io.writeFile).toHaveBeenCalledWith(new URL(uri), content); }); }); diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts index f17b61e13dd..79289b701b2 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts @@ -1,15 +1,12 @@ import type { ICSpellConfigFile } from './CSpellConfigFile.js'; -import type { Deserializer, DeserializerNext, DeserializerParams } from './Deserializer.js'; +import { defaultNextDeserializer, defaultNextSerializer } from './defaultNext.js'; import type { IO } from './IO.js'; +import type { DeserializerNext, DeserializerParams, SerializerMiddleware, SerializerNext } from './Serializer.js'; import { toURL } from './util/toURL.js'; -export const defaultNextDeserializer: DeserializerNext = (content: DeserializerParams) => { - throw new Error(`Unable to parse config file: "${content.url}"`); -}; - export interface CSpellConfigFileReaderWriter { readonly io: IO; - readonly deserializers: Deserializer[]; + readonly middleware: SerializerMiddleware[]; readConfig(uri: URL | string): Promise; writeConfig(configFile: ICSpellConfigFile): Promise; } @@ -17,7 +14,7 @@ export interface CSpellConfigFileReaderWriter { export class CSpellConfigFileReaderWriterImpl implements CSpellConfigFileReaderWriter { constructor( readonly io: IO, - readonly deserializers: Deserializer[], + readonly middleware: SerializerMiddleware[], ) {} async readConfig(uri: URL | string): Promise { @@ -28,19 +25,33 @@ export class CSpellConfigFileReaderWriterImpl implements CSpellConfigFileReaderW const desContent: DeserializerParams = { url, content }; - for (const des of [...this.deserializers].reverse()) { - next = curry(des, next); + for (const des of [...this.middleware].reverse()) { + next = curryDeserialize(des, next); } return next(desContent); } + serialize(configFile: ICSpellConfigFile): string { + let next: SerializerNext = defaultNextSerializer; + + for (const des of [...this.middleware].reverse()) { + next = currySerialize(des, next); + } + + return next(configFile); + } + writeConfig(configFile: ICSpellConfigFile): Promise { - const content = configFile.serialize(); + const content = this.serialize(configFile); return this.io.writeFile(configFile.url, content); } } -function curry(des: Deserializer, next: DeserializerNext): DeserializerNext { - return (content) => des(content, next); +function curryDeserialize(middle: SerializerMiddleware, next: DeserializerNext): DeserializerNext { + return (content) => middle.deserialize(content, next); +} + +function currySerialize(middle: SerializerMiddleware, next: SerializerNext): SerializerNext { + return (cfg) => middle.serialize(cfg, next); } diff --git a/packages/cspell-config-lib/src/CSpellConfigFileYaml.ts b/packages/cspell-config-lib/src/CSpellConfigFileYaml.ts index 831f7ca9273..1f4d41b5af3 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileYaml.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileYaml.ts @@ -2,18 +2,22 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import { parse, stringify } from 'yaml'; import { ImplCSpellConfigFile } from './CSpellConfigFile.js'; -import { detectIndentAsNum } from './deserializers/util.js'; -import type { Serializer } from './Serializer.js'; +import type { SerializeSettingsFn } from './Serializer.js'; +import { detectIndentAsNum } from './serializers/util.js'; import type { TextFile } from './TextFile.js'; export class CSpellConfigFileYaml extends ImplCSpellConfigFile { constructor( readonly url: URL, readonly settings: CSpellSettings, - readonly serializer: Serializer, + readonly serializer: SerializeSettingsFn, ) { super(url, settings); } + + serialize() { + return this.serializer(this.settings); + } } export function parseCSpellConfigFileYaml(file: TextFile): CSpellConfigFileYaml { diff --git a/packages/cspell-config-lib/src/Deserializer.ts b/packages/cspell-config-lib/src/Deserializer.ts deleted file mode 100644 index cbb53420d3f..00000000000 --- a/packages/cspell-config-lib/src/Deserializer.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { ICSpellConfigFile } from './CSpellConfigFile.js'; -import type { TextFile } from './TextFile.js'; - -export interface DeserializerParams extends TextFile {} - -export interface DeserializerNext { - (content: DeserializerParams): ICSpellConfigFile; -} - -export interface Deserializer { - /** - * If a Deserializer can handle a given request, it returns a CSpellConfigFile, otherwise it calls `next`. - */ - (params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile; -} diff --git a/packages/cspell-config-lib/src/Serializer.ts b/packages/cspell-config-lib/src/Serializer.ts index 6337b5ba595..4be8c285724 100644 --- a/packages/cspell-config-lib/src/Serializer.ts +++ b/packages/cspell-config-lib/src/Serializer.ts @@ -1,5 +1,35 @@ import type { CSpellSettings } from '@cspell/cspell-types'; -export interface Serializer { - (settings: CSpellSettings): string; +import type { ICSpellConfigFile } from './CSpellConfigFile.js'; +import type { TextFile } from './TextFile.js'; + +export interface SerializerNext { + (content: ICSpellConfigFile): string; +} + +export interface SerializerReducer { + /** + * If a Serializer can handle a given request, it returns a CSpellConfigFile, otherwise it calls `next`. + */ + (settings: ICSpellConfigFile, next: SerializerNext): string; +} + +export type SerializeSettingsFn = (settings: CSpellSettings) => string; + +export interface DeserializerParams extends TextFile {} + +export interface DeserializerNext { + (content: DeserializerParams): ICSpellConfigFile; +} + +export interface DeserializerReducer { + /** + * If a Deserializer can handle a given request, it returns a CSpellConfigFile, otherwise it calls `next`. + */ + (params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile; +} + +export interface SerializerMiddleware { + serialize: SerializerReducer; + deserialize: DeserializerReducer; } diff --git a/packages/cspell-config-lib/src/createReaderWriter.test.ts b/packages/cspell-config-lib/src/createReaderWriter.test.ts index cb7766e32c0..4e290c0b83d 100644 --- a/packages/cspell-config-lib/src/createReaderWriter.test.ts +++ b/packages/cspell-config-lib/src/createReaderWriter.test.ts @@ -2,8 +2,8 @@ import { describe, expect, test, vi } from 'vitest'; import { createReaderWriter } from './createReaderWriter.js'; import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter.js'; -import { defaultDeserializers } from './deserializers/index.js'; import type { IO } from './IO.js'; +import { defaultDeserializers } from './serializers/index.js'; describe('createReaderWriter', () => { test('createReaderWriter default', () => { @@ -17,6 +17,6 @@ describe('createReaderWriter', () => { }; const rw = createReaderWriter([], io); expect(rw).toBeInstanceOf(CSpellConfigFileReaderWriterImpl); - expect(rw.deserializers).toHaveLength(defaultDeserializers.length); + expect(rw.middleware).toHaveLength(defaultDeserializers.length); }); }); diff --git a/packages/cspell-config-lib/src/createReaderWriter.ts b/packages/cspell-config-lib/src/createReaderWriter.ts index 8279f73177c..801da7555dc 100644 --- a/packages/cspell-config-lib/src/createReaderWriter.ts +++ b/packages/cspell-config-lib/src/createReaderWriter.ts @@ -2,9 +2,9 @@ import { promises as fs } from 'fs'; import type { CSpellConfigFileReaderWriter } from './CSpellConfigFileReaderWriter.js'; import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter.js'; -import type { Deserializer } from './Deserializer.js'; -import { defaultDeserializers } from './deserializers/index.js'; import type { IO } from './IO.js'; +import type { SerializerMiddleware } from './Serializer.js'; +import { defaultDeserializers } from './serializers/index.js'; const defaultIO: IO = { readFile, @@ -12,7 +12,7 @@ const defaultIO: IO = { }; export function createReaderWriter( - deserializers: Deserializer[] = [], + deserializers: SerializerMiddleware[] = [], io: IO = defaultIO, ): CSpellConfigFileReaderWriter { return new CSpellConfigFileReaderWriterImpl(io, deserializers.concat(defaultDeserializers)); diff --git a/packages/cspell-config-lib/src/defaultNext.ts b/packages/cspell-config-lib/src/defaultNext.ts new file mode 100644 index 00000000000..30c5847e6c1 --- /dev/null +++ b/packages/cspell-config-lib/src/defaultNext.ts @@ -0,0 +1,10 @@ +import type { ICSpellConfigFile } from './CSpellConfigFile.js'; +import type { DeserializerNext, DeserializerParams, SerializerNext } from './Serializer.js'; + +export const defaultNextDeserializer: DeserializerNext = (content: DeserializerParams) => { + throw new Error(`Unable to parse config file: "${content.url}"`); +}; + +export const defaultNextSerializer: SerializerNext = (file: ICSpellConfigFile) => { + throw new Error(`Unable to serialize config file: "${file.url}"`); +}; diff --git a/packages/cspell-config-lib/src/deserializers/cspellJson.ts b/packages/cspell-config-lib/src/deserializers/cspellJson.ts deleted file mode 100644 index 3dc166a7baa..00000000000 --- a/packages/cspell-config-lib/src/deserializers/cspellJson.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; -import { parseCSpellConfigFileJson } from '../CSpellConfigFileJson.js'; -import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; - -function _deserializerCSpellJson(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { - if (!isJsonFile(params.url.pathname)) return next(params); - - return parseCSpellConfigFileJson(params); -} - -function isJsonFile(pathname: string) { - pathname = pathname.toLowerCase(); - return pathname.endsWith('.json') || pathname.endsWith('.jsonc'); -} - -export const deserializerCSpellJson: Deserializer = _deserializerCSpellJson; diff --git a/packages/cspell-config-lib/src/deserializers/cspellYaml.ts b/packages/cspell-config-lib/src/deserializers/cspellYaml.ts deleted file mode 100644 index c787c6a6642..00000000000 --- a/packages/cspell-config-lib/src/deserializers/cspellYaml.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; -import { parseCSpellConfigFileYaml } from '../CSpellConfigFileYaml.js'; -import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; - -function _deserializerCSpellYaml(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { - if (!isYamlFile(params.url.pathname)) return next(params); - - return parseCSpellConfigFileYaml(params); -} - -function isYamlFile(pathname: string) { - pathname = pathname.toLowerCase(); - return pathname.endsWith('.yml') || pathname.endsWith('.yaml'); -} - -export const deserializerCSpellYaml: Deserializer = _deserializerCSpellYaml; diff --git a/packages/cspell-config-lib/src/deserializers/index.ts b/packages/cspell-config-lib/src/deserializers/index.ts deleted file mode 100644 index 638851c7477..00000000000 --- a/packages/cspell-config-lib/src/deserializers/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { Deserializer } from '../Deserializer.js'; -import { deserializerCSpellJson } from './cspellJson.js'; -import { deserializerCSpellYaml } from './cspellYaml.js'; -import { deserializerPackageJson } from './packageJson.js'; - -export const defaultDeserializers: Deserializer[] = [ - deserializerPackageJson, - deserializerCSpellJson, - deserializerCSpellYaml, -]; diff --git a/packages/cspell-config-lib/src/deserializers/packageJson.ts b/packages/cspell-config-lib/src/deserializers/packageJson.ts deleted file mode 100644 index 74004ee363a..00000000000 --- a/packages/cspell-config-lib/src/deserializers/packageJson.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; -import { parseCSpellConfigFilePackageJson } from '../CSpellConfigFilePackageJson.js'; -import type { Deserializer, DeserializerNext, DeserializerParams } from '../Deserializer.js'; - -const isSupportedFormat = /\bpackage\.json$/i; - -function _deserializerPackageJson(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { - if (!isSupportedFormat.test(params.url.pathname)) return next(params); - - return parseCSpellConfigFilePackageJson(params); -} - -export const deserializerPackageJson: Deserializer = _deserializerPackageJson; diff --git a/packages/cspell-config-lib/src/index.test.ts b/packages/cspell-config-lib/src/index.test.ts index e8098227b97..c9fc16483dc 100644 --- a/packages/cspell-config-lib/src/index.test.ts +++ b/packages/cspell-config-lib/src/index.test.ts @@ -1,3 +1,4 @@ +import assert from 'node:assert'; import { promises as fs } from 'node:fs'; import { resolve } from 'node:path'; import { pathToFileURL } from 'node:url'; @@ -5,7 +6,7 @@ import { pathToFileURL } from 'node:url'; import { describe, expect, test } from 'vitest'; import * as index from './index.js'; -import { createReaderWriter } from './index.js'; +import { createReaderWriter, CSpellConfigFile } from './index.js'; import { fixtures } from './test-helpers/fixtures.js'; import { copyFile, tempPath } from './test-helpers/util.js'; @@ -35,6 +36,7 @@ describe('cspell-config', () => { const rw = createReaderWriter(); const uri = pathToFileURL(resolve(tempFile)); const cfg = await rw.readConfig(uri); + assert(cfg instanceof CSpellConfigFile); cfg.addWords(addWords); await rw.writeConfig(cfg); expect(await fs.readFile(tempFile, 'utf-8')).toMatchSnapshot(); diff --git a/packages/cspell-config-lib/src/index.ts b/packages/cspell-config-lib/src/index.ts index 8a60200598a..70f370e0b29 100644 --- a/packages/cspell-config-lib/src/index.ts +++ b/packages/cspell-config-lib/src/index.ts @@ -1,6 +1,16 @@ export { createReaderWriter } from './createReaderWriter.js'; -export type { ICSpellConfigFile as CSpellConfigFile } from './CSpellConfigFile.js'; +export { CSpellConfigFile } from './CSpellConfigFile.js'; +export { CSpellConfigFileJson } from './CSpellConfigFileJson.js'; +export { CSpellConfigFilePackageJson } from './CSpellConfigFilePackageJson.js'; export type { CSpellConfigFileReaderWriter } from './CSpellConfigFileReaderWriter.js'; -export type { Deserializer, DeserializerNext, DeserializerParams } from './Deserializer.js'; +export { CSpellConfigFileYaml } from './CSpellConfigFileYaml.js'; export type { IO } from './IO.js'; -export type { Serializer } from './Serializer.js'; +export type { + DeserializerNext, + DeserializerParams, + DeserializerReducer, + SerializerMiddleware, + SerializerNext, + SerializerReducer, + SerializeSettingsFn, +} from './Serializer.js'; diff --git a/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts b/packages/cspell-config-lib/src/serializers/cspellJson.test.ts similarity index 60% rename from packages/cspell-config-lib/src/deserializers/cspellJson.test.ts rename to packages/cspell-config-lib/src/serializers/cspellJson.test.ts index 506789f144c..7defb0f05b2 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellJson.test.ts +++ b/packages/cspell-config-lib/src/serializers/cspellJson.test.ts @@ -1,8 +1,10 @@ -import { describe, expect, test } from 'vitest'; +import assert from 'assert'; +import { describe, expect, test, vi } from 'vitest'; -import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter.js'; +import { CSpellConfigFileJson } from '../CSpellConfigFileJson.js'; +import { defaultNextDeserializer, defaultNextSerializer } from '../defaultNext.js'; import { json } from '../test-helpers/util.js'; -import { deserializerCSpellJson } from './cspellJson.js'; +import { serializerCSpellJson } from './cspellJson.js'; const oc = expect.objectContaining; @@ -24,7 +26,7 @@ describe('cspellJson', () => { ${'cspell-ext.json'} | ${'{}'} | ${oc({ settings: {} })} ${'.cspell.json'} | ${'{\n // add words here\n "words":[]}'} | ${oc({ settings: { words: [] } })} `('success $uri', ({ uri, content, expected }) => { - expect(deserializerCSpellJson({ url: new URL(uri, 'file:///'), content }, next)).toEqual(expected); + expect(serializerCSpellJson.deserialize({ url: new URL(uri, 'file:///'), content }, next)).toEqual(expected); }); test.each` @@ -35,7 +37,9 @@ describe('cspellJson', () => { ${'cspell.json'} | ${''} | ${'Unexpected end of JSON input'} ${'cspell.json'} | ${'[]'} | ${'Unable to parse file:///cspell.json'} `('fail $uri', ({ uri, content, expected }) => { - expect(() => deserializerCSpellJson({ url: new URL(uri, 'file:///'), content }, next)).toThrow(expected); + expect(() => serializerCSpellJson.deserialize({ url: new URL(uri, 'file:///'), content }, next)).toThrow( + expected, + ); }); test.each` @@ -44,7 +48,16 @@ describe('cspellJson', () => { ${'cspell.json?x=5'} | ${'{\n "words":[]}'} | ${json({ words: [] }, 2)} ${'cspell.jsonc'} | ${sampleCSpellJson} | ${sampleCSpellJson} `('serialize $uri', ({ uri, content, expected }) => { - const file = deserializerCSpellJson({ url: new URL(uri, 'file:///'), content }, next); - expect(file?.serialize()).toEqual(expected); + const next = vi.fn(); + const file = serializerCSpellJson.deserialize({ url: new URL(uri, 'file:///'), content }, next); + assert(file instanceof CSpellConfigFileJson); + expect(serializerCSpellJson.serialize(file, defaultNextSerializer)).toEqual(expected); + expect(next).toHaveBeenCalledTimes(0); + }); + + test('serialize reject', () => { + const next = vi.fn(); + serializerCSpellJson.serialize({ url: new URL('file:///file.txt'), settings: {} }, next); + expect(next).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/cspell-config-lib/src/serializers/cspellJson.ts b/packages/cspell-config-lib/src/serializers/cspellJson.ts new file mode 100644 index 00000000000..d5ef2525777 --- /dev/null +++ b/packages/cspell-config-lib/src/serializers/cspellJson.ts @@ -0,0 +1,21 @@ +import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; +import { CSpellConfigFileJson, parseCSpellConfigFileJson } from '../CSpellConfigFileJson.js'; +import type { DeserializerNext, DeserializerParams, SerializerMiddleware, SerializerNext } from '../Serializer.js'; + +function deserializer(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { + if (!isJsonFile(params.url.pathname)) return next(params); + + return parseCSpellConfigFileJson(params); +} + +function isJsonFile(pathname: string) { + pathname = pathname.toLowerCase(); + return pathname.endsWith('.json') || pathname.endsWith('.jsonc'); +} + +function serializer(settings: ICSpellConfigFile, next: SerializerNext): string { + if (!(settings instanceof CSpellConfigFileJson)) return next(settings); + return settings.serialize(); +} + +export const serializerCSpellJson: SerializerMiddleware = { deserialize: deserializer, serialize: serializer }; diff --git a/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts b/packages/cspell-config-lib/src/serializers/cspellYaml.test.ts similarity index 64% rename from packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts rename to packages/cspell-config-lib/src/serializers/cspellYaml.test.ts index cdfc7db0df5..30693c34ee2 100644 --- a/packages/cspell-config-lib/src/deserializers/cspellYaml.test.ts +++ b/packages/cspell-config-lib/src/serializers/cspellYaml.test.ts @@ -1,9 +1,12 @@ -import { describe, expect, test } from 'vitest'; +import assert from 'node:assert'; +import { pathToFileURL } from 'node:url'; + +import { describe, expect, test, vi } from 'vitest'; import { stringify } from 'yaml'; -import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter.js'; -import { deserializerCSpellYaml } from './cspellYaml.js'; -import { pathToFileURL } from 'node:url'; +import { defaultNextDeserializer, defaultNextSerializer } from '../defaultNext.js'; +import { CSpellConfigFileYaml } from '../CSpellConfigFileYaml.js'; +import { serializerCSpellYaml } from './cspellYaml.js'; const oc = expect.objectContaining; const next = defaultNextDeserializer; @@ -22,7 +25,7 @@ words: ${'cspell-ext.yml'} | ${'---\nversion: "0.2"\n'} | ${oc({ settings: { version: '0.2' } })} ${'.cspell.yml'} | ${'\nwords: []\n'} | ${oc({ settings: { words: [] } })} `('success $uri', ({ uri, content, expected }) => { - expect(deserializerCSpellYaml({ url: pathToFileURL(uri), content }, next)).toEqual(expected); + expect(serializerCSpellYaml.deserialize({ url: pathToFileURL(uri), content }, next)).toEqual(expected); }); test.each` @@ -33,7 +36,9 @@ words: ${'cspell.yaml'} | ${'"version'} | ${'Missing closing'} ${'cspell.yaml'} | ${'[]'} | ${'Unable to parse file:///cspell.yaml'} `('fail $uri', ({ uri, content, expected }) => { - expect(() => deserializerCSpellYaml({ url: new URL(uri, 'file:///'), content }, next)).toThrow(expected); + expect(() => serializerCSpellYaml.deserialize({ url: new URL(uri, 'file:///'), content }, next)).toThrow( + expected, + ); }); test.each` @@ -42,8 +47,17 @@ words: ${'cspell.yaml?x=5'} | ${'{\n "words":[]}'} | ${toYaml({ words: [] }, 2)} ${'cspell.yml'} | ${sampleCSpellYaml} | ${sampleCSpellYaml} `('serialize $uri', ({ uri, content, expected }) => { - const file = deserializerCSpellYaml({ url: new URL(uri, 'file:///'), content }, next); - expect(file?.serialize()).toEqual(expected); + const next = vi.fn(); + const file = serializerCSpellYaml.deserialize({ url: new URL(uri, 'file:///'), content }, next); + assert(file instanceof CSpellConfigFileYaml); + expect(serializerCSpellYaml.serialize(file, next)).toEqual(expected); + expect(next).toHaveBeenCalledTimes(0); + }); + + test('serialize reject', () => { + const next = vi.fn(); + serializerCSpellYaml.serialize({ url: new URL('file:///file.txt'), settings: {} }, next); + expect(next).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/cspell-config-lib/src/serializers/cspellYaml.ts b/packages/cspell-config-lib/src/serializers/cspellYaml.ts new file mode 100644 index 00000000000..fa75260bb7d --- /dev/null +++ b/packages/cspell-config-lib/src/serializers/cspellYaml.ts @@ -0,0 +1,21 @@ +import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; +import { CSpellConfigFileYaml, parseCSpellConfigFileYaml } from '../CSpellConfigFileYaml.js'; +import type { DeserializerNext, DeserializerParams, SerializerMiddleware, SerializerNext } from '../Serializer.js'; + +function deserializer(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { + if (!isYamlFile(params.url.pathname)) return next(params); + + return parseCSpellConfigFileYaml(params); +} + +function isYamlFile(pathname: string) { + pathname = pathname.toLowerCase(); + return pathname.endsWith('.yml') || pathname.endsWith('.yaml'); +} + +function serializer(settings: ICSpellConfigFile, next: SerializerNext): string { + if (!(settings instanceof CSpellConfigFileYaml)) return next(settings); + return settings.serialize(); +} + +export const serializerCSpellYaml: SerializerMiddleware = { deserialize: deserializer, serialize: serializer }; diff --git a/packages/cspell-config-lib/src/deserializers/index.test.ts b/packages/cspell-config-lib/src/serializers/index.test.ts similarity index 100% rename from packages/cspell-config-lib/src/deserializers/index.test.ts rename to packages/cspell-config-lib/src/serializers/index.test.ts diff --git a/packages/cspell-config-lib/src/serializers/index.ts b/packages/cspell-config-lib/src/serializers/index.ts new file mode 100644 index 00000000000..cd2728fbacd --- /dev/null +++ b/packages/cspell-config-lib/src/serializers/index.ts @@ -0,0 +1,10 @@ +import type { SerializerMiddleware } from '../Serializer.js'; +import { serializerCSpellJson } from './cspellJson.js'; +import { serializerCSpellYaml } from './cspellYaml.js'; +import { serializerPackageJson } from './packageJson.js'; + +export const defaultDeserializers: SerializerMiddleware[] = [ + serializerPackageJson, + serializerCSpellJson, + serializerCSpellYaml, +]; diff --git a/packages/cspell-config-lib/src/deserializers/packageJson.test.ts b/packages/cspell-config-lib/src/serializers/packageJson.test.ts similarity index 63% rename from packages/cspell-config-lib/src/deserializers/packageJson.test.ts rename to packages/cspell-config-lib/src/serializers/packageJson.test.ts index f73f31f59dd..167c30d191d 100644 --- a/packages/cspell-config-lib/src/deserializers/packageJson.test.ts +++ b/packages/cspell-config-lib/src/serializers/packageJson.test.ts @@ -1,10 +1,11 @@ -import { pathToFileURL } from 'node:url'; +import assert from 'node:assert'; -import { describe, expect, test } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; -import { defaultNextDeserializer } from '../CSpellConfigFileReaderWriter.js'; +import { CSpellConfigFilePackageJson } from '../CSpellConfigFilePackageJson.js'; +import { defaultNextDeserializer, defaultNextSerializer } from '../defaultNext.js'; import { json } from '../test-helpers/util.js'; -import { deserializerPackageJson } from './packageJson.js'; +import { serializerPackageJson } from './packageJson.js'; const oc = expect.objectContaining; const next = defaultNextDeserializer; @@ -15,7 +16,9 @@ describe('packageJson', () => { ${'package.json'} | ${'{}'} | ${oc({ settings: {} })} ${'package.json?x=5'} | ${'{"cspell":{"words":[]}}'} | ${oc({ settings: { words: [] } })} `('success $uri', ({ uri, content, expected }) => { - expect(deserializerPackageJson({ url: new URL(uri, import.meta.url), content }, next)).toEqual(expected); + expect(serializerPackageJson.deserialize({ url: new URL(uri, import.meta.url), content }, next)).toEqual( + expected, + ); }); test.each` @@ -28,7 +31,7 @@ describe('packageJson', () => { ${'file:///package.json'} | ${'[]'} | ${'Unable to parse file:///package.json'} ${'file:///package.json'} | ${'{"cspell": []}'} | ${'Unable to parse file:///package.json'} `('fail $url', ({ url, content, expected }) => { - expect(() => deserializerPackageJson({ url: new URL(url), content }, next)).toThrow(expected); + expect(() => serializerPackageJson.deserialize({ url: new URL(url), content }, next)).toThrow(expected); }); test.each` @@ -37,7 +40,14 @@ describe('packageJson', () => { ${'package.json?x=5'} | ${'{\n "cspell":{"words":[]}}'} | ${json({ cspell: { words: [] } }, 2)} ${'package.json?x=5'} | ${'{\n "cspell":{"words":[]}}'} | ${json({ cspell: { words: [] } }, 2)} `('serialize $uri', ({ uri, content, expected }) => { - const file = deserializerPackageJson({ url: new URL(uri, import.meta.url), content }, next); - expect(file?.serialize()).toEqual(expected); + const file = serializerPackageJson.deserialize({ url: new URL(uri, import.meta.url), content }, next); + assert(file instanceof CSpellConfigFilePackageJson); + expect(serializerPackageJson.serialize(file, defaultNextSerializer)).toEqual(expected); + }); + + test('serialize reject', () => { + const next = vi.fn(); + serializerPackageJson.serialize({ url: new URL('file:///file.txt'), settings: {} }, next); + expect(next).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/cspell-config-lib/src/serializers/packageJson.ts b/packages/cspell-config-lib/src/serializers/packageJson.ts new file mode 100644 index 00000000000..3fcdfaf8e8b --- /dev/null +++ b/packages/cspell-config-lib/src/serializers/packageJson.ts @@ -0,0 +1,18 @@ +import type { ICSpellConfigFile } from '../CSpellConfigFile.js'; +import { CSpellConfigFilePackageJson, parseCSpellConfigFilePackageJson } from '../CSpellConfigFilePackageJson.js'; +import type { DeserializerNext, DeserializerParams, SerializerMiddleware, SerializerNext } from '../Serializer.js'; + +const isSupportedFormat = /\bpackage\.json$/i; + +function deserializer(params: DeserializerParams, next: DeserializerNext): ICSpellConfigFile { + if (!isSupportedFormat.test(params.url.pathname)) return next(params); + + return parseCSpellConfigFilePackageJson(params); +} + +function serializer(settings: ICSpellConfigFile, next: SerializerNext): string { + if (!(settings instanceof CSpellConfigFilePackageJson)) return next(settings); + return settings.serialize(); +} + +export const serializerPackageJson: SerializerMiddleware = { deserialize: deserializer, serialize: serializer }; diff --git a/packages/cspell-config-lib/src/deserializers/util.test.ts b/packages/cspell-config-lib/src/serializers/util.test.ts similarity index 100% rename from packages/cspell-config-lib/src/deserializers/util.test.ts rename to packages/cspell-config-lib/src/serializers/util.test.ts diff --git a/packages/cspell-config-lib/src/deserializers/util.ts b/packages/cspell-config-lib/src/serializers/util.ts similarity index 100% rename from packages/cspell-config-lib/src/deserializers/util.ts rename to packages/cspell-config-lib/src/serializers/util.ts From 79c2b7cde4f5a0cd063ab2dc6ac11bcbc2a1f160 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Thu, 16 Nov 2023 10:54:16 +0100 Subject: [PATCH 5/9] improve coverage --- packages/cspell-config-lib/package.json | 2 +- .../src/CSpellConfigFileReaderWriter.test.ts | 26 +++++++++++++++++++ packages/cspell-config-lib/src/IO.ts | 2 -- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/cspell-config-lib/package.json b/packages/cspell-config-lib/package.json index 46c264e1678..dee4aeac688 100644 --- a/packages/cspell-config-lib/package.json +++ b/packages/cspell-config-lib/package.json @@ -30,7 +30,7 @@ "watch": "tsc -p . -w", "clean": "shx rm -rf dist temp coverage \"*.tsbuildInfo\"", "clean-build": "pnpm run clean && pnpm run build", - "coverage": "vitest --coverage", + "coverage": "vitest run --coverage", "test-watch": "vitest", "test": "vitest run" }, diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts index 87a1faf8b5c..3f255126faf 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts @@ -4,6 +4,8 @@ import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter import type { IO } from './IO.js'; import { defaultDeserializers } from './serializers/index.js'; import { json } from './test-helpers/util.js'; +import { CSpellSettings } from '@cspell/cspell-types'; +import { CSpellConfigFile } from './CSpellConfigFile.js'; const oc = expect.objectContaining; @@ -46,4 +48,28 @@ describe('CSpellConfigFileReaderWriter', () => { await expect(rw.writeConfig(cf)).resolves.toBeUndefined(); expect(io.writeFile).toHaveBeenCalledWith(new URL(uri), content); }); + + test('Fail to serialize', () => { + const io: IO = { + readFile: vi.fn(() => Promise.resolve('')), + writeFile: vi.fn(() => Promise.resolve()), + }; + + const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); + const cf = new Cfg(new URL('file:///cspell.js'), {}); + expect(() => rw.writeConfig(cf)).toThrow('Unable to serialize config file: "file:///cspell.js"'); + }); }); + +class Cfg extends CSpellConfigFile { + constructor( + public readonly url: URL, + public readonly settings: CSpellSettings = {}, + ) { + super(url); + } + + addWords(_words: string[]): this { + return this; + } +} diff --git a/packages/cspell-config-lib/src/IO.ts b/packages/cspell-config-lib/src/IO.ts index 854211618b5..a164dc316ee 100644 --- a/packages/cspell-config-lib/src/IO.ts +++ b/packages/cspell-config-lib/src/IO.ts @@ -2,5 +2,3 @@ export interface IO { readFile(url: URL): Promise; writeFile(url: URL, content: string): Promise; } - -import.meta.resolve; From cd301a71dd284e6dd109e8d724844187a90da253 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Thu, 16 Nov 2023 11:49:34 +0100 Subject: [PATCH 6/9] lint --- .eslintrc.js | 1 + .gitignore | 1 + packages/cspell-config-lib/package.json | 5 +---- .../src/CSpellConfigFileReaderWriter.test.ts | 4 ++-- .../cspell-config-lib/src/serializers/cspellYaml.test.ts | 2 +- packages/cspell-config-lib/src/test-helpers/util.ts | 2 +- pnpm-lock.yaml | 7 ------- vitest.config.mts | 2 ++ 8 files changed, 9 insertions(+), 15 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1921f65a22a..8482551b191 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,6 +20,7 @@ const config = { ignorePatterns: [ '**/[Ss]amples/**', // cspell:disable-line '**/[Tt]emp/**', + '**/.temp/**', '**/*.d.ts', '**/*.d.cts', '**/*.d.mts', diff --git a/.gitignore b/.gitignore index 3fb8588a978..f19e80a0245 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ out # And temp files temp +.temp tmp *.log diff --git a/packages/cspell-config-lib/package.json b/packages/cspell-config-lib/package.json index dee4aeac688..d72874a746d 100644 --- a/packages/cspell-config-lib/package.json +++ b/packages/cspell-config-lib/package.json @@ -49,8 +49,5 @@ "comment-json": "^4.2.3", "yaml": "^1.10.2" }, - "devDependencies": { - "@types/jest": "^29.5.8", - "jest": "^29.7.0" - } + "devDependencies": {} } diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts index 3f255126faf..d7980a756c4 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts @@ -1,11 +1,11 @@ +import type { CSpellSettings } from '@cspell/cspell-types'; import { describe, expect, test, vi } from 'vitest'; +import { CSpellConfigFile } from './CSpellConfigFile.js'; import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter.js'; import type { IO } from './IO.js'; import { defaultDeserializers } from './serializers/index.js'; import { json } from './test-helpers/util.js'; -import { CSpellSettings } from '@cspell/cspell-types'; -import { CSpellConfigFile } from './CSpellConfigFile.js'; const oc = expect.objectContaining; diff --git a/packages/cspell-config-lib/src/serializers/cspellYaml.test.ts b/packages/cspell-config-lib/src/serializers/cspellYaml.test.ts index 30693c34ee2..c0411138138 100644 --- a/packages/cspell-config-lib/src/serializers/cspellYaml.test.ts +++ b/packages/cspell-config-lib/src/serializers/cspellYaml.test.ts @@ -4,8 +4,8 @@ import { pathToFileURL } from 'node:url'; import { describe, expect, test, vi } from 'vitest'; import { stringify } from 'yaml'; -import { defaultNextDeserializer, defaultNextSerializer } from '../defaultNext.js'; import { CSpellConfigFileYaml } from '../CSpellConfigFileYaml.js'; +import { defaultNextDeserializer } from '../defaultNext.js'; import { serializerCSpellYaml } from './cspellYaml.js'; const oc = expect.objectContaining; diff --git a/packages/cspell-config-lib/src/test-helpers/util.ts b/packages/cspell-config-lib/src/test-helpers/util.ts index 13bab5992f1..aae03fd71ba 100644 --- a/packages/cspell-config-lib/src/test-helpers/util.ts +++ b/packages/cspell-config-lib/src/test-helpers/util.ts @@ -8,7 +8,7 @@ export function json(obj: unknown, indent: string | number = 2): string { export function tempPath(file: string): string { const testState = expect.getState(); - return path.join(__dirname, '../../temp', testState.currentTestName || 'test', file); + return path.join(__dirname, '../../.temp', testState.currentTestName || 'test', file); } export async function createPathForFile(file: string): Promise { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c63ad4d954f..0ba6a9987c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -446,13 +446,6 @@ importers: yaml: specifier: ^1.10.2 version: 1.10.2 - devDependencies: - '@types/jest': - specifier: ^29.5.8 - version: 29.5.8 - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@18.18.9) packages/cspell-dictionary: dependencies: diff --git a/vitest.config.mts b/vitest.config.mts index ee016263270..c2d9f3c20d7 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -2,7 +2,9 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { + // exclude: ['temp', 'node_modules', 'dist'], // reporters: 'verbose', + watchExclude: ['**/node_modules/**', '**/dist/**', '**/.temp/**', '**/temp/**', '**/coverage/**'], coverage: { // enabled: true, provider: 'istanbul', From c37d98c584bd989a2de54246fa41a63c5897a5d3 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Thu, 16 Nov 2023 13:23:42 +0100 Subject: [PATCH 7/9] Use TextFileRef --- .../src/CSpellConfigFileReaderWriter.test.ts | 21 ++++++++++--------- .../src/CSpellConfigFileReaderWriter.ts | 12 ++++++----- packages/cspell-config-lib/src/IO.ts | 6 ++++-- packages/cspell-config-lib/src/TextFile.ts | 4 ++++ .../src/createReaderWriter.ts | 11 ++++++---- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts index d7980a756c4..ff8d1c939c0 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.test.ts @@ -15,7 +15,7 @@ describe('CSpellConfigFileReaderWriter', () => { ${'file:///package.json'} | ${json({ name: 'name' })} | ${oc({ url: new URL('file:///package.json'), settings: {} })} `('readConfig', async ({ uri, content, expected }) => { const io: IO = { - readFile: vi.fn(() => content), + readFile: vi.fn((url) => Promise.resolve({ url, content })), writeFile: vi.fn(), }; const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); @@ -27,7 +27,7 @@ describe('CSpellConfigFileReaderWriter', () => { ${'file:///cspell.js'} | ${''} | ${new Error('Unable to parse config file: "file:///cspell.js"')} `('fail readConfig', async ({ uri, content, expected }) => { const io: IO = { - readFile: vi.fn(() => content), + readFile: vi.fn((url) => Promise.resolve({ url, content })), writeFile: vi.fn(), }; const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); @@ -39,25 +39,26 @@ describe('CSpellConfigFileReaderWriter', () => { ${'file:///cspell.json'} | ${'{}\n'} `('writeConfig', async ({ uri, content }) => { const io: IO = { - readFile: vi.fn(() => content), - writeFile: vi.fn(() => Promise.resolve()), + readFile: vi.fn((url) => Promise.resolve({ url, content })), + writeFile: vi.fn((ref) => Promise.resolve(ref)), }; const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); const cf = await rw.readConfig(uri); - await expect(rw.writeConfig(cf)).resolves.toBeUndefined(); - expect(io.writeFile).toHaveBeenCalledWith(new URL(uri), content); + const url = new URL(uri); + await expect(rw.writeConfig(cf)).resolves.toEqual({ url }); + expect(io.writeFile).toHaveBeenCalledWith({ url, content }); }); - test('Fail to serialize', () => { + test('Fail to serialize', async () => { const io: IO = { - readFile: vi.fn(() => Promise.resolve('')), - writeFile: vi.fn(() => Promise.resolve()), + readFile: vi.fn((url) => Promise.resolve({ url, content: '' })), + writeFile: vi.fn((ref) => Promise.resolve(ref)), }; const rw = new CSpellConfigFileReaderWriterImpl(io, defaultDeserializers); const cf = new Cfg(new URL('file:///cspell.js'), {}); - expect(() => rw.writeConfig(cf)).toThrow('Unable to serialize config file: "file:///cspell.js"'); + await expect(rw.writeConfig(cf)).rejects.toThrowError('Unable to serialize config file: "file:///cspell.js"'); }); }); diff --git a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts index 79289b701b2..7a7626ab9ba 100644 --- a/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts +++ b/packages/cspell-config-lib/src/CSpellConfigFileReaderWriter.ts @@ -2,13 +2,14 @@ import type { ICSpellConfigFile } from './CSpellConfigFile.js'; import { defaultNextDeserializer, defaultNextSerializer } from './defaultNext.js'; import type { IO } from './IO.js'; import type { DeserializerNext, DeserializerParams, SerializerMiddleware, SerializerNext } from './Serializer.js'; +import type { TextFileRef } from './TextFile.js'; import { toURL } from './util/toURL.js'; export interface CSpellConfigFileReaderWriter { readonly io: IO; readonly middleware: SerializerMiddleware[]; readConfig(uri: URL | string): Promise; - writeConfig(configFile: ICSpellConfigFile): Promise; + writeConfig(configFile: ICSpellConfigFile): Promise; } export class CSpellConfigFileReaderWriterImpl implements CSpellConfigFileReaderWriter { @@ -19,11 +20,11 @@ export class CSpellConfigFileReaderWriterImpl implements CSpellConfigFileReaderW async readConfig(uri: URL | string): Promise { const url = toURL(uri); - const content = await this.io.readFile(url); + const file = await this.io.readFile(url); let next: DeserializerNext = defaultNextDeserializer; - const desContent: DeserializerParams = { url, content }; + const desContent: DeserializerParams = file; for (const des of [...this.middleware].reverse()) { next = curryDeserialize(des, next); @@ -42,9 +43,10 @@ export class CSpellConfigFileReaderWriterImpl implements CSpellConfigFileReaderW return next(configFile); } - writeConfig(configFile: ICSpellConfigFile): Promise { + async writeConfig(configFile: ICSpellConfigFile): Promise { const content = this.serialize(configFile); - return this.io.writeFile(configFile.url, content); + await this.io.writeFile({ url: configFile.url, content }); + return { url: configFile.url }; } } diff --git a/packages/cspell-config-lib/src/IO.ts b/packages/cspell-config-lib/src/IO.ts index a164dc316ee..41b5e4048e3 100644 --- a/packages/cspell-config-lib/src/IO.ts +++ b/packages/cspell-config-lib/src/IO.ts @@ -1,4 +1,6 @@ +import type { TextFile, TextFileRef } from './TextFile.js'; + export interface IO { - readFile(url: URL): Promise; - writeFile(url: URL, content: string): Promise; + readFile(url: URL): Promise; + writeFile(file: TextFile): Promise; } diff --git a/packages/cspell-config-lib/src/TextFile.ts b/packages/cspell-config-lib/src/TextFile.ts index 7a42ee331d3..9c71388483b 100644 --- a/packages/cspell-config-lib/src/TextFile.ts +++ b/packages/cspell-config-lib/src/TextFile.ts @@ -1,3 +1,7 @@ +export interface TextFileRef { + url: URL; +} + export interface TextFile { url: URL; content: string; diff --git a/packages/cspell-config-lib/src/createReaderWriter.ts b/packages/cspell-config-lib/src/createReaderWriter.ts index 801da7555dc..e2b697332e0 100644 --- a/packages/cspell-config-lib/src/createReaderWriter.ts +++ b/packages/cspell-config-lib/src/createReaderWriter.ts @@ -5,6 +5,7 @@ import { CSpellConfigFileReaderWriterImpl } from './CSpellConfigFileReaderWriter import type { IO } from './IO.js'; import type { SerializerMiddleware } from './Serializer.js'; import { defaultDeserializers } from './serializers/index.js'; +import type { TextFile, TextFileRef } from './TextFile.js'; const defaultIO: IO = { readFile, @@ -18,10 +19,12 @@ export function createReaderWriter( return new CSpellConfigFileReaderWriterImpl(io, deserializers.concat(defaultDeserializers)); } -function readFile(url: URL): Promise { - return fs.readFile(url, 'utf-8'); +async function readFile(url: URL): Promise { + const content = await fs.readFile(url, 'utf-8'); + return { url, content }; } -function writeFile(url: URL, content: string): Promise { - return fs.writeFile(url, content); +async function writeFile(file: TextFile): Promise { + await fs.writeFile(file.url, file.content); + return { url: file.url }; } From 2af144e96c0be68c9a629c87f91ba4eed6c22ce6 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Thu, 16 Nov 2023 13:27:02 +0100 Subject: [PATCH 8/9] Update app.test.ts.snap --- packages/cspell-gitignore/src/__snapshots__/app.test.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cspell-gitignore/src/__snapshots__/app.test.ts.snap b/packages/cspell-gitignore/src/__snapshots__/app.test.ts.snap index e4a3b9d87aa..632f982abdf 100644 --- a/packages/cspell-gitignore/src/__snapshots__/app.test.ts.snap +++ b/packages/cspell-gitignore/src/__snapshots__/app.test.ts.snap @@ -25,7 +25,7 @@ exports[`app > app.run [ ' ' ] 1`] = `""`; exports[`app > app.run [ ' ' ] 2`] = `"Missing files"`; -exports[`app > app.run [ '../node_modules' ] 1`] = `".gitignore:49:node_modules/ ../node_modules"`; +exports[`app > app.run [ '../node_modules' ] 1`] = `".gitignore:50:node_modules/ ../node_modules"`; exports[`app > app.run [ '../node_modules' ] 2`] = `""`; From df1550012ca0f9a55bb22938ee01253120ab97ec Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Thu, 16 Nov 2023 13:51:49 +0100 Subject: [PATCH 9/9] Update util.ts --- packages/cspell-config-lib/src/test-helpers/util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cspell-config-lib/src/test-helpers/util.ts b/packages/cspell-config-lib/src/test-helpers/util.ts index aae03fd71ba..bfeb9ff3881 100644 --- a/packages/cspell-config-lib/src/test-helpers/util.ts +++ b/packages/cspell-config-lib/src/test-helpers/util.ts @@ -8,7 +8,7 @@ export function json(obj: unknown, indent: string | number = 2): string { export function tempPath(file: string): string { const testState = expect.getState(); - return path.join(__dirname, '../../.temp', testState.currentTestName || 'test', file); + return path.join(__dirname, '../../.temp', testState.currentTestName?.replace(/[^a-z./-]/gi, '_') || 'test', file); } export async function createPathForFile(file: string): Promise {