@drupal-canvas/eslint-config 0.2.0 → 0.3.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 +6 -5
- package/dist/index.js +154 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,11 +33,12 @@ export default defineConfig([
|
|
|
33
33
|
The following custom rules are part of the `required` config and validate Drupal
|
|
34
34
|
Canvas Code Components:
|
|
35
35
|
|
|
36
|
-
| Rule
|
|
37
|
-
|
|
|
38
|
-
| `component-dir-name`
|
|
39
|
-
| `component-exports`
|
|
40
|
-
| `component-
|
|
36
|
+
| Rule | Description |
|
|
37
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------- |
|
|
38
|
+
| `component-dir-name` | Validates that `machineName` matches the directory name (index-style) or filename prefix (named-style). |
|
|
39
|
+
| `component-exports` | Validates that component has a default export. |
|
|
40
|
+
| `component-image-example-urls` | Validates that `canvas.module/image` prop examples use fully qualified image URLs. |
|
|
41
|
+
| `component-prop-names` | Validates that component prop IDs match the camelCase version of their titles. |
|
|
41
42
|
|
|
42
43
|
### Deprecated rules
|
|
43
44
|
|
package/dist/index.js
CHANGED
|
@@ -320,9 +320,9 @@ var require_ignore = __commonJS({
|
|
|
320
320
|
};
|
|
321
321
|
}
|
|
322
322
|
if (checkPattern(pattern.pattern)) {
|
|
323
|
-
const
|
|
323
|
+
const rule9 = createRule(pattern, this._ignoreCase);
|
|
324
324
|
this._added = true;
|
|
325
|
-
this._rules.push(
|
|
325
|
+
this._rules.push(rule9);
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
// @param {Array<string> | string | Ignore} pattern
|
|
@@ -344,18 +344,18 @@ var require_ignore = __commonJS({
|
|
|
344
344
|
let ignored = false;
|
|
345
345
|
let unignored = false;
|
|
346
346
|
let matchedRule;
|
|
347
|
-
this._rules.forEach((
|
|
348
|
-
const { negative } =
|
|
347
|
+
this._rules.forEach((rule9) => {
|
|
348
|
+
const { negative } = rule9;
|
|
349
349
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
350
350
|
return;
|
|
351
351
|
}
|
|
352
|
-
const matched =
|
|
352
|
+
const matched = rule9[mode].test(path2);
|
|
353
353
|
if (!matched) {
|
|
354
354
|
return;
|
|
355
355
|
}
|
|
356
356
|
ignored = !negative;
|
|
357
357
|
unignored = negative;
|
|
358
|
-
matchedRule = negative ? UNDEFINED :
|
|
358
|
+
matchedRule = negative ? UNDEFINED : rule9;
|
|
359
359
|
});
|
|
360
360
|
const ret = {
|
|
361
361
|
ignored,
|
|
@@ -668,6 +668,104 @@ var rule2 = {
|
|
|
668
668
|
}
|
|
669
669
|
};
|
|
670
670
|
var component_exports_default = rule2;
|
|
671
|
+
|
|
672
|
+
// src/rules/component-image-example-urls.ts
|
|
673
|
+
var IMAGE_REF = "json-schema-definitions://canvas.module/image";
|
|
674
|
+
function getMappingPair(mapping, key) {
|
|
675
|
+
return mapping.pairs.find((pair) => getYAMLStringValue(pair.key) === key);
|
|
676
|
+
}
|
|
677
|
+
function isYamlMapping(node) {
|
|
678
|
+
return node?.type === "YAMLMapping";
|
|
679
|
+
}
|
|
680
|
+
function isYamlSequence(node) {
|
|
681
|
+
return node?.type === "YAMLSequence";
|
|
682
|
+
}
|
|
683
|
+
function hasImageRef(propMapping) {
|
|
684
|
+
const ref = getYAMLStringValue(
|
|
685
|
+
getMappingPair(propMapping, "$ref")?.value ?? null
|
|
686
|
+
);
|
|
687
|
+
if (ref === IMAGE_REF) {
|
|
688
|
+
return true;
|
|
689
|
+
}
|
|
690
|
+
const itemsValue = getMappingPair(propMapping, "items")?.value;
|
|
691
|
+
if (!isYamlMapping(itemsValue)) {
|
|
692
|
+
return false;
|
|
693
|
+
}
|
|
694
|
+
return getYAMLStringValue(getMappingPair(itemsValue, "$ref")?.value ?? null) === IMAGE_REF;
|
|
695
|
+
}
|
|
696
|
+
function isFullyQualifiedUrl(value) {
|
|
697
|
+
try {
|
|
698
|
+
const parsed = new URL(value);
|
|
699
|
+
return parsed.protocol.length > 0 && parsed.hostname.length > 0;
|
|
700
|
+
} catch {
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
function getInvalidImageExampleNodes(examplesValue) {
|
|
705
|
+
if (!isYamlSequence(examplesValue)) {
|
|
706
|
+
return [];
|
|
707
|
+
}
|
|
708
|
+
const invalidNodes = [];
|
|
709
|
+
for (const example of examplesValue.entries) {
|
|
710
|
+
const imageEntries = isYamlSequence(example) ? example.entries : [example];
|
|
711
|
+
for (const imageEntry of imageEntries) {
|
|
712
|
+
if (!isYamlMapping(imageEntry)) {
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
const srcNode = getMappingPair(imageEntry, "src")?.value;
|
|
716
|
+
if (srcNode?.type === "YAMLScalar" && typeof srcNode.value === "string" && !isFullyQualifiedUrl(srcNode.value)) {
|
|
717
|
+
invalidNodes.push(srcNode);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return invalidNodes;
|
|
722
|
+
}
|
|
723
|
+
var rule3 = {
|
|
724
|
+
meta: {
|
|
725
|
+
type: "problem",
|
|
726
|
+
docs: {
|
|
727
|
+
description: "Validates that default examples for image props use fully-qualified URLs"
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
create(context) {
|
|
731
|
+
if (!isComponentYmlFile(context.filename)) {
|
|
732
|
+
return {};
|
|
733
|
+
}
|
|
734
|
+
return {
|
|
735
|
+
YAMLPair(node) {
|
|
736
|
+
const keyName = getYAMLStringValue(node.key);
|
|
737
|
+
if (keyName !== "props" || !isYamlMapping(node.value)) {
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
const propertiesValue = getMappingPair(node.value, "properties")?.value;
|
|
741
|
+
if (!isYamlMapping(propertiesValue)) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
for (const propPair of propertiesValue.pairs) {
|
|
745
|
+
const propId = getYAMLStringValue(propPair.key);
|
|
746
|
+
if (!propId || !isYamlMapping(propPair.value)) {
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
if (!hasImageRef(propPair.value)) {
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
const examplesValue = getMappingPair(
|
|
753
|
+
propPair.value,
|
|
754
|
+
"examples"
|
|
755
|
+
)?.value;
|
|
756
|
+
const invalidNodes = getInvalidImageExampleNodes(examplesValue);
|
|
757
|
+
for (const invalidNode of invalidNodes) {
|
|
758
|
+
context.report({
|
|
759
|
+
node: invalidNode,
|
|
760
|
+
message: `Image prop "${propId}" example src must be a fully-qualified URL with both scheme and host. Use a placeholder URL such as https://placehold.co/600x400.`
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
var component_image_example_urls_default = rule3;
|
|
671
769
|
var Gt = (n7, t, e) => {
|
|
672
770
|
let s = n7 instanceof RegExp ? ce(n7, e) : n7, i = t instanceof RegExp ? ce(t, e) : t, r = s !== null && i != null && ss(s, i, e);
|
|
673
771
|
return r && { start: r[0], end: r[1], pre: e.slice(0, r[0]), body: e.slice(r[0] + s.length, r[1]), post: e.slice(r[1] + i.length) };
|
|
@@ -4447,7 +4545,7 @@ function checkImportSource(context, node, source) {
|
|
|
4447
4545
|
if (source.startsWith("@fontsource")) {
|
|
4448
4546
|
context.report({
|
|
4449
4547
|
node,
|
|
4450
|
-
message: `Importing font packages ("${source}") is not supported in components
|
|
4548
|
+
message: `Importing font packages ("${source}") is not supported in components.`
|
|
4451
4549
|
});
|
|
4452
4550
|
return;
|
|
4453
4551
|
}
|
|
@@ -4508,7 +4606,7 @@ function checkImportSource(context, node, source) {
|
|
|
4508
4606
|
if (source === "@/lib/FormattedText") {
|
|
4509
4607
|
context.report({
|
|
4510
4608
|
node,
|
|
4511
|
-
message: "The `FormattedText` component was moved into the `drupal-canvas` package.",
|
|
4609
|
+
message: "The `FormattedText` component was moved into the `drupal-canvas` package. The `@/lib/FormattedText` path is provided by Canvas and cannot be used for local files.",
|
|
4512
4610
|
fix(fixer) {
|
|
4513
4611
|
if (node.type === "ImportDeclaration" && node.specifiers.length === 1 && node.specifiers[0].local.name === "FormattedText") {
|
|
4514
4612
|
return fixer.replaceText(
|
|
@@ -4521,6 +4619,42 @@ function checkImportSource(context, node, source) {
|
|
|
4521
4619
|
});
|
|
4522
4620
|
return;
|
|
4523
4621
|
}
|
|
4622
|
+
if (source === "@/lib/utils") {
|
|
4623
|
+
context.report({
|
|
4624
|
+
node,
|
|
4625
|
+
message: "Utilities were moved into the `drupal-canvas` package. The `@/lib/utils` path is provided by Canvas and cannot be used for local files.",
|
|
4626
|
+
fix(fixer) {
|
|
4627
|
+
return fixer.replaceText(node.source, "'drupal-canvas'");
|
|
4628
|
+
}
|
|
4629
|
+
});
|
|
4630
|
+
return;
|
|
4631
|
+
}
|
|
4632
|
+
if (source === "@/lib/jsonapi-utils") {
|
|
4633
|
+
context.report({
|
|
4634
|
+
node,
|
|
4635
|
+
message: "JSON:API utilities were moved into the `drupal-canvas` package. The `@/lib/jsonapi-utils` path is provided by Canvas and cannot be used for local files.",
|
|
4636
|
+
fix(fixer) {
|
|
4637
|
+
return fixer.replaceText(node.source, "'drupal-canvas'");
|
|
4638
|
+
}
|
|
4639
|
+
});
|
|
4640
|
+
return;
|
|
4641
|
+
}
|
|
4642
|
+
if (source === "@/lib/drupal-utils") {
|
|
4643
|
+
context.report({
|
|
4644
|
+
node,
|
|
4645
|
+
message: "Drupal utilities were moved into the `drupal-canvas` package. The `@/lib/drupal-utils` path is provided by Canvas and cannot be used for local files.",
|
|
4646
|
+
fix(fixer) {
|
|
4647
|
+
const importsSortMenu = node.type === "ImportDeclaration" && node.specifiers.some(
|
|
4648
|
+
(specifier) => specifier.local.name === "sortMenu" || specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier" && specifier.imported.name === "sortMenu"
|
|
4649
|
+
);
|
|
4650
|
+
if (!importsSortMenu) {
|
|
4651
|
+
return fixer.replaceText(node.source, "'drupal-canvas'");
|
|
4652
|
+
}
|
|
4653
|
+
return null;
|
|
4654
|
+
}
|
|
4655
|
+
});
|
|
4656
|
+
return;
|
|
4657
|
+
}
|
|
4524
4658
|
if (source.startsWith("@/")) {
|
|
4525
4659
|
const suffix = source.slice(2);
|
|
4526
4660
|
const config = resolveCanvasConfig({ hostRoot: context.cwd });
|
|
@@ -4536,7 +4670,7 @@ function checkImportSource(context, node, source) {
|
|
|
4536
4670
|
return;
|
|
4537
4671
|
}
|
|
4538
4672
|
}
|
|
4539
|
-
var
|
|
4673
|
+
var rule4 = {
|
|
4540
4674
|
meta: {
|
|
4541
4675
|
type: "problem",
|
|
4542
4676
|
docs: {
|
|
@@ -4562,7 +4696,7 @@ var rule3 = {
|
|
|
4562
4696
|
};
|
|
4563
4697
|
}
|
|
4564
4698
|
};
|
|
4565
|
-
var component_imports_default =
|
|
4699
|
+
var component_imports_default = rule4;
|
|
4566
4700
|
function extractProps(propsNode) {
|
|
4567
4701
|
if (!propsNode.value || propsNode.value.type !== "YAMLMapping") {
|
|
4568
4702
|
return [];
|
|
@@ -4596,7 +4730,7 @@ function extractProps(propsNode) {
|
|
|
4596
4730
|
}
|
|
4597
4731
|
return props;
|
|
4598
4732
|
}
|
|
4599
|
-
var
|
|
4733
|
+
var rule5 = {
|
|
4600
4734
|
meta: {
|
|
4601
4735
|
type: "problem",
|
|
4602
4736
|
docs: {
|
|
@@ -4637,7 +4771,7 @@ var rule4 = {
|
|
|
4637
4771
|
};
|
|
4638
4772
|
}
|
|
4639
4773
|
};
|
|
4640
|
-
var component_prop_names_default =
|
|
4774
|
+
var component_prop_names_default = rule5;
|
|
4641
4775
|
|
|
4642
4776
|
// src/configs/required.ts
|
|
4643
4777
|
var required = defineConfig([
|
|
@@ -4663,6 +4797,7 @@ var required = defineConfig([
|
|
|
4663
4797
|
rules: {
|
|
4664
4798
|
"component-dir-name": component_dir_name_default,
|
|
4665
4799
|
"component-exports": component_exports_default,
|
|
4800
|
+
"component-image-example-urls": component_image_example_urls_default,
|
|
4666
4801
|
"component-imports": component_imports_default,
|
|
4667
4802
|
"component-prop-names": component_prop_names_default
|
|
4668
4803
|
}
|
|
@@ -4671,6 +4806,7 @@ var required = defineConfig([
|
|
|
4671
4806
|
rules: {
|
|
4672
4807
|
"drupal-canvas/component-dir-name": "error",
|
|
4673
4808
|
"drupal-canvas/component-exports": "error",
|
|
4809
|
+
"drupal-canvas/component-image-example-urls": "error",
|
|
4674
4810
|
"drupal-canvas/component-imports": "error",
|
|
4675
4811
|
"drupal-canvas/component-prop-names": "error"
|
|
4676
4812
|
}
|
|
@@ -4718,7 +4854,7 @@ var IGNORED_FILES = [
|
|
|
4718
4854
|
function isFileAllowed(fileName, allowedFiles) {
|
|
4719
4855
|
return allowedFiles.some((allowedFile) => allowedFile === fileName);
|
|
4720
4856
|
}
|
|
4721
|
-
var
|
|
4857
|
+
var rule6 = {
|
|
4722
4858
|
meta: {
|
|
4723
4859
|
type: "problem",
|
|
4724
4860
|
docs: {
|
|
@@ -4757,7 +4893,7 @@ var rule5 = {
|
|
|
4757
4893
|
};
|
|
4758
4894
|
}
|
|
4759
4895
|
};
|
|
4760
|
-
var component_files_default =
|
|
4896
|
+
var component_files_default = rule6;
|
|
4761
4897
|
function checkImportSource2(context, node, source) {
|
|
4762
4898
|
if (source.startsWith("./") || source.startsWith("../")) {
|
|
4763
4899
|
context.report({
|
|
@@ -4886,7 +5022,7 @@ function checkImportSource2(context, node, source) {
|
|
|
4886
5022
|
message: `Importing "${source}" is not supported. If this is a local import via a path alias, use the "@/components/" alias instead. If you are importing a third-party package, see the list of supported packages at https://project.pages.drupalcode.org/canvas/code-components/packages. (The status of supporting any third-party package can be tracked at https://drupal.org/i/3560197.)`
|
|
4887
5023
|
});
|
|
4888
5024
|
}
|
|
4889
|
-
var
|
|
5025
|
+
var rule7 = {
|
|
4890
5026
|
meta: {
|
|
4891
5027
|
type: "problem",
|
|
4892
5028
|
docs: {
|
|
@@ -4913,7 +5049,7 @@ var rule6 = {
|
|
|
4913
5049
|
};
|
|
4914
5050
|
}
|
|
4915
5051
|
};
|
|
4916
|
-
var component_imports_deprecated_default =
|
|
5052
|
+
var component_imports_deprecated_default = rule7;
|
|
4917
5053
|
function findTopmostComponentsParentDir(currentParentDir, rootDir) {
|
|
4918
5054
|
if (currentParentDir === rootDir) {
|
|
4919
5055
|
return currentParentDir;
|
|
@@ -4934,7 +5070,7 @@ function hasComponentSubdirectories(dirPath) {
|
|
|
4934
5070
|
}
|
|
4935
5071
|
return false;
|
|
4936
5072
|
}
|
|
4937
|
-
var
|
|
5073
|
+
var rule8 = {
|
|
4938
5074
|
meta: {
|
|
4939
5075
|
type: "problem",
|
|
4940
5076
|
docs: {
|
|
@@ -4969,7 +5105,7 @@ var rule7 = {
|
|
|
4969
5105
|
};
|
|
4970
5106
|
}
|
|
4971
5107
|
};
|
|
4972
|
-
var component_no_hierarchy_default =
|
|
5108
|
+
var component_no_hierarchy_default = rule8;
|
|
4973
5109
|
|
|
4974
5110
|
// src/configs/requiredDeprecated.ts
|
|
4975
5111
|
var required2 = defineConfig([
|