@@ -557,10 +557,16 @@ function createCustomStore() {
557557 );
558558}
559559
560+ const m = createMemo (() => 5 ) as Accessor< number> ;
561+
562+ const m = createMemo (() => 5 )! ;
563+
564+ const m = createMemo (() => 5 )! as Accessor< number> ;
565+
560566```
561567<!-- AUTO-GENERATED-CONTENT:END -->
562568
563- ### Implementation
569+ ## Implementation
564570
565571We analyze in a single pass but take advantage of ESLint's ": exit " selector
566572to take action both on the way down the tree and on the way back up. At any
@@ -586,3 +592,76 @@ Notes:
586592 match a tracked scope that expects a function.
587593- This rule ignores classes. Solid is based on functions/closures only, and
588594 it's uncommon to see classes with reactivity in Solid code.
595+
596+ ## Implementation v2 (in progress)
597+
598+ ` solid/reactivity ` has been public for exactly one year (!) at the time of writing, and after lots
599+ of feedback, testing, and changes, I've noticed a few problems with its first implementation:
600+
601+ - ** Hard to change.** All of the data structure, analysis, and reporting code is colocated in a
602+ single file with all the cases for detecting signals, props, and tracked scopes based on Solid
603+ APIs. There's a few edge cases where detection code is mixed with analysis code. This makes it
604+ hard for contributors to make PRs and hard for others to be able to maintain it.
605+ - ** Limited to variables.** The analysis code relies heavily on ESLint's ` ScopeManager ` and scope
606+ utilities, and therefore it can only deal with variable references, not implicitly reactive
607+ expressions.
608+ - ** Non-extensible.** Since detection code is hardcoded in the ` reactivity.ts ` file, it is plainly
609+ not possible for users to mark certain APIs as reactive in some way.
610+ - ** Susceptible to timing issues.** I'm very proud of the rule's stack-based algorithm for running
611+ signal/props/tracked scope detection and reactivity analysis in a single pass. Its performance is
612+ going to be extremely difficult to beat. But the single-pass approach puts complex requirements on
613+ the detection phase—signals and props have to be marked before nested ` function:exit ` s, relying on
614+ initialization before usage in source order. That's not a requirement I feel comfortable putting on
615+ plugin authors, or really even myself in a few months.
616+
617+ So, I've decided to partially rewrite the rule with a plugin architecture to alleviate these issues.
618+ Both the core detection code and any plugins to alter detection will use the same API.
619+
620+ ### Ease of change and extensibility: Plugins (Customizations)
621+
622+ ` solid/reactivity ` , itself part of an ESLint plugin, will support plugins of its own.
623+
624+ ` eslint-plugin-solid ` will expose a CLI command ` eslint-plugin-solid ` that searches
625+ ` package.json ` files in the current working directory and its ` node_modules ` for a
626+ ` "solid/reactivity" ` key at the top level (raw string search first for perf). This key will be expected to
627+ contain a relative path to a CommonJS or native ESM file, accessible from requiring a subpath of the
628+ module. For example:
629+
630+ ``` ts
631+ const packageJson = { " solid/reactivity" : " ./reactivity-plugin.js" };
632+ require .resolve (` ${packageJson .name }/${packageJson [" solid/reactivity" ]} ` );
633+ // path to reactivity plugin
634+ ```
635+
636+ The command will not run any code in ` node_modules ` ; it will just print out an example ESLint config for
637+ the ` solid/reactivity ` rule, configured to load all plugins found. For example:
638+
639+ ``` json
640+ "solid/reactivity" : [1 , {
641+ "plugins" : [" ./node_modules/some-module-with-plugin/solid-reactivity-plugin.cjs" ]
642+ }]
643+ ```
644+
645+ This code can be inspected to ensure it matches expections, or edited to add additional paths to
646+ more plugins. You can manually configure a particular path as a plugin without running the CLI at
647+ all. At runtime, any plugins configured will be loaded and run alongside the base rules. Custom
648+ hooks (` use* ` /` create* ` ) from imported from these packages will not be treated permissively, others
649+ will.
650+
651+ > ` eslint-plugin-solid ` will ** not** automatically load plugins. They must be preconfigured in an
652+ > ESLint config file.
653+
654+ ### Expression Support
655+
656+ Having detection code being moved to plugins and an API boundary lets us put reference tracking into
657+ the analysis code, so analyzing arbitrary expressions for reactivity becomes easier. Instead of
658+ using ` TSESLint.Scope.Reference ` s only, a custom data structure can be built to handle any ` Node ` from
659+ the plugin API.
660+
661+ ### Timing
662+
663+ This is a good opportunity to transition from a stack-based algorithm, where information is lost
664+ after the exit pass, to a tree-based algorithm that can capture all reactivity information in a data
665+ structure. By using the built tree to walk through the final analysis, and colocating references
666+ with their associated scopes, performance should stay good. The reactivity rule could then power
667+ an editor plugin to show signals, tracked scopes, etc.
0 commit comments