@herb-tools/config 0.8.9 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{src/config-schema.js → config-schema.js} +9 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/{src/config.js → config.js} +73 -83
- package/dist/config.js.map +1 -0
- package/dist/herb-config.cjs +92 -94
- package/dist/herb-config.cjs.map +1 -1
- package/dist/herb-config.esm.js +93 -95
- package/dist/herb-config.esm.js.map +1 -1
- package/dist/index.js.map +1 -0
- package/dist/{src/merge.js → merge.js} +1 -1
- package/dist/merge.js.map +1 -0
- package/dist/types/config-schema.d.ts +19 -0
- package/dist/types/config.d.ts +16 -6
- package/dist/{src/vscode.js → vscode.js} +1 -1
- package/dist/vscode.js.map +1 -0
- package/package.json +3 -3
- package/src/config-schema.ts +11 -0
- package/src/config-template.yml +7 -1
- package/src/config.ts +90 -87
- package/src/merge.ts +1 -1
- package/src/vscode.ts +1 -1
- package/dist/package.json +0 -49
- package/dist/src/config-schema.js.map +0 -1
- package/dist/src/config.js.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/merge.js.map +0 -1
- package/dist/src/vscode.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/types/src/config-schema.d.ts +0 -102
- package/dist/types/src/config.d.ts +0 -365
- package/dist/types/src/index.d.ts +0 -5
- package/dist/types/src/merge.d.ts +0 -11
- package/dist/types/src/vscode.d.ts +0 -13
- /package/dist/{src/index.js → index.js} +0 -0
package/dist/herb-config.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path, { join } from 'path';
|
|
2
2
|
import { promises, existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
3
|
-
import { parseDocument, stringify, isMap
|
|
3
|
+
import { parse as parse$1, parseDocument, stringify, isMap } from 'yaml';
|
|
4
4
|
import picomatch from 'picomatch';
|
|
5
5
|
import { glob } from 'tinyglobby';
|
|
6
6
|
|
|
@@ -1177,7 +1177,7 @@ class Doc {
|
|
|
1177
1177
|
const version$1 = {
|
|
1178
1178
|
major: 4,
|
|
1179
1179
|
minor: 3,
|
|
1180
|
-
patch:
|
|
1180
|
+
patch: 6,
|
|
1181
1181
|
};
|
|
1182
1182
|
|
|
1183
1183
|
const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => {
|
|
@@ -2198,11 +2198,9 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
|
|
|
2198
2198
|
if (keyResult instanceof Promise) {
|
|
2199
2199
|
throw new Error("Async schemas not supported in object keys currently");
|
|
2200
2200
|
}
|
|
2201
|
-
// Numeric string fallback: if key
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
keyResult.issues.length &&
|
|
2205
|
-
keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number");
|
|
2201
|
+
// Numeric string fallback: if key is a numeric string and failed, retry with Number(key)
|
|
2202
|
+
// This handles z.number(), z.literal([1, 2, 3]), and unions containing numeric literals
|
|
2203
|
+
const checkNumericKey = typeof key === "string" && number$1.test(key) && keyResult.issues.length;
|
|
2206
2204
|
if (checkNumericKey) {
|
|
2207
2205
|
const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
|
|
2208
2206
|
if (retryResult instanceof Promise) {
|
|
@@ -3370,7 +3368,7 @@ function finalize(ctx, schema) {
|
|
|
3370
3368
|
}
|
|
3371
3369
|
}
|
|
3372
3370
|
// When ref was extracted to $defs, remove properties that match the definition
|
|
3373
|
-
if (refSchema.$ref) {
|
|
3371
|
+
if (refSchema.$ref && refSeen.def) {
|
|
3374
3372
|
for (const key in schema) {
|
|
3375
3373
|
if (key === "$ref" || key === "allOf")
|
|
3376
3374
|
continue;
|
|
@@ -4800,9 +4798,18 @@ const FormatterConfigSchema = object({
|
|
|
4800
4798
|
maxLineLength: number().int().positive().optional().describe("Maximum line length before wrapping"),
|
|
4801
4799
|
rewriter: RewriterConfigSchema.describe("Rewriter configuration for pre and post-format transformations"),
|
|
4802
4800
|
}).strict().optional();
|
|
4801
|
+
const ValidatorsConfigSchema = object({
|
|
4802
|
+
security: boolean().optional().describe("Enable or disable the security validator (default: true)"),
|
|
4803
|
+
nesting: boolean().optional().describe("Enable or disable the nesting validator (default: true)"),
|
|
4804
|
+
accessibility: boolean().optional().describe("Enable or disable the accessibility validator (default: true)"),
|
|
4805
|
+
}).strict().optional();
|
|
4806
|
+
const EngineConfigSchema = object({
|
|
4807
|
+
validators: ValidatorsConfigSchema.describe("Per-validator enable/disable configuration"),
|
|
4808
|
+
}).strict().optional();
|
|
4803
4809
|
const HerbConfigSchema = object({
|
|
4804
4810
|
version: string().describe("Configuration file version"),
|
|
4805
4811
|
files: FilesConfigSchema.describe("Top-level file configuration"),
|
|
4812
|
+
engine: EngineConfigSchema.describe("Engine configuration"),
|
|
4806
4813
|
linter: LinterConfigSchema,
|
|
4807
4814
|
formatter: FormatterConfigSchema,
|
|
4808
4815
|
}).strict();
|
|
@@ -4826,7 +4833,7 @@ function deepMerge(target, source) {
|
|
|
4826
4833
|
continue;
|
|
4827
4834
|
}
|
|
4828
4835
|
if (Array.isArray(sourceValue)) {
|
|
4829
|
-
if (key === 'include' && Array.isArray(targetValue)) {
|
|
4836
|
+
if ((key === 'include' || key === 'exclude') && Array.isArray(targetValue)) {
|
|
4830
4837
|
output[key] = [...targetValue, ...sourceValue];
|
|
4831
4838
|
}
|
|
4832
4839
|
else {
|
|
@@ -4844,13 +4851,16 @@ function deepMerge(target, source) {
|
|
|
4844
4851
|
return output;
|
|
4845
4852
|
}
|
|
4846
4853
|
|
|
4847
|
-
var version = "0.
|
|
4854
|
+
var version = "0.9.0";
|
|
4848
4855
|
var packageJson = {
|
|
4849
4856
|
version: version};
|
|
4850
4857
|
|
|
4851
|
-
var configTemplate = "# This file configures Herb for your project and team.\n# Settings here take precedence over individual editor preferences.\n#\n# Herb is a suite of tools for HTML+ERB templates including:\n# - Linter: Validates templates and enforces best practices\n# - Formatter: Auto-formats templates with intelligent indentation\n# - Language Server: Provides IDE support (VS Code, Zed, Neovim, etc.)\n#\n# Website: https://herb-tools.dev\n# Configuration: https://herb-tools.dev/configuration\n# GitHub Repo: https://github.com/marcoroth/herb\n#\n\nversion: 0.
|
|
4858
|
+
var configTemplate = "# This file configures Herb for your project and team.\n# Settings here take precedence over individual editor preferences.\n#\n# Herb is a suite of tools for HTML+ERB templates including:\n# - Linter: Validates templates and enforces best practices\n# - Formatter: Auto-formats templates with intelligent indentation\n# - Language Server: Provides IDE support (VS Code, Zed, Neovim, etc.)\n#\n# Website: https://herb-tools.dev\n# Configuration: https://herb-tools.dev/configuration\n# GitHub Repo: https://github.com/marcoroth/herb\n#\n\nversion: 0.9.0\n\n# files:\n# # Additional patterns beyond the defaults (**.html, **.rhtml, **.html.erb, etc.)\n# include:\n# - '**/*.xml.erb'\n# - 'custom/**/*.html'\n#\n# # Patterns to exclude (can exclude defaults too)\n# exclude:\n# - 'public/**/*'\n# - 'tmp/**/*'\n\n# engine:\n# validators:\n# security: true # default: true\n# nesting: true # default: true\n# accessibility: true # default: true\n\nlinter:\n enabled: true\n\n # # Exit with error code when diagnostics of this severity or higher are present\n # # Valid values: error (default), warning, info, hint\n # failLevel: warning\n\n # # Additional patterns beyond the defaults for linting\n # include:\n # - '**/*.xml.erb'\n #\n # # Patterns to exclude from linting\n # exclude:\n # - 'app/views/admin/**/*'\n\n # rules:\n # erb-no-extra-newline:\n # enabled: false\n #\n # # Rules can have 'include', 'only', and 'exclude' patterns\n # some-rule:\n # # Additional patterns to check (additive, ignored when 'only' is present)\n # include:\n # - 'app/components/**/*'\n # # Don't apply this rule to files matching these patterns\n # exclude:\n # - 'app/views/admin/**/*'\n #\n # another-rule:\n # # Only apply this rule to files matching these patterns (overrides all 'include')\n # only:\n # - 'app/views/**/*'\n # # Exclude still applies even with 'only'\n # exclude:\n # - 'app/views/admin/**/*'\n\nformatter:\n enabled: false\n indentWidth: 2\n maxLineLength: 80\n\n # # Additional patterns beyond the defaults for formatting\n # include:\n # - '**/*.xml.erb'\n #\n # # Patterns to exclude from formatting\n # exclude:\n # - 'app/views/admin/**/*'\n\n # # Rewriters modify templates during formatting\n # rewriter:\n # # Pre-format rewriters (modify AST before formatting)\n # pre:\n # - tailwind-class-sorter\n # # Post-format rewriters (modify formatted output string)\n # post: []\n";
|
|
4859
|
+
|
|
4860
|
+
var defaultsYaml = "files:\n include:\n - \"**/*.herb\"\n - \"**/*.html.erb\"\n - \"**/*.html.herb\"\n - \"**/*.html\"\n - \"**/*.html+*.erb\"\n - \"**/*.rhtml\"\n - \"**/*.turbo_stream.erb\"\n\n exclude:\n - \"coverage/**/*\"\n - \"log/**/*\"\n - \"node_modules/**/*\"\n - \"storage/**/*\"\n - \"tmp/**/*\"\n - \"vendor/**/*\"\n\nengine:\n validators:\n security: true\n nesting: true\n accessibility: true\n\nlinter:\n enabled: true\n rules: {}\n\nformatter:\n enabled: false\n indentWidth: 2\n maxLineLength: 80\n";
|
|
4852
4861
|
|
|
4853
4862
|
const DEFAULT_VERSION = packageJson.version;
|
|
4863
|
+
const PARSED_DEFAULTS = parse$1(defaultsYaml);
|
|
4854
4864
|
class Config {
|
|
4855
4865
|
static configPath = ".herb.yml";
|
|
4856
4866
|
static PROJECT_INDICATORS = [
|
|
@@ -4924,8 +4934,9 @@ class Config {
|
|
|
4924
4934
|
}
|
|
4925
4935
|
/**
|
|
4926
4936
|
* Get the files configuration for a specific tool.
|
|
4927
|
-
*
|
|
4928
|
-
* Include
|
|
4937
|
+
* Both include and exclude patterns are additive:
|
|
4938
|
+
* - Include: defaults + files.include + tool.include
|
|
4939
|
+
* - Exclude: defaults + files.exclude + tool.exclude
|
|
4929
4940
|
* @param tool - The tool to get files config for ('linter' or 'formatter')
|
|
4930
4941
|
* @returns The merged files configuration
|
|
4931
4942
|
*/
|
|
@@ -4935,7 +4946,9 @@ class Config {
|
|
|
4935
4946
|
const topLevelInclude = topLevelFiles.include || [];
|
|
4936
4947
|
const toolInclude = toolConfig?.include || [];
|
|
4937
4948
|
const include = [...topLevelInclude, ...toolInclude];
|
|
4938
|
-
const
|
|
4949
|
+
const topLevelExclude = topLevelFiles.exclude || [];
|
|
4950
|
+
const toolExclude = toolConfig?.exclude || [];
|
|
4951
|
+
const exclude = [...topLevelExclude, ...toolExclude];
|
|
4939
4952
|
return {
|
|
4940
4953
|
include,
|
|
4941
4954
|
exclude
|
|
@@ -5019,7 +5032,7 @@ class Config {
|
|
|
5019
5032
|
}
|
|
5020
5033
|
/**
|
|
5021
5034
|
* Check if a tool (linter or formatter) is enabled for a specific file path.
|
|
5022
|
-
* Respects
|
|
5035
|
+
* Respects the tool's enabled state and all exclude patterns (defaults + files.exclude + tool.exclude).
|
|
5023
5036
|
* @param filePath - The file path to check
|
|
5024
5037
|
* @param tool - The tool to check ('linter' or 'formatter')
|
|
5025
5038
|
* @returns true if the tool is enabled for this path
|
|
@@ -5029,8 +5042,8 @@ class Config {
|
|
|
5029
5042
|
if (!isEnabled) {
|
|
5030
5043
|
return false;
|
|
5031
5044
|
}
|
|
5032
|
-
const
|
|
5033
|
-
const excludePatterns =
|
|
5045
|
+
const filesConfig = this.getFilesConfigForTool(tool);
|
|
5046
|
+
const excludePatterns = filesConfig.exclude || [];
|
|
5034
5047
|
return !this.isPathExcluded(filePath, excludePatterns);
|
|
5035
5048
|
}
|
|
5036
5049
|
/**
|
|
@@ -5053,11 +5066,11 @@ class Config {
|
|
|
5053
5066
|
}
|
|
5054
5067
|
/**
|
|
5055
5068
|
* Check if a specific rule is enabled for a specific file path.
|
|
5056
|
-
* Respects
|
|
5069
|
+
* Respects rule.enabled, rule.include, rule.only, and rule.exclude patterns.
|
|
5057
5070
|
*
|
|
5058
5071
|
* Pattern precedence:
|
|
5059
|
-
* - If rule.only
|
|
5060
|
-
* - If rule.only
|
|
5072
|
+
* - If rule.only or rule.include matches the path: bypasses parent excludes (linter.exclude, files.exclude, defaults)
|
|
5073
|
+
* - If no rule.only/include patterns or path doesn't match: respects all parent excludes
|
|
5061
5074
|
* - rule.exclude is always applied regardless of 'only' or 'include'
|
|
5062
5075
|
*
|
|
5063
5076
|
* @param ruleName - The name of the rule to check
|
|
@@ -5065,7 +5078,7 @@ class Config {
|
|
|
5065
5078
|
* @returns true if the rule is enabled for this path
|
|
5066
5079
|
*/
|
|
5067
5080
|
isRuleEnabledForPath(ruleName, filePath) {
|
|
5068
|
-
if (!this.
|
|
5081
|
+
if (!this.isLinterEnabled) {
|
|
5069
5082
|
return false;
|
|
5070
5083
|
}
|
|
5071
5084
|
if (this.isRuleDisabled(ruleName)) {
|
|
@@ -5075,13 +5088,25 @@ class Config {
|
|
|
5075
5088
|
const ruleOnlyPatterns = ruleConfig?.only || [];
|
|
5076
5089
|
const ruleIncludePatterns = ruleConfig?.include || [];
|
|
5077
5090
|
const ruleExcludePatterns = ruleConfig?.exclude || [];
|
|
5091
|
+
let bypassParentExcludes = false;
|
|
5078
5092
|
if (ruleOnlyPatterns.length > 0) {
|
|
5079
|
-
if (
|
|
5093
|
+
if (this.isPathIncluded(filePath, ruleOnlyPatterns)) {
|
|
5094
|
+
bypassParentExcludes = true;
|
|
5095
|
+
}
|
|
5096
|
+
else {
|
|
5080
5097
|
return false;
|
|
5081
5098
|
}
|
|
5082
5099
|
}
|
|
5083
5100
|
else if (ruleIncludePatterns.length > 0) {
|
|
5084
|
-
if (
|
|
5101
|
+
if (this.isPathIncluded(filePath, ruleIncludePatterns)) {
|
|
5102
|
+
bypassParentExcludes = true;
|
|
5103
|
+
}
|
|
5104
|
+
else {
|
|
5105
|
+
return false;
|
|
5106
|
+
}
|
|
5107
|
+
}
|
|
5108
|
+
if (!bypassParentExcludes) {
|
|
5109
|
+
if (!this.isLinterEnabledForPath(filePath)) {
|
|
5085
5110
|
return false;
|
|
5086
5111
|
}
|
|
5087
5112
|
}
|
|
@@ -5418,7 +5443,7 @@ class Config {
|
|
|
5418
5443
|
result.push('');
|
|
5419
5444
|
}
|
|
5420
5445
|
}
|
|
5421
|
-
if (/^ [a-z][\w-]*:/.test(line) && prevLine &&
|
|
5446
|
+
if (/^ [a-z][\w-]*:/.test(line) && prevLine && prevLine.startsWith(' ')) {
|
|
5422
5447
|
result.push('');
|
|
5423
5448
|
}
|
|
5424
5449
|
result.push(line);
|
|
@@ -5572,7 +5597,7 @@ class Config {
|
|
|
5572
5597
|
console.error(`✓ Created default configuration at ${configPath}`);
|
|
5573
5598
|
}
|
|
5574
5599
|
}
|
|
5575
|
-
catch (
|
|
5600
|
+
catch (_error) {
|
|
5576
5601
|
if (!silent) {
|
|
5577
5602
|
console.error(`⚠ Could not create config file at ${configPath}, using defaults in-memory`);
|
|
5578
5603
|
}
|
|
@@ -5661,62 +5686,57 @@ class Config {
|
|
|
5661
5686
|
* Read, parse, and validate config file
|
|
5662
5687
|
*/
|
|
5663
5688
|
static async readAndValidateConfig(configPath, projectRoot, version, exitOnError = false) {
|
|
5689
|
+
const content = await promises.readFile(configPath, "utf8");
|
|
5690
|
+
let parsed;
|
|
5664
5691
|
try {
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5692
|
+
parsed = parse$1(content);
|
|
5693
|
+
}
|
|
5694
|
+
catch (error) {
|
|
5695
|
+
if (exitOnError) {
|
|
5696
|
+
console.error(`\n✗ Invalid YAML syntax in ${configPath}`);
|
|
5697
|
+
if (error instanceof Error) {
|
|
5698
|
+
console.error(` ${error.message}\n`);
|
|
5699
|
+
}
|
|
5700
|
+
process.exit(1);
|
|
5669
5701
|
}
|
|
5670
|
-
|
|
5702
|
+
else {
|
|
5703
|
+
throw new Error(`Invalid YAML syntax in ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
5704
|
+
}
|
|
5705
|
+
}
|
|
5706
|
+
if (parsed === null || parsed === undefined) {
|
|
5707
|
+
parsed = {};
|
|
5708
|
+
}
|
|
5709
|
+
if (!parsed.version) {
|
|
5710
|
+
parsed.version = version;
|
|
5711
|
+
}
|
|
5712
|
+
try {
|
|
5713
|
+
HerbConfigSchema.parse(parsed);
|
|
5714
|
+
}
|
|
5715
|
+
catch (error) {
|
|
5716
|
+
if (error instanceof ZodError) {
|
|
5717
|
+
const validationError = fromZodError(error, {
|
|
5718
|
+
prefix: `Configuration errors in ${configPath}`,
|
|
5719
|
+
});
|
|
5671
5720
|
if (exitOnError) {
|
|
5672
|
-
console.error(`\n✗
|
|
5673
|
-
if (error instanceof Error) {
|
|
5674
|
-
console.error(` ${error.message}\n`);
|
|
5675
|
-
}
|
|
5721
|
+
console.error(`\n✗ ${validationError.toString()}\n`);
|
|
5676
5722
|
process.exit(1);
|
|
5677
5723
|
}
|
|
5678
5724
|
else {
|
|
5679
|
-
throw new Error(
|
|
5680
|
-
}
|
|
5681
|
-
}
|
|
5682
|
-
if (parsed === null || parsed === undefined) {
|
|
5683
|
-
parsed = {};
|
|
5684
|
-
}
|
|
5685
|
-
if (!parsed.version) {
|
|
5686
|
-
parsed.version = version;
|
|
5687
|
-
}
|
|
5688
|
-
try {
|
|
5689
|
-
HerbConfigSchema.parse(parsed);
|
|
5690
|
-
}
|
|
5691
|
-
catch (error) {
|
|
5692
|
-
if (error instanceof ZodError) {
|
|
5693
|
-
const validationError = fromZodError(error, {
|
|
5694
|
-
prefix: `Configuration errors in ${configPath}`,
|
|
5695
|
-
});
|
|
5696
|
-
if (exitOnError) {
|
|
5697
|
-
console.error(`\n✗ ${validationError.toString()}\n`);
|
|
5698
|
-
process.exit(1);
|
|
5699
|
-
}
|
|
5700
|
-
else {
|
|
5701
|
-
throw new Error(validationError.toString());
|
|
5702
|
-
}
|
|
5725
|
+
throw new Error(validationError.toString());
|
|
5703
5726
|
}
|
|
5704
|
-
throw error;
|
|
5705
|
-
}
|
|
5706
|
-
if (parsed.version && parsed.version !== version) {
|
|
5707
|
-
console.error(`\n⚠️ Configuration version mismatch in ${configPath}`);
|
|
5708
|
-
console.error(` Config version: ${parsed.version}`);
|
|
5709
|
-
console.error(` Current version: ${version}`);
|
|
5710
|
-
console.error(` Consider updating your .herb.yml file.\n`);
|
|
5711
5727
|
}
|
|
5712
|
-
const defaults = this.getDefaultConfig(version);
|
|
5713
|
-
const resolved = deepMerge(defaults, parsed);
|
|
5714
|
-
resolved.version = version;
|
|
5715
|
-
return new Config(projectRoot, resolved);
|
|
5716
|
-
}
|
|
5717
|
-
catch (error) {
|
|
5718
5728
|
throw error;
|
|
5719
5729
|
}
|
|
5730
|
+
if (parsed.version && parsed.version !== version) {
|
|
5731
|
+
console.error(`\n⚠️ Configuration version mismatch in ${configPath}`);
|
|
5732
|
+
console.error(` Config version: ${parsed.version}`);
|
|
5733
|
+
console.error(` Current version: ${version}`);
|
|
5734
|
+
console.error(` Consider updating your .herb.yml file.\n`);
|
|
5735
|
+
}
|
|
5736
|
+
const defaults = this.getDefaultConfig(version);
|
|
5737
|
+
const resolved = deepMerge(defaults, parsed);
|
|
5738
|
+
resolved.version = version;
|
|
5739
|
+
return new Config(projectRoot, resolved);
|
|
5720
5740
|
}
|
|
5721
5741
|
/**
|
|
5722
5742
|
* Get default configuration object
|
|
@@ -5724,29 +5744,7 @@ class Config {
|
|
|
5724
5744
|
static getDefaultConfig(version = DEFAULT_VERSION) {
|
|
5725
5745
|
return {
|
|
5726
5746
|
version,
|
|
5727
|
-
|
|
5728
|
-
include: [
|
|
5729
|
-
'**/*.html',
|
|
5730
|
-
'**/*.rhtml',
|
|
5731
|
-
'**/*.html.erb',
|
|
5732
|
-
'**/*.html+*.erb',
|
|
5733
|
-
'**/*.turbo_stream.erb'
|
|
5734
|
-
],
|
|
5735
|
-
exclude: [
|
|
5736
|
-
'node_modules/**/*',
|
|
5737
|
-
'vendor/bundle/**/*',
|
|
5738
|
-
'coverage/**/*',
|
|
5739
|
-
]
|
|
5740
|
-
},
|
|
5741
|
-
linter: {
|
|
5742
|
-
enabled: true,
|
|
5743
|
-
rules: {}
|
|
5744
|
-
},
|
|
5745
|
-
formatter: {
|
|
5746
|
-
enabled: false,
|
|
5747
|
-
indentWidth: 2,
|
|
5748
|
-
maxLineLength: 80
|
|
5749
|
-
}
|
|
5747
|
+
...PARSED_DEFAULTS
|
|
5750
5748
|
};
|
|
5751
5749
|
}
|
|
5752
5750
|
}
|
|
@@ -5786,7 +5784,7 @@ function readExtensionsJson(filePath) {
|
|
|
5786
5784
|
}
|
|
5787
5785
|
return parsed;
|
|
5788
5786
|
}
|
|
5789
|
-
catch (
|
|
5787
|
+
catch (_error) {
|
|
5790
5788
|
console.warn(`Warning: Could not parse ${filePath}, creating new file`);
|
|
5791
5789
|
return { recommendations: [] };
|
|
5792
5790
|
}
|