eslint-plugin-export-scope

Disallows importing scoped exports outside their scope

Downloads
8K
Stars
110
Committers
1

eslint-plugin-export-scope

Don't leak LOCAL utils, states, contexts, components into the global scope.

Demo

Scopes

scope importable from
. current directory and children default for all exports
.. parent directory and children default for index files
../.. two directories above and children
src/consumer within specified directory and children
src/consumer.ts within specified file
* anywhere

Scoped Exports

/** @scopeDefault ../.. */
/** โ˜ Applies to all exports in the file unless overriden with a local `@scope` */

/** @scope * */
export const helper1 = ""; // ๐Ÿ‘ˆ Available everywhere

export const helper2 = ""; // ๐Ÿ‘ˆ inherits scope `../..` from `@scopeDefault`

/** @scope src/components */
export default "";

Default folder scope with .scope.ts files

โ””โ”€โ”€ src
  โ””โ”€โ”€ `common`
    โ”œโ”€โ”€ utils.ts
    โ”œโ”€โ”€ context.ts
    โ””โ”€โ”€ `.scope.ts`
             โ”‚
             โ”‚
  โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
  โ”‚ export default '*' โ”‚
  โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
// โฌ† this will make all exports within `common`
// importable from anywhere unless a
// specific export is overriden on a lower level

Exceptions

Export scope exceptions

// schema.ts
/**
 * @scope ..
 * @scopeException src/schemaConsumer ๐Ÿ‘ˆ whole folder has access
 * @scopeException src/schemaConsumer/index.ts ๐Ÿ‘ˆ whole file has access
 */
export default "";

Folder scope exceptions in .scope.ts files

โ””โ”€โ”€ src
  โ””โ”€โ”€ `generated`
    โ”œโ”€โ”€ schema.ts
    โ””โ”€โ”€ `.scope.ts`
             โ”‚
             โ”‚
  โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
  โ”‚ export default '.';              โ”‚
  โ”‚                                  โ”‚
  โ”‚ export const exceptions = [      โ”‚
  โ”‚   'src/schemaConsumer',          โ”‚
  โ”‚   'src/scripts/schemaParser.ts', โ”‚
  โ”‚ ]                                โ”‚
  โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
// โฌ† by default exports are only importable
// within `generated` folder, but
// folders/files in `exceptions` are exempt.

Installation

Install ESLint and the export-scope package. This package includes both an ESLint plugin and a TS Language Server plugin.

ESLint plugin will highlight imports outside the scope

npm i -D eslint typescript-eslint eslint-plugin-export-scope
// package.json

{
  "type": "module"
}
// eslint.config.js

// @ts-check

import tseslint from "typescript-eslint";
import exportScope from "eslint-plugin-export-scope";

export default tseslint.config(
  // other configs,
  exportScope.configs.flatConfigRecommended,
);
// eslint.config.js

// @ts-check

import tseslint from "typescript-eslint";
import exportScope from "eslint-plugin-export-scope";

export default tseslint.config(
  // other configs,
  {
    files: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.mts", "**/*.mjs", "**/*.cjs"],
    plugins: { "export-scope": exportScope.plugin },
    rules: { "export-scope/no-imports-outside-export-scope": "error" },
    languageOptions: { parser: tseslint.parser, parserOptions: { project: true } },
  },
);
npm i -D eslint @typescript-eslint/parser eslint-plugin-export-scope
                    # โฌ† v6 or above
// .eslintrc.js
module.exports = {
  // ...
  extends: ["plugin:eslint-plugin-export-scope/recommended"],
  parser: "@typescript-eslint/parser",
  parserOptions: { project: true, tsconfigRootDir: __dirname },
  ignorePatterns: ["!.scope.ts"],
};
// .eslintrc.js
module.exports = {
  // ...
  parser: "@typescript-eslint/parser",
  parserOptions: { project: true, tsconfigRootDir: __dirname },
  plugins: ["export-scope"],
  rules: { "export-scope/no-imports-outside-export-scope": "error" },
  ignorePatterns: ["!.scope.ts"],
};

TS plugin will disable autocompletion for exports outside the scope

// tsconfig.json
"compilerOptions": {
  "plugins": [{ "name": "eslint-plugin-export-scope" }],
},
"include": ["**/*", "**/.scope.ts"]
//                  "../../**/.scope.ts" for monorepos

Tell VSCode to Use Workspace Version of TypeScript. Otherwise TS plugin won't work.

  • tsconfig.json file is still required for the plugin to work
  • replace .scope.ts in both configs with .scope.js
  • set compilerOptions.allowJsto true in tsconfig.json

Upgrading from v1 to v2

  • Replace all // comments with jsDocs /** */
  • Replace @scope default with @scopeDefault
  • Relace @.. file/folder prefixes with .scope.ts files.
  • Make sure .eslintrc.js and tsconfig.json configs are updated

Hints

  • Type @ above exports for automatic jsDoc generation.
  • Use autocompletion provided within jsDocs and .scope.ts files.
  • Root .scope.ts file (next to package.json) sets the default for the whole project. Having export default '*' there will make all exports global by default if you prefer a less strict approach.

Issues

โš ๏ธ To re-lint an import in VSCode after updating a scope declaration either touch this import or restart the ESLint Server (ESLint limitation).