textlint icon indicating copy to clipboard operation
textlint copied to clipboard

Supports rules that are ECMAScript Modules

Open azu opened this issue 2 years ago • 2 comments

Currently, textlint can not load a rule that is ECMAScript Modules(ESM).

It means that textlint-module-loader.ts use Dynamic Import instead of require to load a rule module.

This issue aim to support to load a rule that is written by ESM. It is not that rewrite textlint to ESM.

  • Current: require() in CJS can not load ESM, It only load CJS
  • Next(This issue): import() in CJS can load ESM and CJS

TODO

azu avatar May 25 '22 00:05 azu

import(rule) return Promise<NameSpace> So. const default = interop(await import(rule)).default

Edit: const default = interop(await import(rule).default) is correct

azu avatar Sep 10 '22 12:09 azu

  1. Refactor Config
    • Inject config into TextlintEngine from outside like constructor DI
    • Or. No use class. instaed of it, use async function
      • constructor does not support async
    • It means that we need to make config loading async
      • https://github.com/textlint/textlint/blob/d4c5075b5a7bcbf875d7cee122de7dc5253d325e/packages/textlint/src/config/config.ts#L388
    • Probably, we need to based on https://github.com/textlint/editor/tree/master/packages/%40textlint/config-loader
  2. use dynamic import for loading rule/plugin

azu avatar Sep 10 '22 23:09 azu

Change to Async:

  • Config Loading
    • textlintrc.mjs supports require Async API: https://github.com/davidtheclark/cosmiconfig/pull/283
  • Rule/Preset/Filter/Plugin Loading
    • Need to use Dynamic Import to load a module written in ESM
flowchart LR
   A[Load Config File] --> B[Load Modules]

azu avatar Dec 25 '22 06:12 azu

We will introduce new API like createTextlint for supporting Async APIs. v13 continue to support current TextLintEngine and TextFixEngine for backward compatible.

  • #902

New createTextlint support ESM rules/plugins. In other hands, TextLintEngine and TextFixEngine can not support ESM rules/plugins.

https://github.com/textlint/textlint/blob/60cea514f7eaefbff4411087d16a51daf68f12a4/packages/textlint/src/index.ts

API Description Behavior Target Platform Current Status Next Status
cli Command LIne Interface Async Node.js ✅ (Use createTextlint internally)
textlint TextLintCore alias Async Node.js/CommonJS ❌ Deprecated ❌ Deprecated
TextLintCore Old API. It is Procedural API. Lint Only Single File. Recommended to use @texltint/kernel module instead of It. Async Node.js/CommonJS ❌ Deprecated ❌ Deprecated
TextLintEngine Lint Engine API. It load .textlintrc automaticaly ◉ Loading is Sync
◉ Linting is Async
Node.js/CommonJS ✅ Recommended ❌ Deprecated
TextFixEngine Fix Engine API. It load .textlintrc automaticaly ◉ Loading is Sync
◉ Fixing is Async
Node.js/CommonJS ✅ Recommended ❌ Deprecated
createLinter Combine TextLintEngine and TextFixEngine. Support Async APIs. ◉ Loading is Async
◉ Linting/Fixing is Async
Node.js/CommonJS and ESM None ✅ Recommended

azu avatar Dec 25 '22 07:12 azu

We have two config

  • .textlintrc config file
  • CLI options - It override textlintrc

It is just idea that we can implement these as separated loader and merge these.

image
type Loader = (_:unknown) => Promise<Config>;
const config = mergeConfig({
 await configFileLoader(),
 await cliLoader()
});

createTextlint({
  config
});

// OR
createTextlint({
  loaders: [configFileLoader(), cliLoader()]
});

azu avatar Dec 26 '22 07:12 azu