Rule.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. const ChainedMap = require('./ChainedMap');
  2. const ChainedSet = require('./ChainedSet');
  3. const Orderable = require('./Orderable');
  4. const Use = require('./Use');
  5. const Resolve = require('./Resolve');
  6. function toArray(arr) {
  7. return Array.isArray(arr) ? arr : [arr];
  8. }
  9. const Rule = Orderable(
  10. class extends ChainedMap {
  11. constructor(parent, name, ruleType = 'rule') {
  12. super(parent);
  13. this.name = name;
  14. this.names = [];
  15. this.ruleType = ruleType;
  16. this.ruleTypes = [];
  17. let rule = this;
  18. while (rule instanceof Rule) {
  19. this.names.unshift(rule.name);
  20. this.ruleTypes.unshift(rule.ruleType);
  21. rule = rule.parent;
  22. }
  23. this.uses = new ChainedMap(this);
  24. this.include = new ChainedSet(this);
  25. this.exclude = new ChainedSet(this);
  26. this.rules = new ChainedMap(this);
  27. this.oneOfs = new ChainedMap(this);
  28. this.resolve = new Resolve(this);
  29. this.extend([
  30. 'enforce',
  31. 'issuer',
  32. 'parser',
  33. 'resource',
  34. 'resourceQuery',
  35. 'sideEffects',
  36. 'test',
  37. 'type',
  38. ]);
  39. }
  40. use(name) {
  41. return this.uses.getOrCompute(name, () => new Use(this, name));
  42. }
  43. rule(name) {
  44. return this.rules.getOrCompute(name, () => new Rule(this, name, 'rule'));
  45. }
  46. oneOf(name) {
  47. return this.oneOfs.getOrCompute(
  48. name,
  49. () => new Rule(this, name, 'oneOf'),
  50. );
  51. }
  52. pre() {
  53. return this.enforce('pre');
  54. }
  55. post() {
  56. return this.enforce('post');
  57. }
  58. toConfig() {
  59. const config = this.clean(
  60. Object.assign(this.entries() || {}, {
  61. include: this.include.values(),
  62. exclude: this.exclude.values(),
  63. rules: this.rules.values().map((rule) => rule.toConfig()),
  64. oneOf: this.oneOfs.values().map((oneOf) => oneOf.toConfig()),
  65. use: this.uses.values().map((use) => use.toConfig()),
  66. resolve: this.resolve.toConfig(),
  67. }),
  68. );
  69. Object.defineProperties(config, {
  70. __ruleNames: { value: this.names },
  71. __ruleTypes: { value: this.ruleTypes },
  72. });
  73. return config;
  74. }
  75. merge(obj, omit = []) {
  76. if (!omit.includes('include') && 'include' in obj) {
  77. this.include.merge(toArray(obj.include));
  78. }
  79. if (!omit.includes('exclude') && 'exclude' in obj) {
  80. this.exclude.merge(toArray(obj.exclude));
  81. }
  82. if (!omit.includes('use') && 'use' in obj) {
  83. Object.keys(obj.use).forEach((name) =>
  84. this.use(name).merge(obj.use[name]),
  85. );
  86. }
  87. if (!omit.includes('rules') && 'rules' in obj) {
  88. Object.keys(obj.rules).forEach((name) =>
  89. this.rule(name).merge(obj.rules[name]),
  90. );
  91. }
  92. if (!omit.includes('oneOf') && 'oneOf' in obj) {
  93. Object.keys(obj.oneOf).forEach((name) =>
  94. this.oneOf(name).merge(obj.oneOf[name]),
  95. );
  96. }
  97. if (!omit.includes('resolve') && 'resolve' in obj) {
  98. this.resolve.merge(obj.resolve);
  99. }
  100. if (!omit.includes('test') && 'test' in obj) {
  101. this.test(
  102. obj.test instanceof RegExp || typeof obj.test === 'function'
  103. ? obj.test
  104. : new RegExp(obj.test),
  105. );
  106. }
  107. return super.merge(obj, [
  108. ...omit,
  109. 'include',
  110. 'exclude',
  111. 'use',
  112. 'rules',
  113. 'oneOf',
  114. 'resolve',
  115. 'test',
  116. ]);
  117. }
  118. },
  119. );
  120. module.exports = Rule;