From e839990e94f639000bc926ae87187840fb17dee9 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Mon, 4 Dec 2023 15:08:48 +0100 Subject: [PATCH] fix: expose ConfigLoader API (#5032) --- packages/cspell-lib/api/api.d.ts | 47 +++++++++- packages/cspell-lib/src/lib-cjs/pkg-info.cts | 2 + .../configLoader/configLoader.test.ts | 2 +- .../Controller/configLoader/configLoader.ts | 86 ++++++++++++++++--- .../configLoader/defaultConfigLoader.ts | 4 +- .../Settings/Controller/configLoader/index.ts | 1 + .../Controller/configLoader/readSettings.ts | 1 - packages/cspell-lib/src/lib/Settings/index.ts | 2 + .../src/lib/__snapshots__/index.test.ts.snap | 2 + packages/cspell-lib/src/lib/index.ts | 2 + packages/cspell-lib/src/lib/util/url.test.ts | 2 +- packages/cspell-lib/src/lib/util/url.ts | 5 +- .../src/test-util/test.locations.cts | 20 ++--- 13 files changed, 146 insertions(+), 30 deletions(-) diff --git a/packages/cspell-lib/api/api.d.ts b/packages/cspell-lib/api/api.d.ts index 59f3bb704bad..fbb61652d5bc 100644 --- a/packages/cspell-lib/api/api.d.ts +++ b/packages/cspell-lib/api/api.d.ts @@ -3,9 +3,11 @@ import { Glob, CSpellSettingsWithSourceTrace, TextOffset, TextDocumentOffset, Ad export * from '@cspell/cspell-types'; import { WeightMap } from 'cspell-trie-lib'; export { CompoundWordsMethod } from 'cspell-trie-lib'; +import { CSpellConfigFile } from 'cspell-config-lib'; +import { CSpellIO } from 'cspell-io'; +export { asyncIterableToArray, readFileText as readFile, readFileTextSync as readFileSync, writeToFile, writeToFileIterable, writeToFileIterableP } from 'cspell-io'; import { SuggestOptions, SuggestionResult, CachingDictionary, SpellingDictionaryCollection } from 'cspell-dictionary'; export { SpellingDictionary, SpellingDictionaryCollection, SuggestOptions, SuggestionCollector, SuggestionResult, createSpellingDictionary, createCollection as createSpellingDictionaryCollection } from 'cspell-dictionary'; -export { asyncIterableToArray, readFileText as readFile, readFileTextSync as readFileSync, writeToFile, writeToFileIterable, writeToFileIterableP } from 'cspell-io'; type ExclusionFunction = (fileUri: string) => boolean; type FileExclusionFunction = (file: string) => boolean; @@ -412,7 +414,47 @@ type CSpellSettingsI = CSpellSettingsInternal; declare const sectionCSpell = "cSpell"; declare const defaultFileName = "cspell.json"; +interface IConfigLoader { + readSettingsAsync(filename: string | URL, relativeTo?: string | URL, pnpSettings?: PnPSettingsOptional): Promise; + /** + * Read a cspell configuration file. + * @param filenameOrURL - URL, relative path, absolute path, or package name. + * @param relativeTo - optional URL, defaults to `pathToFileURL('./')` + */ + readConfigFile(filenameOrURL: string | URL, relativeTo?: string | URL): Promise; + searchForConfigFileLocation(searchFrom: URL | string | undefined): Promise; + searchForConfigFile(searchFrom: URL | string | undefined): Promise; + /** + * This is an alias for `searchForConfigFile` and `mergeConfigFileWithImports`. + * @param searchFrom the directory / file URL to start searching from. + * @param pnpSettings - related to Using Yarn PNP. + * @returns the resulting settings + */ + searchForConfig(searchFrom: URL | string | undefined, pnpSettings?: PnPSettingsOptional): Promise; + getGlobalSettingsAsync(): Promise; + /** + * The loader caches configuration files for performance. This method clears the cache. + */ + clearCachedSettingsFiles(): void; + /** + * Resolve imports and merge. + * @param cfgFile - configuration file. + * @param pnpSettings - optional settings related to Using Yarn PNP. + */ + mergeConfigFileWithImports(cfgFile: CSpellConfigFile, pnpSettings?: PnPSettingsOptional | undefined): Promise; + /** + * Create an in memory CSpellConfigFile. + * @param filename - URL to the file. Used to resolve imports. + * @param settings - settings to use. + */ + createCSpellConfigFile(filename: URL | string, settings: CSpellUserSettings): CSpellConfigFile; + /** + * Unsubscribe from any events and dispose of any resources including caches. + */ + dispose(): void; +} declare function loadPnP(pnpSettings: PnPSettingsOptional, searchFrom: URL): Promise; +declare function createConfigLoader(cspellIO?: CSpellIO): IConfigLoader; declare const defaultConfigFilenames: readonly string[]; @@ -441,6 +483,7 @@ declare function getGlobalSettings(): CSpellSettingsI; */ declare function getGlobalSettingsAsync(): Promise; declare function getCachedFileSize(): number; +declare function getDefaultConfigLoader(): IConfigLoader; declare function readRawSettings(filename: string | URL, relativeTo?: string | URL): Promise; declare function extractImportErrors(settings: CSpellSettingsWST): ImportFileRefWithError[]; @@ -957,4 +1000,4 @@ interface PerfTimer { type TimeNowFn = () => number; declare function createPerfTimer(name: string, onEnd?: (elapsed: number, name: string) => void, timeNowFn?: TimeNowFn): PerfTimer; -export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError$1 as ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type PerfTimer, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCaches, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createPerfTimer, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, getDefaultSettings, getDictionary, getGlobalSettings, getGlobalSettingsAsync, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; +export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError$1 as ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type PerfTimer, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCaches, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createConfigLoader, createPerfTimer, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, getDefaultConfigLoader, getDefaultSettings, getDictionary, getGlobalSettings, getGlobalSettingsAsync, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; diff --git a/packages/cspell-lib/src/lib-cjs/pkg-info.cts b/packages/cspell-lib/src/lib-cjs/pkg-info.cts index 8243a5d832ca..b655ffb718d5 100644 --- a/packages/cspell-lib/src/lib-cjs/pkg-info.cts +++ b/packages/cspell-lib/src/lib-cjs/pkg-info.cts @@ -1 +1,3 @@ +// import { join } from 'path'; +// export const srcDirectory = join(__dirname, '/'); export const srcDirectory = __dirname; diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts index 63503de31ab3..1e59d1f22fe3 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts @@ -35,7 +35,7 @@ import { readSettingsFiles } from './readSettingsFiles.js'; const { validateRawConfigVersion } = __configLoader_testing__; -const rootCspellLib = pathPackageRoot; +const rootCspellLib = path.join(pathPackageRoot, '.'); const root = pathRepoRoot; const samplesDir = pathPackageSamples; const samplesSrc = path.join(samplesDir, 'src'); diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts index b16f2844929f..8a5edcb2323d 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts @@ -5,7 +5,7 @@ import { createReaderWriter, CSpellConfigFileInMemory } from 'cspell-config-lib' import type { CSpellIO } from 'cspell-io'; import { getDefaultCSpellIO } from 'cspell-io'; import * as path from 'path'; -import { fileURLToPath } from 'url'; +import { fileURLToPath, pathToFileURL } from 'url'; import { onClearCache } from '../../../events/index.js'; import { createCSpellSettingsInternal as csi } from '../../../Models/CSpellSettingsInternalDef.js'; @@ -78,7 +78,66 @@ interface CacheMergeConfigFileWithImports { result: Promise; } -export class ConfigLoader { +export interface IConfigLoader { + readSettingsAsync( + filename: string | URL, + relativeTo?: string | URL, + pnpSettings?: PnPSettingsOptional, + ): Promise; + + /** + * Read a cspell configuration file. + * @param filenameOrURL - URL, relative path, absolute path, or package name. + * @param relativeTo - optional URL, defaults to `pathToFileURL('./')` + */ + readConfigFile(filenameOrURL: string | URL, relativeTo?: string | URL): Promise; + + searchForConfigFileLocation(searchFrom: URL | string | undefined): Promise; + + searchForConfigFile(searchFrom: URL | string | undefined): Promise; + + /** + * This is an alias for `searchForConfigFile` and `mergeConfigFileWithImports`. + * @param searchFrom the directory / file URL to start searching from. + * @param pnpSettings - related to Using Yarn PNP. + * @returns the resulting settings + */ + searchForConfig( + searchFrom: URL | string | undefined, + pnpSettings?: PnPSettingsOptional, + ): Promise; + + getGlobalSettingsAsync(): Promise; + + /** + * The loader caches configuration files for performance. This method clears the cache. + */ + clearCachedSettingsFiles(): void; + + /** + * Resolve imports and merge. + * @param cfgFile - configuration file. + * @param pnpSettings - optional settings related to Using Yarn PNP. + */ + mergeConfigFileWithImports( + cfgFile: CSpellConfigFile, + pnpSettings?: PnPSettingsOptional | undefined, + ): Promise; + + /** + * Create an in memory CSpellConfigFile. + * @param filename - URL to the file. Used to resolve imports. + * @param settings - settings to use. + */ + createCSpellConfigFile(filename: URL | string, settings: CSpellUserSettings): CSpellConfigFile; + + /** + * Unsubscribe from any events and dispose of any resources including caches. + */ + dispose(): void; +} + +export class ConfigLoader implements IConfigLoader { public onReady: Promise; /** @@ -87,10 +146,7 @@ export class ConfigLoader { */ protected constructor(readonly cspellIO: CSpellIO) { this.cspellConfigFileReaderWriter = createReaderWriter(undefined, undefined, createIO(cspellIO)); - this.onReady = this.getGlobalSettingsAsync().then( - () => undefined, - (e) => logError(e), - ); + this.onReady = this.prefetchGlobalSettingsAsync(); this.subscribeToEvents(); } @@ -113,7 +169,8 @@ export class ConfigLoader { relativeTo?: string | URL, pnpSettings?: PnPSettingsOptional, ): Promise { - const ref = resolveFilename(filename, relativeTo || process.cwd()); + await this.onReady; + const ref = resolveFilename(filename, relativeTo || pathToFileURL('./')); const entry = this.importSettings(ref, pnpSettings || defaultPnPSettings, []); return entry.onReady; } @@ -122,7 +179,7 @@ export class ConfigLoader { filenameOrURL: string | URL, relativeTo?: string | URL, ): Promise { - const ref = resolveFilename(filenameOrURL.toString(), relativeTo || process.cwd()); + const ref = resolveFilename(filenameOrURL.toString(), relativeTo || pathToFileURL('./')); const url = this.cspellIO.toFileURL(ref.filename); const href = url.href; if (ref.error) return new ImportError(`Failed to read config file: "${ref.filename}"`, ref.error); @@ -172,7 +229,7 @@ export class ConfigLoader { } public getGlobalSettings(): CSpellSettingsI { - assert(this.globalSettings); + assert(this.globalSettings, 'Global settings not loaded'); return this.globalSettings; } @@ -194,6 +251,15 @@ export class ConfigLoader { this.cachedPendingConfigFile.clear(); this.cspellConfigFileReaderWriter.clearCachedFiles(); this.cachedMergedConfig = new WeakMap(); + this.prefetchGlobalSettingsAsync(); + } + + protected prefetchGlobalSettingsAsync(): Promise { + this.onReady = this.getGlobalSettingsAsync().then( + () => undefined, + (e) => logError(e), + ); + return this.onReady; } protected importSettings( @@ -495,7 +561,7 @@ function createConfigLoaderInternal(cspellIO?: CSpellIO) { return new ConfigLoaderInternal(cspellIO ?? getDefaultCSpellIO()); } -export function createConfigLoader(cspellIO?: CSpellIO): ConfigLoader { +export function createConfigLoader(cspellIO?: CSpellIO): IConfigLoader { return createConfigLoaderInternal(cspellIO); } diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/defaultConfigLoader.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/defaultConfigLoader.ts index 21ed573b93aa..a7f27d3abdb7 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/defaultConfigLoader.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/defaultConfigLoader.ts @@ -2,7 +2,7 @@ import type { CSpellConfigFile } from 'cspell-config-lib'; import { toError } from '../../../util/errors.js'; import { toFileUrl } from '../../../util/url.js'; -import type { ConfigLoader } from './configLoader.js'; +import type { IConfigLoader } from './configLoader.js'; import { getDefaultConfigLoaderInternal } from './configLoader.js'; import { configErrorToRawSettings, configToRawSettings } from './configToRawSettings.js'; import type { PnPSettingsOptional } from './PnPSettings.js'; @@ -66,7 +66,7 @@ export function clearCachedSettingsFiles(): void { return gcl().clearCachedSettingsFiles(); } -export function getDefaultConfigLoader(): ConfigLoader { +export function getDefaultConfigLoader(): IConfigLoader { return getDefaultConfigLoaderInternal(); } function cachedFiles() { diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/index.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/index.ts index 1625c14b78d4..bc52c532e7a0 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/index.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/index.ts @@ -10,6 +10,7 @@ export { defaultConfigFilenames } from './configLocations.js'; export { clearCachedSettingsFiles, getCachedFileSize, + getDefaultConfigLoader, getGlobalSettings, getGlobalSettingsAsync, loadConfig, diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettings.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettings.ts index 0fafecefd368..59a13ee3c260 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettings.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettings.ts @@ -33,7 +33,6 @@ export async function readSettings( pnpSettings?: PnPSettingsOptional, ): Promise { const loader = getDefaultConfigLoader(); - await loader.onReady; const relativeTo = typeof relativeToOrPnP === 'string' || relativeToOrPnP instanceof URL ? relativeToOrPnP : undefined; const pnp = pnpSettings diff --git a/packages/cspell-lib/src/lib/Settings/index.ts b/packages/cspell-lib/src/lib/Settings/index.ts index d2c9543654ed..4e9dd2def09c 100644 --- a/packages/cspell-lib/src/lib/Settings/index.ts +++ b/packages/cspell-lib/src/lib/Settings/index.ts @@ -3,10 +3,12 @@ export { checkFilenameMatchesGlob } from './checkFilenameMatchesGlob.js'; export { currentSettingsFileVersion, ENV_CSPELL_GLOB_ROOT } from './constants.js'; export { clearCachedSettingsFiles, + createConfigLoader, defaultConfigFilenames, defaultFileName, extractImportErrors, getCachedFileSize, + getDefaultConfigLoader, getGlobalSettings, getGlobalSettingsAsync, loadConfig, diff --git a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap index b4176c26a7c8..a985665c6e17 100644 --- a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap +++ b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap @@ -151,6 +151,7 @@ exports[`Validate the cspell API > Verify API exports 1`] = ` "clearCaches": [Function], "combineTextAndLanguageSettings": [Function], "constructSettingsForText": [Function], + "createConfigLoader": [Function], "createPerfTimer": [Function], "createSpellingDictionary": [Function], "createSpellingDictionaryCollection": [Function], @@ -218,6 +219,7 @@ exports[`Validate the cspell API > Verify API exports 1`] = ` "finalizeSettings": [Function], "getCachedFileSize": [Function], "getDefaultBundledSettingsAsync": [Function], + "getDefaultConfigLoader": [Function], "getDefaultSettings": [Function], "getDictionary": [Function], "getGlobalSettings": [Function], diff --git a/packages/cspell-lib/src/lib/index.ts b/packages/cspell-lib/src/lib/index.ts index 74d099e4c705..8de3ecc3a30e 100644 --- a/packages/cspell-lib/src/lib/index.ts +++ b/packages/cspell-lib/src/lib/index.ts @@ -18,6 +18,7 @@ export { calcOverrideSettings, checkFilenameMatchesGlob, type ConfigurationDependencies, + createConfigLoader, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, @@ -27,6 +28,7 @@ export { finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, + getDefaultConfigLoader, getDefaultSettings, getGlobalSettings, getGlobalSettingsAsync, diff --git a/packages/cspell-lib/src/lib/util/url.test.ts b/packages/cspell-lib/src/lib/util/url.test.ts index 81a9d939c6ed..c466e2d5ee29 100644 --- a/packages/cspell-lib/src/lib/util/url.test.ts +++ b/packages/cspell-lib/src/lib/util/url.test.ts @@ -103,7 +103,7 @@ describe('url', () => { describe('cwdURL', () => { test('should return the URL for the current working directory', () => { const result = cwdURL(); - expect(result.href).toBe(pathToFileURL(process.cwd() + '/').href); + expect(result.href).toBe(pathToFileURL('./').href); }); }); diff --git a/packages/cspell-lib/src/lib/util/url.ts b/packages/cspell-lib/src/lib/util/url.ts index d852d3f16675..c4bf372dd614 100644 --- a/packages/cspell-lib/src/lib/util/url.ts +++ b/packages/cspell-lib/src/lib/util/url.ts @@ -19,8 +19,7 @@ export function toFilePathOrHref(url: URL | string): string { * @returns URL for the source directory */ export function getSourceDirectoryUrl(): URL { - const base = pathToFileURL(srcDirectory); - const srcDirectoryURL = new URL(base.pathname + '/', base); + const srcDirectoryURL = pathToFileURL(path.join(srcDirectory, '/')); return srcDirectoryURL; } @@ -34,7 +33,7 @@ export function relativeTo(path: string, relativeTo?: URL | string): URL { } export function cwdURL(): URL { - return pathToFileURL(process.cwd() + '/'); + return pathToFileURL('./'); } export function resolveFileWithURL(file: string | URL, relativeToURL: URL): URL { diff --git a/packages/cspell-lib/src/test-util/test.locations.cts b/packages/cspell-lib/src/test-util/test.locations.cts index edd25f787d50..8773791a29a8 100644 --- a/packages/cspell-lib/src/test-util/test.locations.cts +++ b/packages/cspell-lib/src/test-util/test.locations.cts @@ -1,14 +1,14 @@ import * as path from 'path'; import { pathToFileURL } from 'url'; -export const pathPackageRoot = path.join(__dirname, '../..'); -export const pathRepoRoot = path.join(pathPackageRoot, '../..'); -export const pathPackageSamples = path.join(pathPackageRoot, 'samples'); -export const pathPackageFixtures = path.join(pathPackageRoot, 'fixtures'); -export const pathRepoTestFixtures = path.join(pathRepoRoot, 'test-fixtures'); +export const pathPackageRoot = path.join(__dirname, '../../'); +export const pathRepoRoot = path.join(pathPackageRoot, '../../'); +export const pathPackageSamples = path.join(pathPackageRoot, 'samples/'); +export const pathPackageFixtures = path.join(pathPackageRoot, 'fixtures/'); +export const pathRepoTestFixtures = path.join(pathRepoRoot, 'test-fixtures/'); -export const pathPackageRootURL = pathToFileURL(pathPackageRoot + '/'); -export const pathRepoRootURL = pathToFileURL(pathRepoRoot + '/'); -export const pathPackageSamplesURL = pathToFileURL(pathPackageSamples + '/'); -export const pathPackageFixturesURL = pathToFileURL(pathPackageFixtures + '/'); -export const pathRepoTestFixturesURL = pathToFileURL(pathRepoTestFixtures + '/'); +export const pathPackageRootURL = pathToFileURL(pathPackageRoot); +export const pathRepoRootURL = pathToFileURL(pathRepoRoot); +export const pathPackageSamplesURL = pathToFileURL(pathPackageSamples); +export const pathPackageFixturesURL = pathToFileURL(pathPackageFixtures); +export const pathRepoTestFixturesURL = pathToFileURL(pathRepoTestFixtures);