Skip to content

Commit

Permalink
fix: Use exactOptionalPropertyTypes (#2493)
Browse files Browse the repository at this point in the history
* fix: Use `exactOptionalPropertyTypes`
  • Loading branch information
Jason3S committed Feb 19, 2022
1 parent cf8c305 commit ffde5ac
Show file tree
Hide file tree
Showing 25 changed files with 192 additions and 131 deletions.
31 changes: 23 additions & 8 deletions packages/cspell-lib/api/api.d.ts
@@ -1,5 +1,5 @@
/// <reference types="node" />
import { Glob, CSpellSettingsWithSourceTrace, ReplaceMap, DictionaryInformation, DictionaryDefinitionPreferred, DictionaryDefinitionAugmented, DictionaryDefinitionCustom, TextOffset, TextDocumentOffset, PnPSettings, ImportFileRef, CSpellUserSettings, LocaleId, CSpellSettings } from '@cspell/cspell-types';
import { Glob, CSpellSettingsWithSourceTrace, ReplaceMap, DictionaryInformation, DictionaryDefinitionPreferred, DictionaryDefinitionAugmented, DictionaryDefinitionCustom, TextOffset, TextDocumentOffset, PnPSettings as PnPSettings$1, ImportFileRef, CSpellUserSettings, LocaleId, CSpellSettings } from '@cspell/cspell-types';
export * from '@cspell/cspell-types';
import { CompoundWordsMethod, SuggestionResult, SuggestionCollector, WeightMap } from 'cspell-trie-lib';
export { CompoundWordsMethod, SuggestionCollector, SuggestionResult } from 'cspell-trie-lib';
Expand Down Expand Up @@ -208,6 +208,19 @@ declare class SpellingDictionaryCollection implements SpellingDictionary {
private _isNoSuggestWord;
}

/**
* The keys of an object where the values cannot be undefined.
*/
declare type OptionalKeys<T> = Exclude<{
[P in keyof T]: T[P] extends Exclude<T[P], undefined> ? never : P;
}[keyof T], undefined>;
/**
* Allow undefined in optional fields
*/
declare type OptionalOrUndefined<T> = {
[P in keyof T]: P extends OptionalKeys<T> ? T[P] | undefined : T[P];
};

declare const SymbolCSpellSettingsInternal: unique symbol;
interface CSpellSettingsInternal extends Omit<CSpellSettingsWithSourceTrace, 'dictionaryDefinitions'> {
[SymbolCSpellSettingsInternal]: true;
Expand Down Expand Up @@ -361,6 +374,7 @@ declare type LoaderResult = URI | undefined;

declare type CSpellSettingsWST$1 = CSpellSettingsWithSourceTrace;
declare type CSpellSettingsI$1 = CSpellSettingsInternal;
declare type PnPSettings = OptionalOrUndefined<PnPSettings$1>;
declare const sectionCSpell = "cSpell";
declare const defaultFileName = "cspell.json";
declare const defaultConfigFilenames: readonly string[];
Expand Down Expand Up @@ -395,18 +409,19 @@ interface ImportFileRefWithError$1 extends ImportFileRef {
declare function extractImportErrors(settings: CSpellSettingsWST$1): ImportFileRefWithError$1[];

declare type CSpellSettingsWST = CSpellSettingsWithSourceTrace;
declare type CSpellSettingsWSTO = OptionalOrUndefined<CSpellSettingsWithSourceTrace>;
declare type CSpellSettingsI = CSpellSettingsInternal;
declare const currentSettingsFileVersion = "0.2";
declare const ENV_CSPELL_GLOB_ROOT = "CSPELL_GLOB_ROOT";
declare function mergeSettings(left: CSpellSettingsWST | CSpellSettingsI, ...settings: (CSpellSettingsWST | CSpellSettingsI)[]): CSpellSettingsI;
declare function mergeInDocSettings(left: CSpellSettingsWST, right: CSpellSettingsWST): CSpellSettingsWST;
declare function calcOverrideSettings(settings: CSpellSettingsWST, filename: string): CSpellSettingsI;
declare function mergeSettings(left: CSpellSettingsWSTO | CSpellSettingsI, ...settings: (CSpellSettingsWSTO | CSpellSettingsI)[]): CSpellSettingsI;
declare function mergeInDocSettings(left: CSpellSettingsWSTO, right: CSpellSettingsWSTO): CSpellSettingsWST;
declare function calcOverrideSettings(settings: CSpellSettingsWSTO, filename: string): CSpellSettingsI;
/**
*
* @param settings - settings to finalize
* @returns settings where all globs and file paths have been resolved.
*/
declare function finalizeSettings(settings: CSpellSettingsWST | CSpellSettingsI): CSpellSettingsI;
declare function finalizeSettings(settings: CSpellSettingsWSTO | CSpellSettingsI): CSpellSettingsI;
/**
* @param filename - filename
* @param globs - globs
Expand All @@ -419,20 +434,20 @@ declare function checkFilenameMatchesGlob(filename: string, globs: Glob | Glob[]
* Return a list of Setting Sources used to create this Setting.
* @param settings the settings to search
*/
declare function getSources(settings: CSpellSettingsWST): CSpellSettingsWST[];
declare function getSources(settings: CSpellSettingsWSTO): CSpellSettingsWSTO[];
interface ImportFileRefWithError extends ImportFileRef {
error: Error;
}
interface ConfigurationDependencies {
configFiles: string[];
dictionaryFiles: string[];
}
declare function extractDependencies(settings: CSpellSettingsWST | CSpellSettingsI): ConfigurationDependencies;
declare function extractDependencies(settings: CSpellSettingsWSTO | CSpellSettingsI): ConfigurationDependencies;

declare function getDefaultSettings(): CSpellSettingsInternal;

declare class ImportError extends Error {
readonly cause?: Error;
readonly cause: Error | undefined;
constructor(msg: string, cause?: Error | unknown);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/cspell-lib/cspell.config.json
Expand Up @@ -17,6 +17,6 @@
],
"allowCompoundWords": false,
"dictionaryDefinitions": [],
"ignoreWords": [],
"ignoreWords": ["CSpellSettingsWSTO"],
"import": ["../../cspell.json"]
}
15 changes: 11 additions & 4 deletions packages/cspell-lib/src/Models/CSpellSettingsInternalDef.ts
Expand Up @@ -5,6 +5,8 @@ import {
DictionaryDefinitionPreferred,
} from '@cspell/cspell-types';
import { WeightMap } from 'cspell-trie-lib';
import { OptionalOrUndefined } from '../util/types';
import { clean } from '../util/util';

export const SymbolCSpellSettingsInternal = Symbol('CSpellSettingsInternal');

Expand All @@ -31,15 +33,20 @@ export interface DictionaryDefinitionInternalWithSource extends DictionaryDefini
readonly __source: string;
}

export function createCSpellSettingsInternal(parts: Partial<CSpellSettingsInternal> = {}): CSpellSettingsInternal {
return {
export function createCSpellSettingsInternal(
parts: OptionalOrUndefined<Partial<CSpellSettingsInternal>> = {}
): CSpellSettingsInternal {
return clean({
...parts,
[SymbolCSpellSettingsInternal]: true,
};
});
}

export function isCSpellSettingsInternal(
cs: CSpellSettingsInternal | CSpellSettingsWithSourceTrace
cs:
| CSpellSettingsInternal
| CSpellSettingsWithSourceTrace
| OptionalOrUndefined<CSpellSettingsInternal | CSpellSettingsWithSourceTrace>
): cs is CSpellSettingsInternal {
return !!(<CSpellSettingsInternal>cs)[SymbolCSpellSettingsInternal];
}
49 changes: 27 additions & 22 deletions packages/cspell-lib/src/Settings/CSpellSettingsServer.ts
Expand Up @@ -13,11 +13,13 @@ import {
CSpellSettingsInternal,
isCSpellSettingsInternal,
} from '../Models/CSpellSettingsInternalDef';
import { OptionalOrUndefined } from '../util/types';
import * as util from '../util/util';
import { calcDictionaryDefsToLoad, mapDictDefsToInternal } from './DictionarySettings';
import { resolvePatterns } from './patterns';

type CSpellSettingsWST = CSpellSettingsWithSourceTrace;
type CSpellSettingsWSTO = OptionalOrUndefined<CSpellSettingsWithSourceTrace>;
type CSpellSettingsI = CSpellSettingsInternal;

export const configSettingsFileVersion0_1 = '0.1';
Expand Down Expand Up @@ -104,8 +106,8 @@ function replaceIfNotEmpty<T>(left: Array<T> = [], right: Array<T> = []) {
}

export function mergeSettings(
left: CSpellSettingsWST | CSpellSettingsI,
...settings: (CSpellSettingsWST | CSpellSettingsI)[]
left: CSpellSettingsWSTO | CSpellSettingsI,
...settings: (CSpellSettingsWSTO | CSpellSettingsI)[]
): CSpellSettingsI {
const rawSettings = settings.reduce<CSpellSettingsI>(merge, toInternalSettings(left));
return util.clean(rawSettings);
Expand All @@ -116,7 +118,10 @@ function isEmpty(obj: Object) {
return Object.keys(obj).length === 0 && obj.constructor === Object;
}

function merge(left: CSpellSettingsWST | CSpellSettingsI, right: CSpellSettingsWST | CSpellSettingsI): CSpellSettingsI {
function merge(
left: CSpellSettingsWSTO | CSpellSettingsI,
right: CSpellSettingsWSTO | CSpellSettingsI
): CSpellSettingsI {
const _left = toInternalSettings(left);
const _right = toInternalSettings(right);
if (left === right) {
Expand Down Expand Up @@ -196,7 +201,7 @@ function versionBasedMergeList<T>(
* @param left - setting on the left side of a merge
* @param right - setting on the right side of a merge
*/
function isLeftAncestorOfRight(left: CSpellSettingsWST, right: CSpellSettingsWST): boolean {
function isLeftAncestorOfRight(left: CSpellSettingsWSTO, right: CSpellSettingsWSTO): boolean {
return hasAncestor(right, left, 0);
}

Expand All @@ -206,11 +211,11 @@ function isLeftAncestorOfRight(left: CSpellSettingsWST, right: CSpellSettingsWST
* @param left - setting on the left side of a merge
* @param right - setting on the right side of a merge
*/
function doesLeftHaveRightAncestor(left: CSpellSettingsWST, right: CSpellSettingsWST): boolean {
function doesLeftHaveRightAncestor(left: CSpellSettingsWSTO, right: CSpellSettingsWSTO): boolean {
return hasAncestor(left, right, 1);
}

function hasAncestor(s: CSpellSettingsWST, ancestor: CSpellSettingsWST, side: number): boolean {
function hasAncestor(s: CSpellSettingsWSTO, ancestor: CSpellSettingsWSTO, side: number): boolean {
const sources = s.source?.sources;
if (!sources) return false;
// calc the first or last index of the source array.
Expand All @@ -219,12 +224,12 @@ function hasAncestor(s: CSpellSettingsWST, ancestor: CSpellSettingsWST, side: nu
return src === ancestor || (src && hasAncestor(src, ancestor, side)) || false;
}

export function mergeInDocSettings(left: CSpellSettingsWST, right: CSpellSettingsWST): CSpellSettingsWST {
export function mergeInDocSettings(left: CSpellSettingsWSTO, right: CSpellSettingsWSTO): CSpellSettingsWST {
const merged = {
...mergeSettings(left, right),
includeRegExpList: mergeListUnique(left.includeRegExpList, right.includeRegExpList),
};
return merged;
return util.clean(merged);
}

/**
Expand All @@ -243,7 +248,7 @@ function takeRightOtherwiseLeft<T>(left: T[] | undefined, right: T[] | undefined
return left || right;
}

export function calcOverrideSettings(settings: CSpellSettingsWST, filename: string): CSpellSettingsI {
export function calcOverrideSettings(settings: CSpellSettingsWSTO, filename: string): CSpellSettingsI {
const _settings = toInternalSettings(settings);
const overrides = _settings.overrides || [];

Expand All @@ -258,7 +263,7 @@ export function calcOverrideSettings(settings: CSpellSettingsWST, filename: stri
* @param settings - settings to finalize
* @returns settings where all globs and file paths have been resolved.
*/
export function finalizeSettings(settings: CSpellSettingsWST | CSpellSettingsI): CSpellSettingsI {
export function finalizeSettings(settings: CSpellSettingsWSTO | CSpellSettingsI): CSpellSettingsI {
return _finalizeSettings(toInternalSettings(settings));
}

Expand All @@ -278,9 +283,9 @@ function _finalizeSettings(settings: CSpellSettingsI): CSpellSettingsI {
}

export function toInternalSettings(settings: undefined): undefined;
export function toInternalSettings(settings: CSpellSettingsI | CSpellSettingsWST): CSpellSettingsI;
export function toInternalSettings(settings?: CSpellSettingsI | CSpellSettingsWST): CSpellSettingsI | undefined;
export function toInternalSettings(settings?: CSpellSettingsI | CSpellSettingsWST): CSpellSettingsI | undefined {
export function toInternalSettings(settings: CSpellSettingsI | CSpellSettingsWSTO): CSpellSettingsI;
export function toInternalSettings(settings?: CSpellSettingsI | CSpellSettingsWSTO): CSpellSettingsI | undefined;
export function toInternalSettings(settings?: CSpellSettingsI | CSpellSettingsWSTO): CSpellSettingsI | undefined {
if (settings === undefined) return undefined;
if (isCSpellSettingsInternal(settings)) return settings;

Expand Down Expand Up @@ -310,12 +315,12 @@ export function checkFilenameMatchesGlob(filename: string, globs: Glob | Glob[])
return m.match(filename);
}

function mergeSources(left: CSpellSettingsWST, right: CSpellSettingsWST): Source {
function mergeSources(left: CSpellSettingsWSTO, right: CSpellSettingsWSTO): Source {
const { source: a = { name: 'left' } } = left;
const { source: b = { name: 'right' } } = right;
return {
name: [left.name || a.name, right.name || b.name].join('|'),
sources: [left, right],
sources: [left as CSpellSettingsWithSourceTrace, right as CSpellSettingsWithSourceTrace],
};
}

Expand All @@ -333,11 +338,11 @@ function max<T>(a: T | undefined, b: T | undefined): T | undefined {
* Return a list of Setting Sources used to create this Setting.
* @param settings the settings to search
*/
export function getSources(settings: CSpellSettingsWST): CSpellSettingsWST[] {
const visited = new Set<CSpellSettingsWST>();
const sources: CSpellSettingsWST[] = [];
export function getSources(settings: CSpellSettingsWSTO): CSpellSettingsWSTO[] {
const visited = new Set<CSpellSettingsWSTO>();
const sources: CSpellSettingsWSTO[] = [];

function _walkSourcesTree(settings: CSpellSettingsWST | undefined): void {
function _walkSourcesTree(settings: CSpellSettingsWSTO | undefined): void {
if (!settings || visited.has(settings)) return;
visited.add(settings);
if (!settings.source?.sources?.length) {
Expand All @@ -352,9 +357,9 @@ export function getSources(settings: CSpellSettingsWST): CSpellSettingsWST[] {
return sources;
}

type Imports = CSpellSettingsWST['__imports'];
type Imports = CSpellSettingsWSTO['__imports'];

function mergeImportRefs(left: CSpellSettingsWST, right: CSpellSettingsWST = {}): Imports {
function mergeImportRefs(left: CSpellSettingsWSTO, right: CSpellSettingsWSTO = {}): Imports {
const imports = new Map(left.__imports || []);
if (left.__importRef) {
imports.set(left.__importRef.filename, left.__importRef);
Expand All @@ -378,7 +383,7 @@ export interface ConfigurationDependencies {
dictionaryFiles: string[];
}

export function extractDependencies(settings: CSpellSettingsWST | CSpellSettingsI): ConfigurationDependencies {
export function extractDependencies(settings: CSpellSettingsWSTO | CSpellSettingsI): ConfigurationDependencies {
const settingsI = toInternalSettings(settings);
const configFiles = [...(mergeImportRefs(settingsI) || [])].map(([filename]) => filename);
const dictionaryFiles = calcDictionaryDefsToLoad(settingsI).map((dict) => dict.path);
Expand Down
6 changes: 5 additions & 1 deletion packages/cspell-lib/src/Settings/DefaultSettings.ts
Expand Up @@ -136,7 +136,11 @@ const getSettings = (function () {
if (!settings) {
const jsonSettings = readSettings(defaultConfigFile);
settings = mergeSettings(_defaultSettings, jsonSettings);
settings.name = jsonSettings.name;
if (jsonSettings.name !== undefined) {
settings.name = jsonSettings.name;
} else {
delete settings.name;
}
}
return settings;
};
Expand Down
30 changes: 12 additions & 18 deletions packages/cspell-lib/src/Settings/DictionarySettings.ts
Expand Up @@ -19,6 +19,7 @@ import { createDictionaryReferenceCollection } from './DictionaryReferenceCollec
import { mapDictionaryInformationToWeightMap, WeightMap } from 'cspell-trie-lib';
import { DictionaryInformation } from '@cspell/cspell-types';
import { RequireOptional, UnionFields } from '../util/types';
import { clean } from '../util/util';

export type DefMapArrayItem = [string, DictionaryDefinitionInternal];

Expand Down Expand Up @@ -116,19 +117,19 @@ type DictDef = Partial<
UnionFields<UnionFields<DictionaryDefinition, DictionaryDefinitionAugmented>, DictionaryDefinitionCustom>
>;

class _DictionaryDefinitionInternalWithSource implements RequireOptional<DictionaryDefinitionInternalWithSource> {
class _DictionaryDefinitionInternalWithSource implements DictionaryDefinitionInternalWithSource {
private _weightMap: WeightMap | undefined;
readonly name: string;
readonly path: string;
readonly addWords: boolean | undefined;
readonly description: string | undefined;
readonly dictionaryInformation: DictionaryInformation | undefined;
readonly type: DictionaryFileTypes | undefined;
readonly file: undefined;
readonly repMap: ReplaceMap | undefined;
readonly useCompounds: boolean | undefined;
readonly noSuggest: boolean | undefined;
readonly scope: CustomDictionaryScope | CustomDictionaryScope[] | undefined;
readonly addWords?: boolean;
readonly description?: string;
readonly dictionaryInformation?: DictionaryInformation;
readonly type?: DictionaryFileTypes;
readonly file?: undefined;
readonly repMap?: ReplaceMap;
readonly useCompounds?: boolean;
readonly noSuggest?: boolean;
readonly scope?: CustomDictionaryScope | CustomDictionaryScope[];
constructor(def: DictionaryDefinition, readonly __source: string) {
// this bit of assignment is to have the compiler help use if any new fields are added.
const defAll: DictDef = def;
Expand Down Expand Up @@ -164,17 +165,10 @@ class _DictionaryDefinitionInternalWithSource implements RequireOptional<Diction
useCompounds,
};

Object.assign(this, clean(ddi));
this.name = ddi.name;
this.file = ddi.file;
this.path = ddi.path;
this.addWords = ddi.addWords;
this.description = ddi.description;
this.dictionaryInformation = ddi.dictionaryInformation;
this.type = ddi.type;
this.repMap = ddi.repMap;
this.noSuggest = ddi.noSuggest;
this.scope = ddi.scope;
this.useCompounds = ddi.useCompounds;
this._weightMap = this.dictionaryInformation
? mapDictionaryInformationToWeightMap(this.dictionaryInformation)
: undefined;
Expand Down
2 changes: 1 addition & 1 deletion packages/cspell-lib/src/Settings/ImportError.ts
@@ -1,7 +1,7 @@
import { isError } from '../util/errors';

export class ImportError extends Error {
readonly cause?: Error;
readonly cause: Error | undefined;
constructor(msg: string, cause?: Error | unknown) {
super(msg);
this.cause = isError(cause) ? cause : undefined;
Expand Down
3 changes: 2 additions & 1 deletion packages/cspell-lib/src/Settings/InDocSettings.ts
@@ -1,6 +1,7 @@
import type { CSpellUserSettings } from '@cspell/cspell-types';
import { genSequence, Sequence } from 'gensequence';
import * as Text from '../util/text';
import { clean } from '../util/util';
import { mergeInDocSettings } from './CSpellSettingsServer';

// cspell:ignore gimuy
Expand Down Expand Up @@ -70,7 +71,7 @@ function parseLocale(match: string): CSpellUserSettings {

function parseIgnoreWords(match: string): CSpellUserSettings {
const wordsSetting = parseWords(match);
return { id: 'in-doc-ignore', ignoreWords: wordsSetting.words };
return clean({ id: 'in-doc-ignore', ignoreWords: wordsSetting.words });
}

function parseRegEx(match: string): string[] {
Expand Down

0 comments on commit ffde5ac

Please sign in to comment.