html-validate 8.26.0 → 8.27.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/dist/es/core.js CHANGED
@@ -2,7 +2,7 @@ import Ajv from 'ajv';
2
2
  import { e as entities$1, h as html5, b as bundledElements } from './elements.js';
3
3
  import betterAjvErrors from '@sidvind/better-ajv-errors';
4
4
  import { n as naturalJoin } from './utils/natural-join.js';
5
- import fs from 'fs';
5
+ import fs from 'node:fs';
6
6
  import kleur from 'kleur';
7
7
  import { stylish as stylish$1 } from '@html-validate/stylish';
8
8
  import semver from 'semver';
@@ -10562,10 +10562,6 @@ var configurationSchema = {
10562
10562
  properties: properties
10563
10563
  };
10564
10564
 
10565
- const TRANSFORMER_API = {
10566
- VERSION: 1
10567
- };
10568
-
10569
10565
  var defaultConfig = {};
10570
10566
 
10571
10567
  const config$5 = {
@@ -10772,6 +10768,99 @@ const presets = {
10772
10768
  "html-validate:a17y": config$5
10773
10769
  };
10774
10770
 
10771
+ function getNamedTransformerFromPlugin(name, plugins, pluginName, key) {
10772
+ const plugin = plugins.find((cur) => cur.name === pluginName);
10773
+ if (!plugin) {
10774
+ throw new ConfigError(`No plugin named "${pluginName}" has been loaded`);
10775
+ }
10776
+ if (!plugin.transformer) {
10777
+ throw new ConfigError(`Plugin does not expose any transformers`);
10778
+ }
10779
+ if (typeof plugin.transformer === "function") {
10780
+ throw new ConfigError(
10781
+ `Transformer "${name}" refers to named transformer but plugin exposes only unnamed, use "${pluginName}" instead.`
10782
+ );
10783
+ }
10784
+ const transformer = plugin.transformer[key];
10785
+ if (!transformer) {
10786
+ throw new ConfigError(`Plugin "${pluginName}" does not expose a transformer named "${key}".`);
10787
+ }
10788
+ return transformer;
10789
+ }
10790
+
10791
+ function getTransformerFromModule(resolvers, name) {
10792
+ return resolveTransformer(resolvers, name, { cache: true });
10793
+ }
10794
+
10795
+ function getUnnamedTransformerFromPlugin(name, plugin) {
10796
+ if (!plugin.transformer) {
10797
+ throw new ConfigError(`Plugin does not expose any transformers`);
10798
+ }
10799
+ if (typeof plugin.transformer !== "function") {
10800
+ if (plugin.transformer.default) {
10801
+ return plugin.transformer.default;
10802
+ }
10803
+ throw new ConfigError(
10804
+ `Transformer "${name}" refers to unnamed transformer but plugin exposes only named.`
10805
+ );
10806
+ }
10807
+ return plugin.transformer;
10808
+ }
10809
+
10810
+ const TRANSFORMER_API = {
10811
+ VERSION: 1
10812
+ };
10813
+
10814
+ function validateTransformer(transformer) {
10815
+ const version = transformer.api ?? 0;
10816
+ if (version !== TRANSFORMER_API.VERSION) {
10817
+ throw new ConfigError(
10818
+ `Transformer uses API version ${String(version)} but only version ${String(TRANSFORMER_API.VERSION)} is supported`
10819
+ );
10820
+ }
10821
+ }
10822
+ function loadTransformerFunction(resolvers, name, plugins) {
10823
+ const match = name.match(/(.*):(.*)/);
10824
+ if (match) {
10825
+ const [, pluginName, key] = match;
10826
+ const transformer2 = getNamedTransformerFromPlugin(name, plugins, pluginName, key);
10827
+ validateTransformer(transformer2);
10828
+ return transformer2;
10829
+ }
10830
+ const plugin = plugins.find((cur) => cur.name === name);
10831
+ if (plugin) {
10832
+ const transformer2 = getUnnamedTransformerFromPlugin(name, plugin);
10833
+ validateTransformer(transformer2);
10834
+ return transformer2;
10835
+ }
10836
+ const transformer = getTransformerFromModule(resolvers, name);
10837
+ validateTransformer(transformer);
10838
+ return transformer;
10839
+ }
10840
+ function getTransformerFunction(resolvers, name, plugins) {
10841
+ try {
10842
+ const transformer = loadTransformerFunction(resolvers, name, plugins);
10843
+ validateTransformer(transformer);
10844
+ return transformer;
10845
+ } catch (err) {
10846
+ if (err instanceof ConfigError) {
10847
+ throw new ConfigError(`Failed to load transformer "${name}": ${err.message}`, err);
10848
+ } else {
10849
+ throw new ConfigError(`Failed to load transformer "${name}"`, ensureError(err));
10850
+ }
10851
+ }
10852
+ }
10853
+ function getCachedTransformerFunction(cache, resolvers, name, plugins) {
10854
+ const cached = cache.get(name);
10855
+ if (cached) {
10856
+ return cached;
10857
+ } else {
10858
+ const transformer = getTransformerFunction(resolvers, name, plugins);
10859
+ cache.set(name, transformer);
10860
+ return transformer;
10861
+ }
10862
+ }
10863
+
10775
10864
  class ResolvedConfig {
10776
10865
  /**
10777
10866
  * @internal
@@ -10781,6 +10870,7 @@ class ResolvedConfig {
10781
10870
  this.plugins = plugins;
10782
10871
  this.rules = rules;
10783
10872
  this.transformers = transformers;
10873
+ this.cache = /* @__PURE__ */ new Map();
10784
10874
  this.original = original;
10785
10875
  }
10786
10876
  /**
@@ -10804,48 +10894,48 @@ class ResolvedConfig {
10804
10894
  *
10805
10895
  * When transforming zero or more new sources will be generated.
10806
10896
  *
10897
+ * @internal
10807
10898
  * @param source - Current source to transform.
10808
10899
  * @param filename - If set it is the filename used to match
10809
10900
  * transformer. Default is to use filename from source.
10810
10901
  * @returns A list of transformed sources ready for validation.
10811
10902
  */
10812
- transformSource(source, filename) {
10903
+ transformSource(resolvers, source, filename) {
10813
10904
  const transformer = this.findTransformer(filename ?? source.filename);
10814
10905
  const context = {
10815
10906
  hasChain: (filename2) => {
10816
10907
  return !!this.findTransformer(filename2);
10817
10908
  },
10818
10909
  chain: (source2, filename2) => {
10819
- return this.transformSource(source2, filename2);
10910
+ return this.transformSource(resolvers, source2, filename2);
10820
10911
  }
10821
10912
  };
10822
- if (transformer) {
10823
- try {
10824
- return Array.from(transformer.fn.call(context, source), (cur) => {
10825
- cur.transformedBy ??= [];
10826
- cur.transformedBy.push(transformer.name);
10827
- return cur;
10828
- });
10829
- } catch (err) {
10830
- const message = err instanceof Error ? err.message : String(err);
10831
- throw new NestedError(
10832
- `When transforming "${source.filename}": ${message}`,
10833
- ensureError(err)
10834
- );
10835
- }
10836
- } else {
10913
+ if (!transformer) {
10837
10914
  return [source];
10838
10915
  }
10916
+ const fn = getCachedTransformerFunction(this.cache, resolvers, transformer.name, this.plugins);
10917
+ try {
10918
+ const transformedSources = Array.from(fn.call(context, source));
10919
+ for (const source2 of transformedSources) {
10920
+ source2.transformedBy ??= [];
10921
+ source2.transformedBy.push(transformer.name);
10922
+ }
10923
+ return transformedSources;
10924
+ } catch (err) {
10925
+ const message = err instanceof Error ? err.message : String(err);
10926
+ throw new NestedError(`When transforming "${source.filename}": ${message}`, ensureError(err));
10927
+ }
10839
10928
  }
10840
10929
  /**
10841
10930
  * Wrapper around [[transformSource]] which reads a file before passing it
10842
10931
  * as-is to transformSource.
10843
10932
  *
10933
+ * @internal
10844
10934
  * @param filename - Filename to transform (according to configured
10845
10935
  * transformations)
10846
10936
  * @returns A list of transformed sources ready for validation.
10847
10937
  */
10848
- transformFilename(filename) {
10938
+ transformFilename(resolvers, filename) {
10849
10939
  const stdin = 0;
10850
10940
  const src = filename !== "/dev/stdin" ? filename : stdin;
10851
10941
  const data = fs.readFileSync(src, { encoding: "utf8" });
@@ -10857,10 +10947,12 @@ class ResolvedConfig {
10857
10947
  offset: 0,
10858
10948
  originalData: data
10859
10949
  };
10860
- return this.transformSource(source);
10950
+ return this.transformSource(resolvers, source);
10861
10951
  }
10862
10952
  /**
10863
10953
  * Returns true if a transformer matches given filename.
10954
+ *
10955
+ * @public
10864
10956
  */
10865
10957
  canTransform(filename) {
10866
10958
  const entry = this.findTransformer(filename);
@@ -10979,6 +11071,12 @@ function toArray(value) {
10979
11071
  return [value];
10980
11072
  }
10981
11073
  }
11074
+ function transformerEntries(transform) {
11075
+ return Object.entries(transform).map(([pattern, name]) => {
11076
+ const regex = new RegExp(pattern);
11077
+ return { pattern: regex, name };
11078
+ });
11079
+ }
10982
11080
  class Config {
10983
11081
  /**
10984
11082
  * @internal
@@ -10993,10 +11091,10 @@ class Config {
10993
11091
  };
10994
11092
  this.config = mergeInternal(initial, options);
10995
11093
  this.configurations = /* @__PURE__ */ new Map();
10996
- this.initialized = false;
10997
11094
  this.resolvers = toArray(resolvers);
10998
11095
  this.metaTable = null;
10999
11096
  this.plugins = [];
11097
+ this.transformers = transformerEntries(this.config.transform ?? {});
11000
11098
  }
11001
11099
  /**
11002
11100
  * Create a new blank configuration. See also `Config.defaultConfig()`.
@@ -11079,19 +11177,10 @@ class Config {
11079
11177
  return instance;
11080
11178
  }
11081
11179
  /**
11082
- * Initialize plugins, transforms etc.
11083
- *
11084
- * Must be called before trying to use config. Can safely be called multiple
11085
- * times.
11086
- *
11087
11180
  * @public
11181
+ * @deprecated Not needed any longer, this is a dummy noop method.
11088
11182
  */
11089
11183
  init() {
11090
- if (this.initialized) {
11091
- return;
11092
- }
11093
- this.transformers = this.precompileTransformers(this.config.transform ?? {});
11094
- this.initialized = true;
11095
11184
  }
11096
11185
  /**
11097
11186
  * Returns true if this configuration is marked as "root".
@@ -11204,6 +11293,14 @@ class Config {
11204
11293
  getPlugins() {
11205
11294
  return this.plugins;
11206
11295
  }
11296
+ /**
11297
+ * Get all configured transformers.
11298
+ *
11299
+ * @internal
11300
+ */
11301
+ getTransformers() {
11302
+ return this.transformers;
11303
+ }
11207
11304
  loadPlugins(plugins) {
11208
11305
  return plugins.map((moduleName, index) => {
11209
11306
  if (typeof moduleName !== "string") {
@@ -11287,99 +11384,6 @@ class Config {
11287
11384
  transformers: this.transformers
11288
11385
  };
11289
11386
  }
11290
- precompileTransformers(transform) {
11291
- return Object.entries(transform).map(([pattern, name]) => {
11292
- try {
11293
- const fn = this.getTransformFunction(name);
11294
- const version = fn.api ?? 0;
11295
- if (version !== TRANSFORMER_API.VERSION) {
11296
- throw new ConfigError(
11297
- `Transformer uses API version ${String(version)} but only version ${String(TRANSFORMER_API.VERSION)} is supported`
11298
- );
11299
- }
11300
- return {
11301
- // eslint-disable-next-line security/detect-non-literal-regexp -- expected to be a regexp
11302
- pattern: new RegExp(pattern),
11303
- name,
11304
- fn
11305
- };
11306
- } catch (err) {
11307
- if (err instanceof ConfigError) {
11308
- throw new ConfigError(`Failed to load transformer "${name}": ${err.message}`, err);
11309
- } else {
11310
- throw new ConfigError(`Failed to load transformer "${name}"`, ensureError(err));
11311
- }
11312
- }
11313
- });
11314
- }
11315
- /**
11316
- * Get transformation function requested by configuration.
11317
- *
11318
- * Searches:
11319
- *
11320
- * - Named transformers from plugins.
11321
- * - Unnamed transformer from plugin.
11322
- * - Standalone modules (local or node_modules)
11323
- *
11324
- * @param name - Key from configuration
11325
- */
11326
- getTransformFunction(name) {
11327
- const match = name.match(/(.*):(.*)/);
11328
- if (match) {
11329
- const [, pluginName, key] = match;
11330
- return this.getNamedTransformerFromPlugin(name, pluginName, key);
11331
- }
11332
- const plugin = this.plugins.find((cur) => cur.name === name);
11333
- if (plugin) {
11334
- return this.getUnnamedTransformerFromPlugin(name, plugin);
11335
- }
11336
- return this.getTransformerFromModule(name);
11337
- }
11338
- /**
11339
- * @param name - Original name from configuration
11340
- * @param pluginName - Name of plugin
11341
- * @param key - Name of transform (from plugin)
11342
- */
11343
- getNamedTransformerFromPlugin(name, pluginName, key) {
11344
- const plugin = this.plugins.find((cur) => cur.name === pluginName);
11345
- if (!plugin) {
11346
- throw new ConfigError(`No plugin named "${pluginName}" has been loaded`);
11347
- }
11348
- if (!plugin.transformer) {
11349
- throw new ConfigError(`Plugin does not expose any transformer`);
11350
- }
11351
- if (typeof plugin.transformer === "function") {
11352
- throw new ConfigError(
11353
- `Transformer "${name}" refers to named transformer but plugin exposes only unnamed, use "${pluginName}" instead.`
11354
- );
11355
- }
11356
- const transformer = plugin.transformer[key];
11357
- if (!transformer) {
11358
- throw new ConfigError(`Plugin "${pluginName}" does not expose a transformer named "${key}".`);
11359
- }
11360
- return transformer;
11361
- }
11362
- /**
11363
- * @param name - Original name from configuration
11364
- * @param plugin - Plugin instance
11365
- */
11366
- getUnnamedTransformerFromPlugin(name, plugin) {
11367
- if (!plugin.transformer) {
11368
- throw new ConfigError(`Plugin does not expose any transformer`);
11369
- }
11370
- if (typeof plugin.transformer !== "function") {
11371
- if (plugin.transformer.default) {
11372
- return plugin.transformer.default;
11373
- }
11374
- throw new ConfigError(
11375
- `Transformer "${name}" refers to unnamed transformer but plugin exposes only named.`
11376
- );
11377
- }
11378
- return plugin.transformer;
11379
- }
11380
- getTransformerFromModule(name) {
11381
- return resolveTransformer(this.resolvers, name, { cache: true });
11382
- }
11383
11387
  }
11384
11388
 
11385
11389
  class ConfigLoader {
@@ -11397,6 +11401,12 @@ class ConfigLoader {
11397
11401
  configData ? this.loadFromObject(configData) : this.defaultConfig()
11398
11402
  );
11399
11403
  }
11404
+ /**
11405
+ * @internal
11406
+ */
11407
+ getResolvers() {
11408
+ return this.resolvers;
11409
+ }
11400
11410
  /**
11401
11411
  * @internal For testing only
11402
11412
  */
@@ -12580,11 +12590,9 @@ class StaticConfigLoader extends ConfigLoader {
12580
12590
  getConfigFor(_handle, configOverride) {
12581
12591
  const override = this.loadFromObject(configOverride ?? {});
12582
12592
  if (override.isRootFound()) {
12583
- override.init();
12584
12593
  return override.resolve();
12585
12594
  }
12586
12595
  const merged = this.globalConfig.merge(this.resolvers, override);
12587
- merged.init();
12588
12596
  return merged.resolve();
12589
12597
  }
12590
12598
  flushCache() {
@@ -12654,7 +12662,8 @@ class HtmlValidate {
12654
12662
  async validateSource(input, configOverride) {
12655
12663
  const source = normalizeSource(input);
12656
12664
  const config = await this.getConfigFor(source.filename, configOverride);
12657
- const transformedSource = config.transformSource(source);
12665
+ const resolvers = this.configLoader.getResolvers();
12666
+ const transformedSource = config.transformSource(resolvers, source);
12658
12667
  const engine = new Engine(config, Parser);
12659
12668
  return engine.lint(transformedSource);
12660
12669
  }
@@ -12668,7 +12677,8 @@ class HtmlValidate {
12668
12677
  validateSourceSync(input, configOverride) {
12669
12678
  const source = normalizeSource(input);
12670
12679
  const config = this.getConfigForSync(source.filename, configOverride);
12671
- const transformedSource = config.transformSource(source);
12680
+ const resolvers = this.configLoader.getResolvers();
12681
+ const transformedSource = config.transformSource(resolvers, source);
12672
12682
  const engine = new Engine(config, Parser);
12673
12683
  return engine.lint(transformedSource);
12674
12684
  }
@@ -12681,7 +12691,8 @@ class HtmlValidate {
12681
12691
  */
12682
12692
  async validateFile(filename) {
12683
12693
  const config = await this.getConfigFor(filename);
12684
- const source = config.transformFilename(filename);
12694
+ const resolvers = this.configLoader.getResolvers();
12695
+ const source = config.transformFilename(resolvers, filename);
12685
12696
  const engine = new Engine(config, Parser);
12686
12697
  return Promise.resolve(engine.lint(source));
12687
12698
  }
@@ -12694,7 +12705,8 @@ class HtmlValidate {
12694
12705
  */
12695
12706
  validateFileSync(filename) {
12696
12707
  const config = this.getConfigForSync(filename);
12697
- const source = config.transformFilename(filename);
12708
+ const resolvers = this.configLoader.getResolvers();
12709
+ const source = config.transformFilename(resolvers, filename);
12698
12710
  const engine = new Engine(config, Parser);
12699
12711
  return engine.lint(source);
12700
12712
  }
@@ -12762,7 +12774,8 @@ class HtmlValidate {
12762
12774
  */
12763
12775
  dumpTokens(filename) {
12764
12776
  const config = this.getConfigForSync(filename);
12765
- const source = config.transformFilename(filename);
12777
+ const resolvers = this.configLoader.getResolvers();
12778
+ const source = config.transformFilename(resolvers, filename);
12766
12779
  const engine = new Engine(config, Parser);
12767
12780
  return engine.dumpTokens(source);
12768
12781
  }
@@ -12777,7 +12790,8 @@ class HtmlValidate {
12777
12790
  */
12778
12791
  dumpEvents(filename) {
12779
12792
  const config = this.getConfigForSync(filename);
12780
- const source = config.transformFilename(filename);
12793
+ const resolvers = this.configLoader.getResolvers();
12794
+ const source = config.transformFilename(resolvers, filename);
12781
12795
  const engine = new Engine(config, Parser);
12782
12796
  return engine.dumpEvents(source);
12783
12797
  }
@@ -12792,7 +12806,8 @@ class HtmlValidate {
12792
12806
  */
12793
12807
  dumpTree(filename) {
12794
12808
  const config = this.getConfigForSync(filename);
12795
- const source = config.transformFilename(filename);
12809
+ const resolvers = this.configLoader.getResolvers();
12810
+ const source = config.transformFilename(resolvers, filename);
12796
12811
  const engine = new Engine(config, Parser);
12797
12812
  return engine.dumpTree(source);
12798
12813
  }
@@ -12807,7 +12822,8 @@ class HtmlValidate {
12807
12822
  */
12808
12823
  dumpSource(filename) {
12809
12824
  const config = this.getConfigForSync(filename);
12810
- const sources = config.transformFilename(filename);
12825
+ const resolvers = this.configLoader.getResolvers();
12826
+ const sources = config.transformFilename(resolvers, filename);
12811
12827
  return sources.reduce((result, source) => {
12812
12828
  const line = String(source.line);
12813
12829
  const column = String(source.column);
@@ -13002,7 +13018,7 @@ class HtmlValidate {
13002
13018
  }
13003
13019
 
13004
13020
  const name = "html-validate";
13005
- const version = "8.25.1";
13021
+ const version = "8.26.0";
13006
13022
  const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
13007
13023
 
13008
13024
  function definePlugin(plugin) {