@crutchcrew/oxlint-plugin-import-access 1.0.1 → 1.1.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 CHANGED
@@ -38,7 +38,7 @@ This plugin adds a directory-level layer between a file and the whole project: a
38
38
  | **Checks unsaved edits in the editor** | ✅ | ✅ | ❌ skipped until saved |
39
39
  | **Same results as the original rule** | ✅ verified¹ | – | ✅ |
40
40
 
41
- ¹ With `defaultImportability: "public"`, which makes exports without an access tag `@public` like in the original. This plugin's default is `"package"`.
41
+ ¹ With `defaultImportability: "public"`, which makes exports without an access tag `@public` like in the original. This plugin's default is `"package"`. This plugin also checks the members used through namespace imports (`import * as foo`), which the original doesn't check.
42
42
 
43
43
  ## Install
44
44
 
@@ -53,6 +53,11 @@ export declare class ImportabilityPolicy {
53
53
  #private;
54
54
  readonly options: PackageOptions;
55
55
  constructor(options: PackageOptions);
56
+ /**
57
+ * Whether some export of `specifier` could be reported. Cheap way to skip namespace imports
58
+ * of external modules and of modules whose exports are all public.
59
+ */
60
+ mayReport(checker: ImportabilityChecker, importerFileName: string, specifier: string): boolean;
56
61
  /**
57
62
  * Check importing `name` (the export name, `default` for default imports) via `specifier`.
58
63
  */
package/dist/index.js CHANGED
@@ -941,10 +941,17 @@ class ImportabilityPolicy {
941
941
  const packageName = lookupPackageName(importerFileName);
942
942
  return packageName !== null && (specifier === packageName || specifier.startsWith(`${packageName}/`));
943
943
  }
944
- check(checker, importerFileName, specifier, name) {
944
+ #targetModule(checker, importerFileName, specifier) {
945
945
  const { defaultImportability, projectDirectory } = this.options;
946
946
  const assumeAllPublic = defaultImportability === "public";
947
- const module = checker.targetModule(importerFileName, specifier, projectDirectory, assumeAllPublic);
947
+ return checker.targetModule(importerFileName, specifier, projectDirectory, assumeAllPublic);
948
+ }
949
+ mayReport(checker, importerFileName, specifier) {
950
+ return this.#targetModule(checker, importerFileName, specifier)?.names !== undefined;
951
+ }
952
+ check(checker, importerFileName, specifier, name) {
953
+ const { defaultImportability } = this.options;
954
+ const module = this.#targetModule(checker, importerFileName, specifier);
948
955
  const found = module && checker.findExport(module, name);
949
956
  if (found === undefined || !found.entries[0].checked) {
950
957
  return;
@@ -1003,6 +1010,21 @@ function realFileName(fileName) {
1003
1010
  function nameOf(node) {
1004
1011
  return node.type === "Literal" ? node.value : node.name;
1005
1012
  }
1013
+ function accessedMember(identifier) {
1014
+ const parent = identifier.parent;
1015
+ if (parent.type === "MemberExpression" && parent.object === identifier) {
1016
+ const { property } = parent;
1017
+ if (property.type === "Identifier" && !parent.computed) {
1018
+ return { node: property, name: property.name };
1019
+ }
1020
+ if (property.type === "Literal" && typeof property.value === "string") {
1021
+ return { node: property, name: property.value };
1022
+ }
1023
+ } else if (parent.type === "TSQualifiedName") {
1024
+ return { node: parent.right, name: parent.right.name };
1025
+ }
1026
+ return;
1027
+ }
1006
1028
  var rule = {
1007
1029
  meta: {
1008
1030
  type: "problem",
@@ -1060,6 +1082,20 @@ var rule = {
1060
1082
  ImportDefaultSpecifier(node) {
1061
1083
  check(node, node.parent.source.value, "default", false);
1062
1084
  },
1085
+ ImportNamespaceSpecifier(node) {
1086
+ const specifier = node.parent.source.value;
1087
+ if (!policy.mayReport(checker, importer, specifier)) {
1088
+ return;
1089
+ }
1090
+ for (const variable of context.sourceCode.getDeclaredVariables(node)) {
1091
+ for (const { identifier } of variable.references) {
1092
+ const member = accessedMember(identifier);
1093
+ if (member !== undefined) {
1094
+ check(member.node, specifier, member.name, false);
1095
+ }
1096
+ }
1097
+ }
1098
+ },
1063
1099
  ExportSpecifier(node) {
1064
1100
  const { source } = node.parent;
1065
1101
  if (source !== null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crutchcrew/oxlint-plugin-import-access",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Oxlint JS plugin for import access via JSDoc @public, @package and @private, without a type checker",
5
5
  "keywords": [
6
6
  "import-access",