# Environment `env.project`

Creates configuration objects for custom project setup and module imports.

- Source files will be checked for the correct usage of ES modules with static `import` and `export` statements, as well as dynamic `import` expressions. For the latter, only literal strings will be checked, other expressions that build the imported module names dynamically cannot be checked.

- Enforces an hierarchy of internal packages. If a project distributes its source files into multiple installation packages, the dependencies between these packages can be checked to prevent that files from a base package import files from a dependent package (which may not get installed on the target machine).

- Bans the TypeScript compiler directive `<amd-module>`. This directive was used in the past to declare module names when transpiling TypeScript module code to AMD modules.

## Signature

```ts
function project(options: EnvProjectOptions): ConfigArg
```

## Options

| Name | Type | Default | Description |
| - | - | - | - |
| `basePath` | `string` | `'.'` | Path to a sub directory to apply the environment preset to. |
| `files` | `Array<string\|string[]>` | _required_ | Glob patterns for source files to be included. Use embedded arrays for AND patterns. |
| `ignores` | `string[]` | `[]` | Glob patterns for source files matching `files` to be ignored. |
| `alias` | `Record<string, string>` | `{}` | Maps all alias prefixes to actual paths in the project (see below). |
| `external` | `string \| string[]` | `[]` | Specifies glob patterns for external modules (see below). |
| `hierarchy` | `Record<string, RuleNoInvalidHierarchyPackage>` | `{}` | Allows to separate the source files into virtual packages (see below). |
| `rules` | `RulesConfig` | `{}` | Additional linter rules to be added to the configuration. |

### Option `alias`

- Type: `Record<string, string>`
- Default: `{}`

Maps all alias prefixes to actual paths in the project. All paths must be relative to the project's root directory.

#### `alias` Example

```ts
// eslint.config.ts
import { defineConfig, env } from '@open-xchange/linter-presets/eslint'

export default defineConfig(

  // project configuration options
  { /* ... */ },

  // project environment
  env.project({
    files: ['src/**/*.{js,ts}'],
    alias: {
      '@': 'src',
    },
  }),
)
```

- The alias prefix `'@/'` of a module name will be replaced with the path `src/` to check the existence of source files.
- The module `'@/my/module'` will correspond to the file `src/my/module.js` (relative to the project's root directory).

### Option `external`

- Type: `string[]`
- Default: `[]`

Specifies glob patterns for modules that can be imported although there is no module file available, e.g. due to build tool configuration.

#### `external` Example

```ts
// eslint.config.ts
import { defineConfig, env } from '@open-xchange/linter-presets/eslint'

export default defineConfig(

  // project configuration options
  { /* ... */ },

  // project environment
  env.project({
    files: ['src/**/*.{js,ts}'],
    alias: { '@': 'src' },
    external: ['virtual:*', '@/special/lib/**/*.js'],
  }),
)
```

- All imports starting with `'virtual:'` will not be checked.
- All imports of `.js` files deeply inside `src/special/lib/` will not be checked.

### Option `hierarchy`

- Type: `Record<string, RuleNoInvalidHierarchyPackage>`
- Default: `{}`

Allows to separate the source files into several virtual packages. This option is completely independent from any actual packaging performed in later steps of the build process. Its solely purpose is to impose dependencies between the source files to prevent importing files between specific packages.

Each key in the `hierarchy` record is the arbitrary unique name of a package. The record values must be objects satisfying the interface `RuleNoInvalidHierarchyPackage`:

| Name | Type | Default | Description |
| - | - | - | - |
| `files` | `string[]` | _required_ | Glob patterns selecting all source files that are part of the package. |
| `extends` | `string\|string[]` | `[]` | Specifies the names of all packages (dictionary keys of the option `hierarchy`) this package depends on. |
| `optional` | `boolean` | `false` | Set to `true` to mark an optional package that may be missing in an installation. Such a package cannot be imported statically (with `import` statement) from a non-optional package, but can only be loaded dynamically at runtime (by calling `import()`). The rule will mark all static imports of optional code as an error. |

Modules that are part of such a package may import any modules from the same package, or from packages it depends on (also recursively from their dependent packages).

Example configuration:

```ts
// eslint.config.ts
import { defineConfig, env } from '@open-xchange/linter-presets/eslint'

export default defineConfig(

  // project configuration options
  { /* ... */ },

  // project environment
  env.project({
    files: ['src/**/*.{js,ts}'],
    alias: { '@': 'src' },
    hierarchy: {
      base: {
        files: ['@/base/**/*', '@/tools/**/*'],
      },
      debug: {
        files: ['@/debug/**/*'],
        extends: 'base',
        optional: true,
      },
      special: {
        files: ['@/my/special/**/*'],
        extends: ['base', 'debug'],
      },
    },
  }),
)
```

- The package `base` contains all modules starting with `@/base/` or `@/tools/`. All modules in the package `base` can import themselves, but they cannot import any other modules from the project.
- The _optional_ package `debug` contains all modules starting with `@/debug/`. Modules in this package can import other modules from this package, and from the package `base`. Modules in this package can only be imported dynamically from other packages.
- The package `special` contains all modules starting with `@/my/special/`. Modules in this package can import other modules from this package, and all modules from the packages `base` and `debug`. The latter package can only be imported dynamically.
