@nitpicker/core 0.24.0 → 0.25.1
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 +165 -35
- package/lib/assert-u32-id.d.ts +15 -0
- package/lib/assert-u32-id.js +22 -0
- package/lib/check-native-executor-config.d.ts +21 -0
- package/lib/check-native-executor-config.js +24 -0
- package/lib/compute-alias-keys.d.ts +28 -0
- package/lib/compute-alias-keys.js +30 -0
- package/lib/compute-body-hash.d.ts +22 -0
- package/lib/compute-body-hash.js +25 -0
- package/lib/compute-url-sort-ranks.d.ts +28 -0
- package/lib/compute-url-sort-ranks.js +49 -0
- package/lib/create-isolated-cluster-run.d.ts +35 -0
- package/lib/create-isolated-cluster-run.js +52 -0
- package/lib/create-template-classification-run.d.ts +49 -0
- package/lib/create-template-classification-run.js +386 -0
- package/lib/group-alias-candidates.d.ts +40 -0
- package/lib/group-alias-candidates.js +104 -0
- package/lib/load-native-binding.d.ts +26 -0
- package/lib/load-native-binding.js +152 -0
- package/lib/match-js-license-comment-signal.d.ts +19 -0
- package/lib/match-js-license-comment-signal.js +21 -0
- package/lib/match-selector-html.d.ts +41 -0
- package/lib/match-selector-html.js +42 -0
- package/lib/match-selector-snapshots.d.ts +40 -0
- package/lib/match-selector-snapshots.js +57 -0
- package/lib/match-structural-technology-signals.d.ts +23 -0
- package/lib/match-structural-technology-signals.js +25 -0
- package/lib/max-decoded-snapshot-bytes.d.ts +22 -0
- package/lib/max-decoded-snapshot-bytes.js +35 -0
- package/lib/native-binding.d.ts +9 -0
- package/lib/native-binding.js +9 -0
- package/lib/pack-stored-snapshots.d.ts +23 -0
- package/lib/pack-stored-snapshots.js +53 -0
- package/lib/run-with-signal.d.ts +27 -0
- package/lib/run-with-signal.js +54 -0
- package/lib/search-html-document.d.ts +32 -0
- package/lib/search-html-document.js +31 -0
- package/lib/search-html-snapshots.d.ts +46 -0
- package/lib/search-html-snapshots.js +54 -0
- package/lib/template-block-sample-size.d.ts +13 -0
- package/lib/template-block-sample-size.js +14 -0
- package/lib/template-exact-page-limit.d.ts +18 -0
- package/lib/template-exact-page-limit.js +19 -0
- package/lib/template-memory-budget.d.ts +16 -0
- package/lib/template-memory-budget.js +17 -0
- package/lib/to-native-selector-plan.d.ts +16 -0
- package/lib/to-native-selector-plan.js +40 -0
- package/lib/to-u32-ids.d.ts +14 -0
- package/lib/to-u32-ids.js +22 -0
- package/lib/types.d.ts +736 -248
- package/lib/validate-search-pattern.d.ts +25 -0
- package/lib/validate-search-pattern.js +27 -0
- package/package.json +83 -16
- package/lib/core.d.ts +0 -4
- package/lib/core.js +0 -4
- package/lib/discover-analyze-plugins.d.ts +0 -14
- package/lib/discover-analyze-plugins.js +0 -32
- package/lib/get-table-cache-root.d.ts +0 -18
- package/lib/get-table-cache-root.js +0 -22
- package/lib/hooks/define-plugin.d.ts +0 -68
- package/lib/hooks/define-plugin.js +0 -69
- package/lib/import-modules.d.ts +0 -24
- package/lib/import-modules.js +0 -38
- package/lib/load-plugin-settings.d.ts +0 -44
- package/lib/load-plugin-settings.js +0 -125
- package/lib/nitpicker.d.ts +0 -150
- package/lib/nitpicker.js +0 -437
- package/lib/page-analysis-worker.d.ts +0 -58
- package/lib/page-analysis-worker.js +0 -68
- package/lib/read-plugin-labels.d.ts +0 -15
- package/lib/read-plugin-labels.js +0 -30
- package/lib/table.d.ts +0 -75
- package/lib/table.js +0 -132
- package/lib/url-event-bus.d.ts +0 -33
- package/lib/url-event-bus.js +0 -21
- package/lib/worker/runner.d.ts +0 -25
- package/lib/worker/runner.js +0 -31
- package/lib/worker/types.d.ts +0 -23
- package/lib/worker/types.js +0 -1
- package/lib/worker/worker-pool.d.ts +0 -82
- package/lib/worker/worker-pool.js +0 -278
- package/lib/worker/worker.d.ts +0 -34
- package/lib/worker/worker.js +0 -108
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { NativeSearchPattern } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compiles a `query search-html` pattern and reports whether it matches the
|
|
4
|
+
* empty string.
|
|
5
|
+
*
|
|
6
|
+
* The pattern is a literal, or a regular expression in the syntax of Rust's
|
|
7
|
+
* `regex` crate: backreferences and look-around are not supported, and
|
|
8
|
+
* matching runs in time linear in the document. The addon keeps the last
|
|
9
|
+
* compiled pattern, so a search that follows with the same pattern does not
|
|
10
|
+
* compile it again; this is for refusing a pattern before the archive is
|
|
11
|
+
* opened.
|
|
12
|
+
* @param pattern - The pattern and its flags.
|
|
13
|
+
* @returns Whether the pattern matches the empty string, which `search-html` rejects
|
|
14
|
+
* because it would match at every position of every snapshot.
|
|
15
|
+
* @throws {Error} With code `InvalidArg` and the regex engine's message if the
|
|
16
|
+
* pattern is not valid, uses an unsupported construct, or compiles to more than
|
|
17
|
+
* the engine's size limit.
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* validateSearchPattern({ source: 'a+', literal: false, ignoreCase: false, multiLine: false, dotAll: false }); // false
|
|
21
|
+
* validateSearchPattern({ source: 'a*', literal: false, ignoreCase: false, multiLine: false, dotAll: false }); // true
|
|
22
|
+
* validateSearchPattern({ source: '(?=a)a', literal: false, ignoreCase: false, multiLine: false, dotAll: false }); // throws
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateSearchPattern(pattern: NativeSearchPattern): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { nativeBinding } from './native-binding.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compiles a `query search-html` pattern and reports whether it matches the
|
|
4
|
+
* empty string.
|
|
5
|
+
*
|
|
6
|
+
* The pattern is a literal, or a regular expression in the syntax of Rust's
|
|
7
|
+
* `regex` crate: backreferences and look-around are not supported, and
|
|
8
|
+
* matching runs in time linear in the document. The addon keeps the last
|
|
9
|
+
* compiled pattern, so a search that follows with the same pattern does not
|
|
10
|
+
* compile it again; this is for refusing a pattern before the archive is
|
|
11
|
+
* opened.
|
|
12
|
+
* @param pattern - The pattern and its flags.
|
|
13
|
+
* @returns Whether the pattern matches the empty string, which `search-html` rejects
|
|
14
|
+
* because it would match at every position of every snapshot.
|
|
15
|
+
* @throws {Error} With code `InvalidArg` and the regex engine's message if the
|
|
16
|
+
* pattern is not valid, uses an unsupported construct, or compiles to more than
|
|
17
|
+
* the engine's size limit.
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* validateSearchPattern({ source: 'a+', literal: false, ignoreCase: false, multiLine: false, dotAll: false }); // false
|
|
21
|
+
* validateSearchPattern({ source: 'a*', literal: false, ignoreCase: false, multiLine: false, dotAll: false }); // true
|
|
22
|
+
* validateSearchPattern({ source: '(?=a)a', literal: false, ignoreCase: false, multiLine: false, dotAll: false }); // throws
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function validateSearchPattern(pattern) {
|
|
26
|
+
return nativeBinding.validateSearchPattern(pattern);
|
|
27
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitpicker/core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.25.1",
|
|
4
|
+
"description": "Native (Rust, Node-API) compute core for Nitpicker",
|
|
5
5
|
"author": "D-ZERO",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"engines": {
|
|
@@ -20,23 +20,90 @@
|
|
|
20
20
|
],
|
|
21
21
|
"type": "module",
|
|
22
22
|
"exports": {
|
|
23
|
-
"
|
|
24
|
-
"import": "./lib/
|
|
25
|
-
"types": "./lib/
|
|
23
|
+
"./check-native-executor-config": {
|
|
24
|
+
"import": "./lib/check-native-executor-config.js",
|
|
25
|
+
"types": "./lib/check-native-executor-config.d.ts"
|
|
26
|
+
},
|
|
27
|
+
"./compute-alias-keys": {
|
|
28
|
+
"import": "./lib/compute-alias-keys.js",
|
|
29
|
+
"types": "./lib/compute-alias-keys.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"./compute-body-hash": {
|
|
32
|
+
"import": "./lib/compute-body-hash.js",
|
|
33
|
+
"types": "./lib/compute-body-hash.d.ts"
|
|
34
|
+
},
|
|
35
|
+
"./compute-url-sort-ranks": {
|
|
36
|
+
"import": "./lib/compute-url-sort-ranks.js",
|
|
37
|
+
"types": "./lib/compute-url-sort-ranks.d.ts"
|
|
38
|
+
},
|
|
39
|
+
"./create-isolated-cluster-run": {
|
|
40
|
+
"import": "./lib/create-isolated-cluster-run.js",
|
|
41
|
+
"types": "./lib/create-isolated-cluster-run.d.ts"
|
|
42
|
+
},
|
|
43
|
+
"./create-template-classification-run": {
|
|
44
|
+
"import": "./lib/create-template-classification-run.js",
|
|
45
|
+
"types": "./lib/create-template-classification-run.d.ts"
|
|
46
|
+
},
|
|
47
|
+
"./group-alias-candidates": {
|
|
48
|
+
"import": "./lib/group-alias-candidates.js",
|
|
49
|
+
"types": "./lib/group-alias-candidates.d.ts"
|
|
50
|
+
},
|
|
51
|
+
"./match-js-license-comment-signal": {
|
|
52
|
+
"import": "./lib/match-js-license-comment-signal.js",
|
|
53
|
+
"types": "./lib/match-js-license-comment-signal.d.ts"
|
|
54
|
+
},
|
|
55
|
+
"./match-selector-html": {
|
|
56
|
+
"import": "./lib/match-selector-html.js",
|
|
57
|
+
"types": "./lib/match-selector-html.d.ts"
|
|
58
|
+
},
|
|
59
|
+
"./match-selector-snapshots": {
|
|
60
|
+
"import": "./lib/match-selector-snapshots.js",
|
|
61
|
+
"types": "./lib/match-selector-snapshots.d.ts"
|
|
62
|
+
},
|
|
63
|
+
"./match-structural-technology-signals": {
|
|
64
|
+
"import": "./lib/match-structural-technology-signals.js",
|
|
65
|
+
"types": "./lib/match-structural-technology-signals.d.ts"
|
|
66
|
+
},
|
|
67
|
+
"./max-decoded-snapshot-bytes": {
|
|
68
|
+
"import": "./lib/max-decoded-snapshot-bytes.js",
|
|
69
|
+
"types": "./lib/max-decoded-snapshot-bytes.d.ts"
|
|
70
|
+
},
|
|
71
|
+
"./search-html-document": {
|
|
72
|
+
"import": "./lib/search-html-document.js",
|
|
73
|
+
"types": "./lib/search-html-document.d.ts"
|
|
74
|
+
},
|
|
75
|
+
"./search-html-snapshots": {
|
|
76
|
+
"import": "./lib/search-html-snapshots.js",
|
|
77
|
+
"types": "./lib/search-html-snapshots.d.ts"
|
|
78
|
+
},
|
|
79
|
+
"./validate-search-pattern": {
|
|
80
|
+
"import": "./lib/validate-search-pattern.js",
|
|
81
|
+
"types": "./lib/validate-search-pattern.d.ts"
|
|
82
|
+
},
|
|
83
|
+
"./template-exact-page-limit": {
|
|
84
|
+
"import": "./lib/template-exact-page-limit.js",
|
|
85
|
+
"types": "./lib/template-exact-page-limit.d.ts"
|
|
86
|
+
},
|
|
87
|
+
"./template-memory-budget": {
|
|
88
|
+
"import": "./lib/template-memory-budget.js",
|
|
89
|
+
"types": "./lib/template-memory-budget.d.ts"
|
|
90
|
+
},
|
|
91
|
+
"./template-block-sample-size": {
|
|
92
|
+
"import": "./lib/template-block-sample-size.js",
|
|
93
|
+
"types": "./lib/template-block-sample-size.d.ts"
|
|
94
|
+
},
|
|
95
|
+
"./types": {
|
|
96
|
+
"import": "./lib/types.js",
|
|
97
|
+
"types": "./lib/types.d.ts"
|
|
26
98
|
}
|
|
27
99
|
},
|
|
28
100
|
"scripts": {
|
|
29
|
-
"build": "tsc",
|
|
30
|
-
"clean": "tsc --build --clean"
|
|
101
|
+
"build": "node scripts/build-native.mjs && tsc",
|
|
102
|
+
"clean": "node scripts/build-native.mjs --clean && tsc --build --clean"
|
|
31
103
|
},
|
|
32
|
-
"
|
|
33
|
-
"@
|
|
34
|
-
"@
|
|
35
|
-
"@nitpicker/crawler": "0.24.0",
|
|
36
|
-
"@nitpicker/types": "0.24.0",
|
|
37
|
-
"ansi-colors": "4.1.3",
|
|
38
|
-
"cosmiconfig": "10.0.1",
|
|
39
|
-
"jsdom": "30.0.1"
|
|
104
|
+
"optionalDependencies": {
|
|
105
|
+
"@nitpicker/core-darwin-arm64": "0.25.1",
|
|
106
|
+
"@nitpicker/core-linux-x64-gnu": "0.25.1"
|
|
40
107
|
},
|
|
41
|
-
"gitHead": "
|
|
108
|
+
"gitHead": "fa839178ea8f40e92fc742e0480c6cfbbb8fb01f"
|
|
42
109
|
}
|
package/lib/core.d.ts
DELETED
package/lib/core.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Returns the standard set of `@nitpicker/analyze-*` plugins
|
|
4
|
-
* as {@link Plugin} entries with default (empty) settings.
|
|
5
|
-
*
|
|
6
|
-
* This is used as a fallback when no configuration file is found,
|
|
7
|
-
* allowing `nitpicker analyze` to work out of the box without
|
|
8
|
-
* requiring a `.nitpickerrc` file.
|
|
9
|
-
*
|
|
10
|
-
* All analyze plugins are treated as standard packages bundled
|
|
11
|
-
* with the CLI, so no filesystem scanning is necessary.
|
|
12
|
-
* @returns Array of standard analyze plugins with empty settings.
|
|
13
|
-
*/
|
|
14
|
-
export declare function discoverAnalyzePlugins(): Plugin[];
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standard analyze plugin module names bundled with the Nitpicker CLI.
|
|
3
|
-
*
|
|
4
|
-
* These are treated as built-in plugins and always available without
|
|
5
|
-
* explicit configuration.
|
|
6
|
-
*/
|
|
7
|
-
const STANDARD_ANALYZE_PLUGINS = [
|
|
8
|
-
'@nitpicker/analyze-axe',
|
|
9
|
-
'@nitpicker/analyze-markuplint',
|
|
10
|
-
'@nitpicker/analyze-search',
|
|
11
|
-
'@nitpicker/analyze-textlint',
|
|
12
|
-
];
|
|
13
|
-
/**
|
|
14
|
-
* Returns the standard set of `@nitpicker/analyze-*` plugins
|
|
15
|
-
* as {@link Plugin} entries with default (empty) settings.
|
|
16
|
-
*
|
|
17
|
-
* This is used as a fallback when no configuration file is found,
|
|
18
|
-
* allowing `nitpicker analyze` to work out of the box without
|
|
19
|
-
* requiring a `.nitpickerrc` file.
|
|
20
|
-
*
|
|
21
|
-
* All analyze plugins are treated as standard packages bundled
|
|
22
|
-
* with the CLI, so no filesystem scanning is necessary.
|
|
23
|
-
* @returns Array of standard analyze plugins with empty settings.
|
|
24
|
-
*/
|
|
25
|
-
export function discoverAnalyzePlugins() {
|
|
26
|
-
return STANDARD_ANALYZE_PLUGINS.map((moduleName) => ({
|
|
27
|
-
name: moduleName,
|
|
28
|
-
module: moduleName,
|
|
29
|
-
configFilePath: '',
|
|
30
|
-
settings: {},
|
|
31
|
-
}));
|
|
32
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolve the storage location for the analyze command's scratch `table`
|
|
3
|
-
* cache (per-page axe results, cleared at the start of every `analyze` run).
|
|
4
|
-
*
|
|
5
|
-
* Defined as a child of {@link getArchiveCacheRoot} so that
|
|
6
|
-
* `NITPICKER_TAR_CACHE_DIR` — which already redirects the tar-extraction
|
|
7
|
-
* cache — consistently redirects this cache too, instead of the two caches
|
|
8
|
-
* silently splitting across different roots.
|
|
9
|
-
* @returns Absolute path to the `table` cache directory. The `Cache` class
|
|
10
|
-
* creates a further subdirectory under this path named after its `name`
|
|
11
|
-
* argument.
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* const cache = new Cache('nitpicker-axe', getTableCacheRoot());
|
|
15
|
-
* await cache.clear();
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export declare function getTableCacheRoot(): string;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { getArchiveCacheRoot } from '@nitpicker/crawler';
|
|
3
|
-
/**
|
|
4
|
-
* Resolve the storage location for the analyze command's scratch `table`
|
|
5
|
-
* cache (per-page axe results, cleared at the start of every `analyze` run).
|
|
6
|
-
*
|
|
7
|
-
* Defined as a child of {@link getArchiveCacheRoot} so that
|
|
8
|
-
* `NITPICKER_TAR_CACHE_DIR` — which already redirects the tar-extraction
|
|
9
|
-
* cache — consistently redirects this cache too, instead of the two caches
|
|
10
|
-
* silently splitting across different roots.
|
|
11
|
-
* @returns Absolute path to the `table` cache directory. The `Cache` class
|
|
12
|
-
* creates a further subdirectory under this path named after its `name`
|
|
13
|
-
* argument.
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* const cache = new Cache('nitpicker-axe', getTableCacheRoot());
|
|
17
|
-
* await cache.clear();
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export function getTableCacheRoot() {
|
|
21
|
-
return path.join(getArchiveCacheRoot(), 'table');
|
|
22
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import type { PluginFactory } from '../types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Identity function that provides full type inference for analyze plugin definitions.
|
|
4
|
-
*
|
|
5
|
-
* This function does **nothing at runtime** - it returns its argument unchanged.
|
|
6
|
-
* Its sole purpose is to give TypeScript enough context to infer the generic
|
|
7
|
-
* parameters `O` (options type) and `T` (column key union) from the plugin
|
|
8
|
-
* implementation, without requiring explicit type annotations at the call site.
|
|
9
|
-
*
|
|
10
|
-
* ## Why an identity function?
|
|
11
|
-
*
|
|
12
|
-
* Without this wrapper, plugin authors would need to manually annotate the
|
|
13
|
-
* `PluginFactory` type with both generic parameters:
|
|
14
|
-
*
|
|
15
|
-
* ```ts
|
|
16
|
-
* // Without definePlugin - verbose and error-prone
|
|
17
|
-
* const factory: PluginFactory<{ lang: string }, 'score' | 'details'> = (options) => { ... };
|
|
18
|
-
* export default factory;
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* With `definePlugin`, TypeScript infers everything from the function body:
|
|
22
|
-
*
|
|
23
|
-
* ```ts
|
|
24
|
-
* // With definePlugin - concise and type-safe
|
|
25
|
-
* export default definePlugin(async (options: { lang: string }) => {
|
|
26
|
-
* return {
|
|
27
|
-
* label: 'Custom Analysis',
|
|
28
|
-
* headers: { score: 'Score', details: 'Details' },
|
|
29
|
-
* async eachPage({ window }) {
|
|
30
|
-
* return { page: { score: { value: 100 }, details: { value: 'OK' } } };
|
|
31
|
-
* },
|
|
32
|
-
* };
|
|
33
|
-
* });
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* This pattern is sometimes called a "satisfies helper" or "builder pattern"
|
|
37
|
-
* and is common in TypeScript libraries that need generic inference from
|
|
38
|
-
* function arguments (cf. Zod's `z.object()`, tRPC's `router()`).
|
|
39
|
-
* @template O - Shape of the plugin's settings/options from the config file.
|
|
40
|
-
* @template T - String literal union of column keys contributed by this plugin.
|
|
41
|
-
* @param factory - The plugin factory function to pass through.
|
|
42
|
-
* @returns The same function, unchanged.
|
|
43
|
-
* @example
|
|
44
|
-
* ```ts
|
|
45
|
-
* import { definePlugin } from '@nitpicker/core';
|
|
46
|
-
*
|
|
47
|
-
* type Options = { keywords: string[] };
|
|
48
|
-
*
|
|
49
|
-
* export default definePlugin(async (options: Options) => {
|
|
50
|
-
* return {
|
|
51
|
-
* label: 'キーワード検索',
|
|
52
|
-
* headers: { found: 'Keywords Found', count: 'Match Count' },
|
|
53
|
-
* async eachPage({ html }) {
|
|
54
|
-
* const matches = options.keywords.filter(k => html.includes(k));
|
|
55
|
-
* return {
|
|
56
|
-
* page: {
|
|
57
|
-
* found: { value: matches.join(', ') },
|
|
58
|
-
* count: { value: matches.length },
|
|
59
|
-
* },
|
|
60
|
-
* };
|
|
61
|
-
* },
|
|
62
|
-
* };
|
|
63
|
-
* });
|
|
64
|
-
* ```
|
|
65
|
-
* @see {@link ../types.ts!PluginFactory} for the function signature being wrapped
|
|
66
|
-
* @see {@link ../types.ts!AnalyzePlugin} for the returned plugin interface
|
|
67
|
-
*/
|
|
68
|
-
export declare function definePlugin<O, T extends string = string>(factory: PluginFactory<O, T>): PluginFactory<O, T>;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Identity function that provides full type inference for analyze plugin definitions.
|
|
3
|
-
*
|
|
4
|
-
* This function does **nothing at runtime** - it returns its argument unchanged.
|
|
5
|
-
* Its sole purpose is to give TypeScript enough context to infer the generic
|
|
6
|
-
* parameters `O` (options type) and `T` (column key union) from the plugin
|
|
7
|
-
* implementation, without requiring explicit type annotations at the call site.
|
|
8
|
-
*
|
|
9
|
-
* ## Why an identity function?
|
|
10
|
-
*
|
|
11
|
-
* Without this wrapper, plugin authors would need to manually annotate the
|
|
12
|
-
* `PluginFactory` type with both generic parameters:
|
|
13
|
-
*
|
|
14
|
-
* ```ts
|
|
15
|
-
* // Without definePlugin - verbose and error-prone
|
|
16
|
-
* const factory: PluginFactory<{ lang: string }, 'score' | 'details'> = (options) => { ... };
|
|
17
|
-
* export default factory;
|
|
18
|
-
* ```
|
|
19
|
-
*
|
|
20
|
-
* With `definePlugin`, TypeScript infers everything from the function body:
|
|
21
|
-
*
|
|
22
|
-
* ```ts
|
|
23
|
-
* // With definePlugin - concise and type-safe
|
|
24
|
-
* export default definePlugin(async (options: { lang: string }) => {
|
|
25
|
-
* return {
|
|
26
|
-
* label: 'Custom Analysis',
|
|
27
|
-
* headers: { score: 'Score', details: 'Details' },
|
|
28
|
-
* async eachPage({ window }) {
|
|
29
|
-
* return { page: { score: { value: 100 }, details: { value: 'OK' } } };
|
|
30
|
-
* },
|
|
31
|
-
* };
|
|
32
|
-
* });
|
|
33
|
-
* ```
|
|
34
|
-
*
|
|
35
|
-
* This pattern is sometimes called a "satisfies helper" or "builder pattern"
|
|
36
|
-
* and is common in TypeScript libraries that need generic inference from
|
|
37
|
-
* function arguments (cf. Zod's `z.object()`, tRPC's `router()`).
|
|
38
|
-
* @template O - Shape of the plugin's settings/options from the config file.
|
|
39
|
-
* @template T - String literal union of column keys contributed by this plugin.
|
|
40
|
-
* @param factory - The plugin factory function to pass through.
|
|
41
|
-
* @returns The same function, unchanged.
|
|
42
|
-
* @example
|
|
43
|
-
* ```ts
|
|
44
|
-
* import { definePlugin } from '@nitpicker/core';
|
|
45
|
-
*
|
|
46
|
-
* type Options = { keywords: string[] };
|
|
47
|
-
*
|
|
48
|
-
* export default definePlugin(async (options: Options) => {
|
|
49
|
-
* return {
|
|
50
|
-
* label: 'キーワード検索',
|
|
51
|
-
* headers: { found: 'Keywords Found', count: 'Match Count' },
|
|
52
|
-
* async eachPage({ html }) {
|
|
53
|
-
* const matches = options.keywords.filter(k => html.includes(k));
|
|
54
|
-
* return {
|
|
55
|
-
* page: {
|
|
56
|
-
* found: { value: matches.join(', ') },
|
|
57
|
-
* count: { value: matches.length },
|
|
58
|
-
* },
|
|
59
|
-
* };
|
|
60
|
-
* },
|
|
61
|
-
* };
|
|
62
|
-
* });
|
|
63
|
-
* ```
|
|
64
|
-
* @see {@link ../types.ts!PluginFactory} for the function signature being wrapped
|
|
65
|
-
* @see {@link ../types.ts!AnalyzePlugin} for the returned plugin interface
|
|
66
|
-
*/
|
|
67
|
-
export function definePlugin(factory) {
|
|
68
|
-
return factory;
|
|
69
|
-
}
|
package/lib/import-modules.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { AnalyzePlugin, Plugin } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Dynamically imports and initializes all analyze plugin modules.
|
|
4
|
-
*
|
|
5
|
-
* For each plugin in the list:
|
|
6
|
-
* 1. Validates that `plugin.module` starts with `@nitpicker/analyze-`
|
|
7
|
-
* 2. Calls `import(plugin.module)` to load the npm package
|
|
8
|
-
* 3. Invokes the module's default export (a `PluginFactory` factory)
|
|
9
|
-
* with the plugin's `settings`
|
|
10
|
-
* 4. Returns the resulting `AnalyzePlugin` instance
|
|
11
|
-
*
|
|
12
|
-
* All plugins are loaded in parallel via `Promise.all` for performance.
|
|
13
|
-
*
|
|
14
|
-
* This function is called both in the main thread (for `headers` and `eachUrl`)
|
|
15
|
-
* and inside each Worker thread (for `eachPage`). The Worker-side call is
|
|
16
|
-
* necessary because plugin modules may not be transferable across threads.
|
|
17
|
-
* @param plugins - Array of plugin definitions from the resolved config.
|
|
18
|
-
* @returns Array of initialized `AnalyzePlugin` instances, in the same order.
|
|
19
|
-
* @throws {Error} If any plugin module name does not start with `@nitpicker/analyze-`.
|
|
20
|
-
* @see {@link ./types.ts} for the `PluginFactory` factory function signature
|
|
21
|
-
* @see {@link ./page-analysis-worker.ts} for Worker-side usage
|
|
22
|
-
* @see {@link ./nitpicker.ts!Nitpicker.analyze} for main-thread usage
|
|
23
|
-
*/
|
|
24
|
-
export declare function importModules(plugins: Plugin[]): Promise<AnalyzePlugin<string>[]>;
|
package/lib/import-modules.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Allowed prefix for analyze plugin module names.
|
|
3
|
-
* Only modules starting with this prefix are permitted to be dynamically imported.
|
|
4
|
-
*/
|
|
5
|
-
const ALLOWED_PREFIX = '@nitpicker/analyze-';
|
|
6
|
-
/**
|
|
7
|
-
* Dynamically imports and initializes all analyze plugin modules.
|
|
8
|
-
*
|
|
9
|
-
* For each plugin in the list:
|
|
10
|
-
* 1. Validates that `plugin.module` starts with `@nitpicker/analyze-`
|
|
11
|
-
* 2. Calls `import(plugin.module)` to load the npm package
|
|
12
|
-
* 3. Invokes the module's default export (a `PluginFactory` factory)
|
|
13
|
-
* with the plugin's `settings`
|
|
14
|
-
* 4. Returns the resulting `AnalyzePlugin` instance
|
|
15
|
-
*
|
|
16
|
-
* All plugins are loaded in parallel via `Promise.all` for performance.
|
|
17
|
-
*
|
|
18
|
-
* This function is called both in the main thread (for `headers` and `eachUrl`)
|
|
19
|
-
* and inside each Worker thread (for `eachPage`). The Worker-side call is
|
|
20
|
-
* necessary because plugin modules may not be transferable across threads.
|
|
21
|
-
* @param plugins - Array of plugin definitions from the resolved config.
|
|
22
|
-
* @returns Array of initialized `AnalyzePlugin` instances, in the same order.
|
|
23
|
-
* @throws {Error} If any plugin module name does not start with `@nitpicker/analyze-`.
|
|
24
|
-
* @see {@link ./types.ts} for the `PluginFactory` factory function signature
|
|
25
|
-
* @see {@link ./page-analysis-worker.ts} for Worker-side usage
|
|
26
|
-
* @see {@link ./nitpicker.ts!Nitpicker.analyze} for main-thread usage
|
|
27
|
-
*/
|
|
28
|
-
export async function importModules(plugins) {
|
|
29
|
-
const analyzeMods = await Promise.all(plugins.map(async (plugin) => {
|
|
30
|
-
if (!plugin.module.startsWith(ALLOWED_PREFIX)) {
|
|
31
|
-
throw new Error(`Unauthorized plugin module: "${plugin.module}". Plugin modules must start with "${ALLOWED_PREFIX}".`);
|
|
32
|
-
}
|
|
33
|
-
const mod = await import(plugin.module);
|
|
34
|
-
const factory = mod.default;
|
|
35
|
-
return factory(plugin.settings);
|
|
36
|
-
}));
|
|
37
|
-
return analyzeMods;
|
|
38
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { Config, PluginOverrides } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Loads the analyze plugin configuration from the user's config file.
|
|
4
|
-
*
|
|
5
|
-
* Uses cosmiconfig to search the filesystem from `process.cwd()` upward
|
|
6
|
-
* for a Nitpicker configuration file. The external config format
|
|
7
|
-
* (`ConfigJSON` from `@nitpicker/types`) is normalized into the internal
|
|
8
|
-
* {@link Config} model:
|
|
9
|
-
*
|
|
10
|
-
* - `config.plugins.analyze` (object keyed by module name with settings)
|
|
11
|
-
* is converted to an ordered `Plugin[]` array
|
|
12
|
-
* - Boolean `true` settings are normalized to empty objects `{}`
|
|
13
|
-
* - The config file path is attached to each plugin for relative path resolution
|
|
14
|
-
* @param defaultConfig - Optional partial config to merge as defaults.
|
|
15
|
-
* Plugin lists are concatenated (defaults first, then discovered plugins).
|
|
16
|
-
* @param pluginOverrides - CLI-specified plugin setting overrides.
|
|
17
|
-
* Values are shallow-merged into the matching plugin's settings,
|
|
18
|
-
* with CLI values taking precedence over config-file values.
|
|
19
|
-
* @returns Fully resolved {@link Config} with the `analyze` plugin list.
|
|
20
|
-
* @example
|
|
21
|
-
* ```ts
|
|
22
|
-
* // .nitpickerrc.json
|
|
23
|
-
* // {
|
|
24
|
-
* // "plugins": {
|
|
25
|
-
* // "analyze": {
|
|
26
|
-
* // "@nitpicker/analyze-axe": { "lang": "ja" },
|
|
27
|
-
* // "@nitpicker/analyze-markuplint": true
|
|
28
|
-
* // }
|
|
29
|
-
* // }
|
|
30
|
-
* // }
|
|
31
|
-
*
|
|
32
|
-
* const config = await loadPluginSettings();
|
|
33
|
-
* // config.analyze = [
|
|
34
|
-
* // { name: '@nitpicker/analyze-axe', module: '@nitpicker/analyze-axe',
|
|
35
|
-
* // configFilePath: '/path/to/.nitpickerrc.json', settings: { lang: 'ja' } },
|
|
36
|
-
* // { name: '@nitpicker/analyze-markuplint', module: '@nitpicker/analyze-markuplint',
|
|
37
|
-
* // configFilePath: '/path/to/.nitpickerrc.json', settings: {} },
|
|
38
|
-
* // ]
|
|
39
|
-
* ```
|
|
40
|
-
* @see {@link ./types.ts!Config} for the output type
|
|
41
|
-
* @see {@link ./types.ts!Plugin} for individual plugin entries
|
|
42
|
-
* @see {@link ./types.ts!PluginOverrides} for CLI override support
|
|
43
|
-
*/
|
|
44
|
-
export declare function loadPluginSettings(defaultConfig?: Partial<Config>, pluginOverrides?: PluginOverrides): Promise<Config>;
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { cosmiconfig } from 'cosmiconfig';
|
|
2
|
-
import { discoverAnalyzePlugins } from './discover-analyze-plugins.js';
|
|
3
|
-
/**
|
|
4
|
-
* The cosmiconfig module name used for config file discovery.
|
|
5
|
-
* Searches for: `.nitpickerrc`, `.nitpickerrc.json`, `.nitpickerrc.yaml`,
|
|
6
|
-
* `nitpicker.config.js`, `nitpicker.config.cjs`, or a `"nitpicker"` key
|
|
7
|
-
* in `package.json`.
|
|
8
|
-
*/
|
|
9
|
-
const MODULE_NAME = 'nitpicker';
|
|
10
|
-
/**
|
|
11
|
-
* Loads the analyze plugin configuration from the user's config file.
|
|
12
|
-
*
|
|
13
|
-
* Uses cosmiconfig to search the filesystem from `process.cwd()` upward
|
|
14
|
-
* for a Nitpicker configuration file. The external config format
|
|
15
|
-
* (`ConfigJSON` from `@nitpicker/types`) is normalized into the internal
|
|
16
|
-
* {@link Config} model:
|
|
17
|
-
*
|
|
18
|
-
* - `config.plugins.analyze` (object keyed by module name with settings)
|
|
19
|
-
* is converted to an ordered `Plugin[]` array
|
|
20
|
-
* - Boolean `true` settings are normalized to empty objects `{}`
|
|
21
|
-
* - The config file path is attached to each plugin for relative path resolution
|
|
22
|
-
* @param defaultConfig - Optional partial config to merge as defaults.
|
|
23
|
-
* Plugin lists are concatenated (defaults first, then discovered plugins).
|
|
24
|
-
* @param pluginOverrides - CLI-specified plugin setting overrides.
|
|
25
|
-
* Values are shallow-merged into the matching plugin's settings,
|
|
26
|
-
* with CLI values taking precedence over config-file values.
|
|
27
|
-
* @returns Fully resolved {@link Config} with the `analyze` plugin list.
|
|
28
|
-
* @example
|
|
29
|
-
* ```ts
|
|
30
|
-
* // .nitpickerrc.json
|
|
31
|
-
* // {
|
|
32
|
-
* // "plugins": {
|
|
33
|
-
* // "analyze": {
|
|
34
|
-
* // "@nitpicker/analyze-axe": { "lang": "ja" },
|
|
35
|
-
* // "@nitpicker/analyze-markuplint": true
|
|
36
|
-
* // }
|
|
37
|
-
* // }
|
|
38
|
-
* // }
|
|
39
|
-
*
|
|
40
|
-
* const config = await loadPluginSettings();
|
|
41
|
-
* // config.analyze = [
|
|
42
|
-
* // { name: '@nitpicker/analyze-axe', module: '@nitpicker/analyze-axe',
|
|
43
|
-
* // configFilePath: '/path/to/.nitpickerrc.json', settings: { lang: 'ja' } },
|
|
44
|
-
* // { name: '@nitpicker/analyze-markuplint', module: '@nitpicker/analyze-markuplint',
|
|
45
|
-
* // configFilePath: '/path/to/.nitpickerrc.json', settings: {} },
|
|
46
|
-
* // ]
|
|
47
|
-
* ```
|
|
48
|
-
* @see {@link ./types.ts!Config} for the output type
|
|
49
|
-
* @see {@link ./types.ts!Plugin} for individual plugin entries
|
|
50
|
-
* @see {@link ./types.ts!PluginOverrides} for CLI override support
|
|
51
|
-
*/
|
|
52
|
-
export async function loadPluginSettings(defaultConfig = {}, pluginOverrides = {}) {
|
|
53
|
-
const explorer = cosmiconfig(MODULE_NAME);
|
|
54
|
-
const result = await explorer.search();
|
|
55
|
-
if (!result) {
|
|
56
|
-
const defaultPlugins = defaultConfig.analyze || [];
|
|
57
|
-
const plugins = defaultPlugins.length > 0 ? defaultPlugins : discoverAnalyzePlugins();
|
|
58
|
-
return {
|
|
59
|
-
analyze: applyPluginOverrides(plugins, pluginOverrides),
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
const config = result.config;
|
|
63
|
-
const { isEmpty, filepath } = result;
|
|
64
|
-
if (!config || isEmpty) {
|
|
65
|
-
const defaultPlugins = defaultConfig.analyze || [];
|
|
66
|
-
const plugins = defaultPlugins.length > 0 ? defaultPlugins : discoverAnalyzePlugins();
|
|
67
|
-
return {
|
|
68
|
-
analyze: applyPluginOverrides(plugins, pluginOverrides),
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
const analyzePlugins = [];
|
|
72
|
-
if (config.plugins && config.plugins.analyze) {
|
|
73
|
-
const moduleNames = Object.keys(config.plugins.analyze);
|
|
74
|
-
for (const name of moduleNames) {
|
|
75
|
-
if (!config.plugins.analyze[name]) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
const settings = config.plugins.analyze[name] === true ? {} : config.plugins.analyze[name];
|
|
79
|
-
analyzePlugins.push({
|
|
80
|
-
name,
|
|
81
|
-
module: name,
|
|
82
|
-
configFilePath: filepath,
|
|
83
|
-
settings,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
const mergedPlugins = [...(defaultConfig.analyze || []), ...analyzePlugins];
|
|
88
|
-
const finalPlugins = mergedPlugins.length > 0 ? mergedPlugins : discoverAnalyzePlugins();
|
|
89
|
-
return {
|
|
90
|
-
analyze: applyPluginOverrides(finalPlugins, pluginOverrides),
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Applies CLI-specified overrides to plugin settings.
|
|
95
|
-
*
|
|
96
|
-
* For each plugin in the list, if there is a matching entry in
|
|
97
|
-
* `overrides`, the override values are shallow-merged into the
|
|
98
|
-
* plugin's existing settings. CLI values take precedence over
|
|
99
|
-
* config-file values.
|
|
100
|
-
*
|
|
101
|
-
* **Limitation**: Merging is shallow (one level). Nested objects in
|
|
102
|
-
* the override will replace the entire config-file value, not deep-merge.
|
|
103
|
-
* @param plugins - The plugin list to apply overrides to.
|
|
104
|
-
* @param overrides - CLI-specified plugin setting overrides.
|
|
105
|
-
* @returns A new plugin array with overrides applied.
|
|
106
|
-
*/
|
|
107
|
-
function applyPluginOverrides(plugins, overrides) {
|
|
108
|
-
const overrideKeys = Object.keys(overrides);
|
|
109
|
-
if (overrideKeys.length === 0) {
|
|
110
|
-
return plugins;
|
|
111
|
-
}
|
|
112
|
-
return plugins.map((plugin) => {
|
|
113
|
-
const override = overrides[plugin.module];
|
|
114
|
-
if (!override) {
|
|
115
|
-
return plugin;
|
|
116
|
-
}
|
|
117
|
-
return {
|
|
118
|
-
...plugin,
|
|
119
|
-
settings: {
|
|
120
|
-
...plugin.settings,
|
|
121
|
-
...override,
|
|
122
|
-
},
|
|
123
|
-
};
|
|
124
|
-
});
|
|
125
|
-
}
|