"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractImportErrors = exports.getSources = exports.checkFilenameMatchesGlob = exports.clearCachedFiles = exports.getCachedFileSize = exports.getGlobalSettings = exports.finalizeSettings = exports.calcOverrideSettings = exports.mergeInDocSettings = exports.mergeSettings = exports.readSettingsFiles = exports.readSettings = exports.defaultFileName = exports.sectionCSpell = void 0; const fs = __importStar(require("fs")); const json = __importStar(require("comment-json")); const path = __importStar(require("path")); const DictionarySettings_1 = require("./DictionarySettings"); const util = __importStar(require("../util/util")); const configstore_1 = __importDefault(require("configstore")); const minimatch_1 = __importDefault(require("minimatch")); const resolveFile_1 = require("../util/resolveFile"); const currentSettingsFileVersion = '0.1'; exports.sectionCSpell = 'cSpell'; const packageName = 'cspell'; exports.defaultFileName = 'cSpell.json'; const defaultSettings = { id: 'default', name: 'default', version: currentSettingsFileVersion, }; let globalSettings; const cachedFiles = new Map(); function readJsonFile(fileRef) { const { filename } = fileRef; let s = {}; try { s = json.parse(fs.readFileSync(filename).toString()); } catch (err) { fileRef.error = new Error(`Failed to read config file: "${filename}"`); } s.__importRef = fileRef; return s; } function normalizeSettings(settings, pathToSettings) { // Fix up dictionaryDefinitions const dictionaryDefinitions = DictionarySettings_1.normalizePathForDictDefs(settings.dictionaryDefinitions || [], pathToSettings); const languageSettings = (settings.languageSettings || []).map((langSetting) => ({ ...langSetting, dictionaryDefinitions: DictionarySettings_1.normalizePathForDictDefs(langSetting.dictionaryDefinitions || [], pathToSettings), })); const imports = typeof settings.import === 'string' ? [settings.import] : settings.import || []; const source = settings.source || { name: settings.name || settings.id || pathToSettings }; const fileSettings = { ...settings, dictionaryDefinitions, languageSettings }; if (!imports.length) { return fileSettings; } const importedSettings = imports .map((name) => resolveFilename(name, pathToSettings)) .map((ref) => ((ref.sources = [source]), ref)) .map((ref) => importSettings(ref)) .reduce((a, b) => mergeSettings(a, b)); const finalizeSettings = mergeSettings(importedSettings, fileSettings); finalizeSettings.name = settings.name || finalizeSettings.name || ''; finalizeSettings.id = settings.id || finalizeSettings.id || ''; return finalizeSettings; } function mergeSourceList(orig, append) { const collection = new Map(orig.map((s) => [s.name + (s.filename || ''), s])); for (const s of append || []) { const key = s.name + (s.filename || ''); if (!collection.has(key)) { collection.set(key, s); } } return [...collection.values()]; } function importSettings(fileRef, defaultValues = defaultSettings) { let { filename } = fileRef; filename = path.resolve(filename); const importRef = { ...fileRef, filename }; const cached = cachedFiles.get(filename); if (cached) { const cachedImportRef = cached.__importRef || importRef; cachedImportRef.sources = mergeSourceList(cachedImportRef.sources || [], importRef.sources); cached.__importRef = cachedImportRef; return cached; } const id = [path.basename(path.dirname(filename)), path.basename(filename)].join('/'); const finalizeSettings = { id }; cachedFiles.set(filename, finalizeSettings); // add an empty entry to prevent circular references. const settings = { ...defaultValues, id, ...readJsonFile(importRef) }; const pathToSettings = path.dirname(filename); Object.assign(finalizeSettings, normalizeSettings(settings, pathToSettings)); const finalizeSrc = { name: path.basename(filename), ...finalizeSettings.source }; finalizeSettings.source = { ...finalizeSrc, filename }; cachedFiles.set(filename, finalizeSettings); return finalizeSettings; } function readSettings(filename, defaultValues) { return importSettings({ filename }, defaultValues); } exports.readSettings = readSettings; function readSettingsFiles(filenames) { return filenames.map((filename) => readSettings(filename)).reduce((a, b) => mergeSettings(a, b), defaultSettings); } exports.readSettingsFiles = readSettingsFiles; /** * Merges two lists of strings and removes duplicates. Order is NOT preserved. */ function mergeList(left = [], right = []) { const setOfWords = new Set([...left, ...right]); return [...setOfWords.keys()]; } function tagLanguageSettings(tag, settings = []) { return settings.map((s) => ({ id: tag + '.' + (s.id || s.local || s.languageId), ...s, })); } function replaceIfNotEmpty(left = [], right = []) { const filtered = right.filter((a) => !!a); if (filtered.length) { return filtered; } return left; } function mergeSettings(left, ...settings) { const rawSettings = settings.reduce(merge, left); return util.clean(rawSettings); } exports.mergeSettings = mergeSettings; // eslint-disable-next-line @typescript-eslint/no-explicit-any function isEmpty(obj) { return Object.keys(obj).length === 0 && obj.constructor === Object; } function merge(left, right) { if (left === right) { return left; } if (isEmpty(right)) { return left; } if (isEmpty(left)) { return right; } if (hasLeftAncestor(right, left)) { return right; } if (hasRightAncestor(left, right)) { return left; } const leftId = left.id || left.languageId || ''; const rightId = right.id || right.languageId || ''; const includeRegExpList = takeRightThenLeft(left.includeRegExpList, right.includeRegExpList); const optionals = includeRegExpList.length ? { includeRegExpList } : {}; const settings = { ...left, ...right, ...optionals, id: [leftId, rightId].join('|'), name: [left.name || '', right.name || ''].join('|'), words: mergeList(left.words, right.words), userWords: mergeList(left.userWords, right.userWords), flagWords: mergeList(left.flagWords, right.flagWords), ignoreWords: mergeList(left.ignoreWords, right.ignoreWords), enabledLanguageIds: replaceIfNotEmpty(left.enabledLanguageIds, right.enabledLanguageIds), ignoreRegExpList: mergeList(left.ignoreRegExpList, right.ignoreRegExpList), patterns: mergeList(left.patterns, right.patterns), dictionaryDefinitions: mergeList(left.dictionaryDefinitions, right.dictionaryDefinitions), dictionaries: mergeList(left.dictionaries, right.dictionaries), languageSettings: mergeList(tagLanguageSettings(leftId, left.languageSettings), tagLanguageSettings(rightId, right.languageSettings)), enabled: right.enabled !== undefined ? right.enabled : left.enabled, source: mergeSources(left, right), __imports: mergeImportRefs(left, right), __importRef: undefined, }; return settings; } function hasLeftAncestor(s, left) { return hasAncestor(s, left, 0); } function hasRightAncestor(s, right) { return hasAncestor(s, right, 1); } function hasAncestor(s, ancestor, side) { if (s.source) { return ((s.source && s.source.sources && s.source.sources[side] && (s.source.sources[side] === ancestor || hasAncestor(s.source.sources[side], ancestor, side))) || false); } return false; } function mergeInDocSettings(left, right) { const merged = { ...mergeSettings(left, right), includeRegExpList: mergeList(left.includeRegExpList, right.includeRegExpList), }; return merged; } exports.mergeInDocSettings = mergeInDocSettings; function takeRightThenLeft(left = [], right = []) { if (right.length) { return right; } return left; } function calcOverrideSettings(settings, filename) { const overrides = settings.overrides || []; const result = overrides .filter((override) => checkFilenameMatchesGlob(filename, override.filename)) .reduce((settings, override) => mergeSettings(settings, override), settings); return result; } exports.calcOverrideSettings = calcOverrideSettings; function finalizeSettings(settings) { // apply patterns to any RegExpLists. const finalized = { ...settings, ignoreRegExpList: applyPatterns(settings.ignoreRegExpList, settings.patterns), includeRegExpList: applyPatterns(settings.includeRegExpList, settings.patterns), }; finalized.name = 'Finalized ' + (finalized.name || ''); finalized.source = { name: settings.name || 'src', sources: [settings] }; return finalized; } exports.finalizeSettings = finalizeSettings; function applyPatterns(regExpList = [], patternDefinitions = []) { const patternMap = new Map(patternDefinitions.map((def) => [def.name.toLowerCase(), def.pattern])); function* flatten(patterns) { for (const pattern of patterns) { if (Array.isArray(pattern)) { yield* flatten(pattern); } else { yield pattern; } } } const patternList = regExpList.map((p) => patternMap.get(p.toString().toLowerCase()) || p); return [...flatten(patternList)]; } function resolveFilename(filename, relativeTo) { const r = resolveFile_1.resolveFile(filename, relativeTo); return { filename: r.filename, error: r.found ? undefined : new Error(`Failed to resolve file: "${filename}"`), }; } function getGlobalSettings() { if (!globalSettings) { const globalConf = {}; try { const cfgStore = new configstore_1.default(packageName); Object.assign(globalConf, cfgStore.all); } catch (error) { console.log(error); } globalSettings = { id: 'global_config', ...normalizeSettings(globalConf || {}, __dirname), }; } return globalSettings; } exports.getGlobalSettings = getGlobalSettings; function getCachedFileSize() { return cachedFiles.size; } exports.getCachedFileSize = getCachedFileSize; function clearCachedFiles() { cachedFiles.clear(); } exports.clearCachedFiles = clearCachedFiles; function checkFilenameMatchesGlob(filename, globs) { if (typeof globs === 'string') { globs = [globs]; } const matches = globs.filter((g) => minimatch_1.default(filename, g, { matchBase: true })); return matches.length > 0; } exports.checkFilenameMatchesGlob = checkFilenameMatchesGlob; function mergeSources(left, right) { 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], }; } /** * Return a list of Setting Sources used to create this Setting. * @param settings settings to search */ function getSources(settings) { var _a, _b; if (!((_b = (_a = settings.source) === null || _a === void 0 ? void 0 : _a.sources) === null || _b === void 0 ? void 0 : _b.length)) { return [settings]; } const left = settings.source.sources[0]; const right = settings.source.sources[1]; return right ? getSources(left).concat(getSources(right)) : getSources(left); } exports.getSources = getSources; function mergeImportRefs(left, right) { var _a; const imports = new Map(left.__imports || []); if (left.__importRef) { imports.set(left.__importRef.filename, left.__importRef); } if (right.__importRef) { imports.set(right.__importRef.filename, right.__importRef); } const rightImports = ((_a = right.__imports) === null || _a === void 0 ? void 0 : _a.values()) || []; for (const ref of rightImports) { imports.set(ref.filename, ref); } return imports.size ? imports : undefined; } function isImportFileRefWithError(ref) { return !!ref.error; } function extractImportErrors(settings) { const imports = mergeImportRefs(settings, {}); return !imports ? [] : [...imports.values()].filter(isImportFileRefWithError); } exports.extractImportErrors = extractImportErrors; //# sourceMappingURL=CSpellSettingsServer.js.map