eslint-plugin-harlanzw 0.14.0 → 0.14.2
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 +5 -1
- package/dist/index.mjs +27 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -76,10 +76,12 @@ The rules are organized into the following categories:
|
|
|
76
76
|
| [`ai-deslop-false-dichotomy`](./src/prompt/rules/deslop-false-dichotomy.ts) | flag "it's not X, it's Y" contrast patterns common in AI writing |
|
|
77
77
|
| [`ai-deslop-filler`](./src/prompt/rules/deslop-filler.ts) | remove AI-generated filler sentences and phrases (e.g. "it's worth noting that") |
|
|
78
78
|
| [`ai-deslop-hedging`](./src/prompt/rules/deslop-hedging.ts) | remove hedging/qualifying words that weaken copy (e.g. "very", "really", "quite", "just") |
|
|
79
|
+
| [`ai-deslop-no-em-dash`](./src/prompt/rules/deslop-no-em-dash.ts) | replace em dashes in content prose |
|
|
79
80
|
| [`ai-deslop-no-exclamation`](./src/prompt/rules/deslop-no-exclamation.ts) | remove exclamation marks from content prose |
|
|
80
81
|
| [`ai-deslop-passive-voice`](./src/prompt/rules/deslop-passive-voice.ts) | flag passive voice constructions (e.g. "is generated" → rewrite in active voice) |
|
|
81
82
|
| [`ai-deslop-weak-opener`](./src/prompt/rules/deslop-weak-opener.ts) | flag weak sentence openers like "There is" and "It is possible to" |
|
|
82
83
|
| [`ai-deslop-frontmatter-spacing`](./src/prompt/rules/deslop-frontmatter-spacing.ts) | remove empty lines inside YAML frontmatter |
|
|
84
|
+
| [`ai-deslop-code-lang`](./src/prompt/rules/deslop-code-lang.ts) | require language hints on fenced code examples |
|
|
83
85
|
| [`ai-deslop-vue-ts-lang`](./src/prompt/rules/deslop-vue-ts-lang.ts) | require `lang="ts"` on Vue `<script>` blocks in code examples |
|
|
84
86
|
| **pnpm** | |
|
|
85
87
|
| [`pnpm-require-trust-policy`](./src/prompt/rules/pnpm-require-trust-policy.ts) | require `trustPolicyIgnoreAfter: 262800` in `pnpm-workspace.yaml` |
|
|
@@ -180,7 +182,7 @@ export default [
|
|
|
180
182
|
|
|
181
183
|
### AI Deslop Rules
|
|
182
184
|
|
|
183
|
-
|
|
185
|
+
14 rules for cleaning AI-generated slop from your content markdown files (`content/**/*.md`). Most rules are auto-fixable.
|
|
184
186
|
|
|
185
187
|
```js
|
|
186
188
|
// eslint.config.js
|
|
@@ -208,10 +210,12 @@ export default [
|
|
|
208
210
|
| `ai-deslop-autolink` | Links first mention of tech terms to their canonical URLs ("Nuxt" → `[Nuxt](https://nuxt.com)`) |
|
|
209
211
|
| `ai-deslop-false-dichotomy` | Flags "it's not X, it's Y" false contrast patterns |
|
|
210
212
|
| `ai-deslop-hedging` | Strips hedging words that weaken copy ("very", "really", "quite", "just", "somewhat") |
|
|
213
|
+
| `ai-deslop-no-em-dash` | Replaces em dashes in content prose |
|
|
211
214
|
| `ai-deslop-no-exclamation` | Replaces exclamation marks with periods in content prose |
|
|
212
215
|
| `ai-deslop-passive-voice` | Flags passive voice ("is generated", "was created") for active rewriting |
|
|
213
216
|
| `ai-deslop-weak-opener` | Flags weak expletive openers ("There is", "It is possible to") |
|
|
214
217
|
| `ai-deslop-frontmatter-spacing` | Removes empty lines inside YAML frontmatter blocks |
|
|
218
|
+
| `ai-deslop-code-lang` | Adds language hints to fenced code blocks |
|
|
215
219
|
| `ai-deslop-vue-ts-lang` | Adds `lang="ts"` to Vue `<script>` blocks in code examples |
|
|
216
220
|
|
|
217
221
|
### Prompt Rules
|
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import process from 'node:process';
|
|
|
4
4
|
import { TextSourceCodeBase, ConfigCommentParser, Directive, VisitNodeStep } from '@eslint/plugin-kit';
|
|
5
5
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
6
6
|
|
|
7
|
-
const version = "0.14.
|
|
7
|
+
const version = "0.14.2";
|
|
8
8
|
|
|
9
9
|
const STRENGTH_PATTERNS = {
|
|
10
10
|
strong: ["never", "must", "always", "under no circumstances", "absolutely", "required", "mandatory", "forbidden", "prohibited"],
|
|
@@ -3518,7 +3518,20 @@ const VUE_REACTIVITY_APIS = /* @__PURE__ */ new Set([
|
|
|
3518
3518
|
// Dependency injection (composition-context only)
|
|
3519
3519
|
"provide",
|
|
3520
3520
|
"inject",
|
|
3521
|
-
"hasInjectionContext"
|
|
3521
|
+
"hasInjectionContext",
|
|
3522
|
+
// Lifecycle hooks (composition-context only)
|
|
3523
|
+
"onBeforeMount",
|
|
3524
|
+
"onMounted",
|
|
3525
|
+
"onBeforeUpdate",
|
|
3526
|
+
"onUpdated",
|
|
3527
|
+
"onBeforeUnmount",
|
|
3528
|
+
"onUnmounted",
|
|
3529
|
+
"onActivated",
|
|
3530
|
+
"onDeactivated",
|
|
3531
|
+
"onErrorCaptured",
|
|
3532
|
+
"onRenderTracked",
|
|
3533
|
+
"onRenderTriggered",
|
|
3534
|
+
"onServerPrefetch"
|
|
3522
3535
|
]);
|
|
3523
3536
|
const VUEUSE_REACTIVITY_APIS = /* @__PURE__ */ new Set([
|
|
3524
3537
|
// Watch variants
|
|
@@ -3653,9 +3666,9 @@ const COMPOSABLE_RE = /^_?use[A-Z_]/;
|
|
|
3653
3666
|
const NON_REACTIVE_COMPOSABLE_CALLS = /* @__PURE__ */ new Set([
|
|
3654
3667
|
"useNuxtApp"
|
|
3655
3668
|
]);
|
|
3656
|
-
function isComposableCall(node) {
|
|
3669
|
+
function isComposableCall(node, options = {}) {
|
|
3657
3670
|
if (node.callee.type === "Identifier") {
|
|
3658
|
-
return COMPOSABLE_RE.test(node.callee.name) && !NON_REACTIVE_COMPOSABLE_CALLS.has(node.callee.name);
|
|
3671
|
+
return COMPOSABLE_RE.test(node.callee.name) && (options.countNuxtAppAsComposable || !NON_REACTIVE_COMPOSABLE_CALLS.has(node.callee.name));
|
|
3659
3672
|
}
|
|
3660
3673
|
return false;
|
|
3661
3674
|
}
|
|
@@ -3692,7 +3705,7 @@ function trackNonVueImports(node, nonVueImports) {
|
|
|
3692
3705
|
}
|
|
3693
3706
|
}
|
|
3694
3707
|
}
|
|
3695
|
-
function createReactivityChecker(vueImports, nonVueImports) {
|
|
3708
|
+
function createReactivityChecker(vueImports, nonVueImports, options = {}) {
|
|
3696
3709
|
function isAutoImportedReactivityCall(node) {
|
|
3697
3710
|
if (node.callee.type === "Identifier") {
|
|
3698
3711
|
const name = node.callee.name;
|
|
@@ -3708,7 +3721,7 @@ function createReactivityChecker(vueImports, nonVueImports) {
|
|
|
3708
3721
|
return false;
|
|
3709
3722
|
switch (expr.type) {
|
|
3710
3723
|
case "CallExpression":
|
|
3711
|
-
if (isReactivityCall(expr, vueImports) || isAutoImportedReactivityCall(expr) || isComposableCall(expr) || isReactiveLifecycleCall(expr))
|
|
3724
|
+
if (isReactivityCall(expr, vueImports) || isAutoImportedReactivityCall(expr) || isComposableCall(expr, options) || isReactiveLifecycleCall(expr))
|
|
3712
3725
|
return true;
|
|
3713
3726
|
return expr.arguments.some((arg) => hasReactivityInArg(arg));
|
|
3714
3727
|
case "NewExpression":
|
|
@@ -5799,6 +5812,7 @@ const vueNoAsyncLifecycleHook = createEslintRule({
|
|
|
5799
5812
|
});
|
|
5800
5813
|
|
|
5801
5814
|
const RULE_NAME$9 = "vue-no-faux-composables";
|
|
5815
|
+
const SERVER_RE = /(?:^|[/\\])server[/\\]/;
|
|
5802
5816
|
const vueNoFauxComposables = createEslintRule({
|
|
5803
5817
|
name: RULE_NAME$9,
|
|
5804
5818
|
meta: {
|
|
@@ -5814,12 +5828,14 @@ const vueNoFauxComposables = createEslintRule({
|
|
|
5814
5828
|
defaultOptions: [],
|
|
5815
5829
|
create: (context) => {
|
|
5816
5830
|
const filename = context.filename || context.getFilename();
|
|
5817
|
-
if (filename.endsWith(".vue"))
|
|
5831
|
+
if (filename.endsWith(".vue") || SERVER_RE.test(filename))
|
|
5818
5832
|
return {};
|
|
5819
5833
|
const vueImports = /* @__PURE__ */ new Set();
|
|
5820
5834
|
const nonVueImports = /* @__PURE__ */ new Set();
|
|
5821
5835
|
const composableFunctions = /* @__PURE__ */ new Map();
|
|
5822
|
-
const { hasReactivityInStatement, hasReactivityInExpression } = createReactivityChecker(vueImports, nonVueImports
|
|
5836
|
+
const { hasReactivityInStatement, hasReactivityInExpression } = createReactivityChecker(vueImports, nonVueImports, {
|
|
5837
|
+
countNuxtAppAsComposable: true
|
|
5838
|
+
});
|
|
5823
5839
|
function checkFunctionForReactivity(functionNode, functionName) {
|
|
5824
5840
|
if (!functionNode.body)
|
|
5825
5841
|
return;
|
|
@@ -6720,6 +6736,8 @@ const REGEX_1 = /[/\\]composables[/\\]/;
|
|
|
6720
6736
|
const RULE_NAME = "vue-require-composable-prefix";
|
|
6721
6737
|
const DEFINE_RE = /^define[A-Z]/;
|
|
6722
6738
|
const CREATE_RE = /^create[A-Z]/;
|
|
6739
|
+
const PROVIDE_RE = /^provide[A-Z]/;
|
|
6740
|
+
const INJECT_RE = /^inject[A-Z]/;
|
|
6723
6741
|
const vueRequireComposablePrefix = createEslintRule({
|
|
6724
6742
|
name: RULE_NAME,
|
|
6725
6743
|
meta: {
|
|
@@ -6743,7 +6761,7 @@ const vueRequireComposablePrefix = createEslintRule({
|
|
|
6743
6761
|
const candidateFunctions = /* @__PURE__ */ new Map();
|
|
6744
6762
|
const { hasReactivityInStatement, hasReactivityInExpression } = createReactivityChecker(vueImports, nonVueImports);
|
|
6745
6763
|
function isExcludedName(name) {
|
|
6746
|
-
return DEFINE_RE.test(name) || CREATE_RE.test(name) || name === "setup";
|
|
6764
|
+
return DEFINE_RE.test(name) || CREATE_RE.test(name) || PROVIDE_RE.test(name) || INJECT_RE.test(name) || name === "setup";
|
|
6747
6765
|
}
|
|
6748
6766
|
function checkFunctionForReactivity(functionNode, idNode, functionName) {
|
|
6749
6767
|
if (!functionNode.body)
|