oxlint-plugin-react-doctor 0.3.0-dev.9a8ad6e → 0.4.0-dev.a5c6993
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/dist/index.d.ts +266 -0
- package/dist/index.js +321 -40
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1829,6 +1829,44 @@ declare const REACT_DOCTOR_RULES: readonly [{
|
|
|
1829
1829
|
readonly recommendation?: string;
|
|
1830
1830
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
1831
1831
|
};
|
|
1832
|
+
}, {
|
|
1833
|
+
readonly key: "react-doctor/nextjs-error-boundary-missing-use-client";
|
|
1834
|
+
readonly id: "nextjs-error-boundary-missing-use-client";
|
|
1835
|
+
readonly source: "react-doctor";
|
|
1836
|
+
readonly originallyExternal: false;
|
|
1837
|
+
readonly rule: {
|
|
1838
|
+
readonly framework: "nextjs";
|
|
1839
|
+
readonly category: "Bugs";
|
|
1840
|
+
readonly id: string;
|
|
1841
|
+
readonly title?: string;
|
|
1842
|
+
readonly severity: RuleSeverity;
|
|
1843
|
+
readonly requires?: ReadonlyArray<string>;
|
|
1844
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
1845
|
+
readonly tags?: ReadonlyArray<string>;
|
|
1846
|
+
readonly defaultEnabled?: boolean;
|
|
1847
|
+
readonly lifecycle?: "retired";
|
|
1848
|
+
readonly recommendation?: string;
|
|
1849
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
1850
|
+
};
|
|
1851
|
+
}, {
|
|
1852
|
+
readonly key: "react-doctor/nextjs-global-error-missing-html-body";
|
|
1853
|
+
readonly id: "nextjs-global-error-missing-html-body";
|
|
1854
|
+
readonly source: "react-doctor";
|
|
1855
|
+
readonly originallyExternal: false;
|
|
1856
|
+
readonly rule: {
|
|
1857
|
+
readonly framework: "nextjs";
|
|
1858
|
+
readonly category: "Bugs";
|
|
1859
|
+
readonly id: string;
|
|
1860
|
+
readonly title?: string;
|
|
1861
|
+
readonly severity: RuleSeverity;
|
|
1862
|
+
readonly requires?: ReadonlyArray<string>;
|
|
1863
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
1864
|
+
readonly tags?: ReadonlyArray<string>;
|
|
1865
|
+
readonly defaultEnabled?: boolean;
|
|
1866
|
+
readonly lifecycle?: "retired";
|
|
1867
|
+
readonly recommendation?: string;
|
|
1868
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
1869
|
+
};
|
|
1832
1870
|
}, {
|
|
1833
1871
|
readonly key: "react-doctor/nextjs-image-missing-sizes";
|
|
1834
1872
|
readonly id: "nextjs-image-missing-sizes";
|
|
@@ -1962,6 +2000,44 @@ declare const REACT_DOCTOR_RULES: readonly [{
|
|
|
1962
2000
|
readonly recommendation?: string;
|
|
1963
2001
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
1964
2002
|
};
|
|
2003
|
+
}, {
|
|
2004
|
+
readonly key: "react-doctor/nextjs-no-default-export-in-route-handler";
|
|
2005
|
+
readonly id: "nextjs-no-default-export-in-route-handler";
|
|
2006
|
+
readonly source: "react-doctor";
|
|
2007
|
+
readonly originallyExternal: false;
|
|
2008
|
+
readonly rule: {
|
|
2009
|
+
readonly framework: "nextjs";
|
|
2010
|
+
readonly category: "Bugs";
|
|
2011
|
+
readonly id: string;
|
|
2012
|
+
readonly title?: string;
|
|
2013
|
+
readonly severity: RuleSeverity;
|
|
2014
|
+
readonly requires?: ReadonlyArray<string>;
|
|
2015
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
2016
|
+
readonly tags?: ReadonlyArray<string>;
|
|
2017
|
+
readonly defaultEnabled?: boolean;
|
|
2018
|
+
readonly lifecycle?: "retired";
|
|
2019
|
+
readonly recommendation?: string;
|
|
2020
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
2021
|
+
};
|
|
2022
|
+
}, {
|
|
2023
|
+
readonly key: "react-doctor/nextjs-no-edge-og-runtime";
|
|
2024
|
+
readonly id: "nextjs-no-edge-og-runtime";
|
|
2025
|
+
readonly source: "react-doctor";
|
|
2026
|
+
readonly originallyExternal: false;
|
|
2027
|
+
readonly rule: {
|
|
2028
|
+
readonly framework: "nextjs";
|
|
2029
|
+
readonly category: "Bugs";
|
|
2030
|
+
readonly id: string;
|
|
2031
|
+
readonly title?: string;
|
|
2032
|
+
readonly severity: RuleSeverity;
|
|
2033
|
+
readonly requires?: ReadonlyArray<string>;
|
|
2034
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
2035
|
+
readonly tags?: ReadonlyArray<string>;
|
|
2036
|
+
readonly defaultEnabled?: boolean;
|
|
2037
|
+
readonly lifecycle?: "retired";
|
|
2038
|
+
readonly recommendation?: string;
|
|
2039
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
2040
|
+
};
|
|
1965
2041
|
}, {
|
|
1966
2042
|
readonly key: "react-doctor/nextjs-no-font-link";
|
|
1967
2043
|
readonly id: "nextjs-no-font-link";
|
|
@@ -1981,6 +2057,25 @@ declare const REACT_DOCTOR_RULES: readonly [{
|
|
|
1981
2057
|
readonly recommendation?: string;
|
|
1982
2058
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
1983
2059
|
};
|
|
2060
|
+
}, {
|
|
2061
|
+
readonly key: "react-doctor/nextjs-no-google-analytics-script";
|
|
2062
|
+
readonly id: "nextjs-no-google-analytics-script";
|
|
2063
|
+
readonly source: "react-doctor";
|
|
2064
|
+
readonly originallyExternal: false;
|
|
2065
|
+
readonly rule: {
|
|
2066
|
+
readonly framework: "nextjs";
|
|
2067
|
+
readonly category: "Bugs";
|
|
2068
|
+
readonly id: string;
|
|
2069
|
+
readonly title?: string;
|
|
2070
|
+
readonly severity: RuleSeverity;
|
|
2071
|
+
readonly requires?: ReadonlyArray<string>;
|
|
2072
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
2073
|
+
readonly tags?: ReadonlyArray<string>;
|
|
2074
|
+
readonly defaultEnabled?: boolean;
|
|
2075
|
+
readonly lifecycle?: "retired";
|
|
2076
|
+
readonly recommendation?: string;
|
|
2077
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
2078
|
+
};
|
|
1984
2079
|
}, {
|
|
1985
2080
|
readonly key: "react-doctor/nextjs-no-head-import";
|
|
1986
2081
|
readonly id: "nextjs-no-head-import";
|
|
@@ -2076,6 +2171,25 @@ declare const REACT_DOCTOR_RULES: readonly [{
|
|
|
2076
2171
|
readonly recommendation?: string;
|
|
2077
2172
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
2078
2173
|
};
|
|
2174
|
+
}, {
|
|
2175
|
+
readonly key: "react-doctor/nextjs-no-script-in-head";
|
|
2176
|
+
readonly id: "nextjs-no-script-in-head";
|
|
2177
|
+
readonly source: "react-doctor";
|
|
2178
|
+
readonly originallyExternal: false;
|
|
2179
|
+
readonly rule: {
|
|
2180
|
+
readonly framework: "nextjs";
|
|
2181
|
+
readonly category: "Bugs";
|
|
2182
|
+
readonly id: string;
|
|
2183
|
+
readonly title?: string;
|
|
2184
|
+
readonly severity: RuleSeverity;
|
|
2185
|
+
readonly requires?: ReadonlyArray<string>;
|
|
2186
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
2187
|
+
readonly tags?: ReadonlyArray<string>;
|
|
2188
|
+
readonly defaultEnabled?: boolean;
|
|
2189
|
+
readonly lifecycle?: "retired";
|
|
2190
|
+
readonly recommendation?: string;
|
|
2191
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
2192
|
+
};
|
|
2079
2193
|
}, {
|
|
2080
2194
|
readonly key: "react-doctor/nextjs-no-side-effect-in-get-handler";
|
|
2081
2195
|
readonly id: "nextjs-no-side-effect-in-get-handler";
|
|
@@ -2114,6 +2228,25 @@ declare const REACT_DOCTOR_RULES: readonly [{
|
|
|
2114
2228
|
readonly recommendation?: string;
|
|
2115
2229
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
2116
2230
|
};
|
|
2231
|
+
}, {
|
|
2232
|
+
readonly key: "react-doctor/nextjs-no-vercel-og-import";
|
|
2233
|
+
readonly id: "nextjs-no-vercel-og-import";
|
|
2234
|
+
readonly source: "react-doctor";
|
|
2235
|
+
readonly originallyExternal: false;
|
|
2236
|
+
readonly rule: {
|
|
2237
|
+
readonly framework: "nextjs";
|
|
2238
|
+
readonly category: "Bugs";
|
|
2239
|
+
readonly id: string;
|
|
2240
|
+
readonly title?: string;
|
|
2241
|
+
readonly severity: RuleSeverity;
|
|
2242
|
+
readonly requires?: ReadonlyArray<string>;
|
|
2243
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
2244
|
+
readonly tags?: ReadonlyArray<string>;
|
|
2245
|
+
readonly defaultEnabled?: boolean;
|
|
2246
|
+
readonly lifecycle?: "retired";
|
|
2247
|
+
readonly recommendation?: string;
|
|
2248
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
2249
|
+
};
|
|
2117
2250
|
}, {
|
|
2118
2251
|
readonly key: "react-doctor/no-access-key";
|
|
2119
2252
|
readonly id: "no-access-key";
|
|
@@ -8127,6 +8260,44 @@ declare const RULES: readonly [{
|
|
|
8127
8260
|
readonly recommendation?: string;
|
|
8128
8261
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8129
8262
|
};
|
|
8263
|
+
}, {
|
|
8264
|
+
readonly key: "react-doctor/nextjs-error-boundary-missing-use-client";
|
|
8265
|
+
readonly id: "nextjs-error-boundary-missing-use-client";
|
|
8266
|
+
readonly source: "react-doctor";
|
|
8267
|
+
readonly originallyExternal: false;
|
|
8268
|
+
readonly rule: {
|
|
8269
|
+
readonly framework: "nextjs";
|
|
8270
|
+
readonly category: "Bugs";
|
|
8271
|
+
readonly id: string;
|
|
8272
|
+
readonly title?: string;
|
|
8273
|
+
readonly severity: RuleSeverity;
|
|
8274
|
+
readonly requires?: ReadonlyArray<string>;
|
|
8275
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
8276
|
+
readonly tags?: ReadonlyArray<string>;
|
|
8277
|
+
readonly defaultEnabled?: boolean;
|
|
8278
|
+
readonly lifecycle?: "retired";
|
|
8279
|
+
readonly recommendation?: string;
|
|
8280
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8281
|
+
};
|
|
8282
|
+
}, {
|
|
8283
|
+
readonly key: "react-doctor/nextjs-global-error-missing-html-body";
|
|
8284
|
+
readonly id: "nextjs-global-error-missing-html-body";
|
|
8285
|
+
readonly source: "react-doctor";
|
|
8286
|
+
readonly originallyExternal: false;
|
|
8287
|
+
readonly rule: {
|
|
8288
|
+
readonly framework: "nextjs";
|
|
8289
|
+
readonly category: "Bugs";
|
|
8290
|
+
readonly id: string;
|
|
8291
|
+
readonly title?: string;
|
|
8292
|
+
readonly severity: RuleSeverity;
|
|
8293
|
+
readonly requires?: ReadonlyArray<string>;
|
|
8294
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
8295
|
+
readonly tags?: ReadonlyArray<string>;
|
|
8296
|
+
readonly defaultEnabled?: boolean;
|
|
8297
|
+
readonly lifecycle?: "retired";
|
|
8298
|
+
readonly recommendation?: string;
|
|
8299
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8300
|
+
};
|
|
8130
8301
|
}, {
|
|
8131
8302
|
readonly key: "react-doctor/nextjs-image-missing-sizes";
|
|
8132
8303
|
readonly id: "nextjs-image-missing-sizes";
|
|
@@ -8260,6 +8431,44 @@ declare const RULES: readonly [{
|
|
|
8260
8431
|
readonly recommendation?: string;
|
|
8261
8432
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8262
8433
|
};
|
|
8434
|
+
}, {
|
|
8435
|
+
readonly key: "react-doctor/nextjs-no-default-export-in-route-handler";
|
|
8436
|
+
readonly id: "nextjs-no-default-export-in-route-handler";
|
|
8437
|
+
readonly source: "react-doctor";
|
|
8438
|
+
readonly originallyExternal: false;
|
|
8439
|
+
readonly rule: {
|
|
8440
|
+
readonly framework: "nextjs";
|
|
8441
|
+
readonly category: "Bugs";
|
|
8442
|
+
readonly id: string;
|
|
8443
|
+
readonly title?: string;
|
|
8444
|
+
readonly severity: RuleSeverity;
|
|
8445
|
+
readonly requires?: ReadonlyArray<string>;
|
|
8446
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
8447
|
+
readonly tags?: ReadonlyArray<string>;
|
|
8448
|
+
readonly defaultEnabled?: boolean;
|
|
8449
|
+
readonly lifecycle?: "retired";
|
|
8450
|
+
readonly recommendation?: string;
|
|
8451
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8452
|
+
};
|
|
8453
|
+
}, {
|
|
8454
|
+
readonly key: "react-doctor/nextjs-no-edge-og-runtime";
|
|
8455
|
+
readonly id: "nextjs-no-edge-og-runtime";
|
|
8456
|
+
readonly source: "react-doctor";
|
|
8457
|
+
readonly originallyExternal: false;
|
|
8458
|
+
readonly rule: {
|
|
8459
|
+
readonly framework: "nextjs";
|
|
8460
|
+
readonly category: "Bugs";
|
|
8461
|
+
readonly id: string;
|
|
8462
|
+
readonly title?: string;
|
|
8463
|
+
readonly severity: RuleSeverity;
|
|
8464
|
+
readonly requires?: ReadonlyArray<string>;
|
|
8465
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
8466
|
+
readonly tags?: ReadonlyArray<string>;
|
|
8467
|
+
readonly defaultEnabled?: boolean;
|
|
8468
|
+
readonly lifecycle?: "retired";
|
|
8469
|
+
readonly recommendation?: string;
|
|
8470
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8471
|
+
};
|
|
8263
8472
|
}, {
|
|
8264
8473
|
readonly key: "react-doctor/nextjs-no-font-link";
|
|
8265
8474
|
readonly id: "nextjs-no-font-link";
|
|
@@ -8279,6 +8488,25 @@ declare const RULES: readonly [{
|
|
|
8279
8488
|
readonly recommendation?: string;
|
|
8280
8489
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8281
8490
|
};
|
|
8491
|
+
}, {
|
|
8492
|
+
readonly key: "react-doctor/nextjs-no-google-analytics-script";
|
|
8493
|
+
readonly id: "nextjs-no-google-analytics-script";
|
|
8494
|
+
readonly source: "react-doctor";
|
|
8495
|
+
readonly originallyExternal: false;
|
|
8496
|
+
readonly rule: {
|
|
8497
|
+
readonly framework: "nextjs";
|
|
8498
|
+
readonly category: "Bugs";
|
|
8499
|
+
readonly id: string;
|
|
8500
|
+
readonly title?: string;
|
|
8501
|
+
readonly severity: RuleSeverity;
|
|
8502
|
+
readonly requires?: ReadonlyArray<string>;
|
|
8503
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
8504
|
+
readonly tags?: ReadonlyArray<string>;
|
|
8505
|
+
readonly defaultEnabled?: boolean;
|
|
8506
|
+
readonly lifecycle?: "retired";
|
|
8507
|
+
readonly recommendation?: string;
|
|
8508
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8509
|
+
};
|
|
8282
8510
|
}, {
|
|
8283
8511
|
readonly key: "react-doctor/nextjs-no-head-import";
|
|
8284
8512
|
readonly id: "nextjs-no-head-import";
|
|
@@ -8374,6 +8602,25 @@ declare const RULES: readonly [{
|
|
|
8374
8602
|
readonly recommendation?: string;
|
|
8375
8603
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8376
8604
|
};
|
|
8605
|
+
}, {
|
|
8606
|
+
readonly key: "react-doctor/nextjs-no-script-in-head";
|
|
8607
|
+
readonly id: "nextjs-no-script-in-head";
|
|
8608
|
+
readonly source: "react-doctor";
|
|
8609
|
+
readonly originallyExternal: false;
|
|
8610
|
+
readonly rule: {
|
|
8611
|
+
readonly framework: "nextjs";
|
|
8612
|
+
readonly category: "Bugs";
|
|
8613
|
+
readonly id: string;
|
|
8614
|
+
readonly title?: string;
|
|
8615
|
+
readonly severity: RuleSeverity;
|
|
8616
|
+
readonly requires?: ReadonlyArray<string>;
|
|
8617
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
8618
|
+
readonly tags?: ReadonlyArray<string>;
|
|
8619
|
+
readonly defaultEnabled?: boolean;
|
|
8620
|
+
readonly lifecycle?: "retired";
|
|
8621
|
+
readonly recommendation?: string;
|
|
8622
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8623
|
+
};
|
|
8377
8624
|
}, {
|
|
8378
8625
|
readonly key: "react-doctor/nextjs-no-side-effect-in-get-handler";
|
|
8379
8626
|
readonly id: "nextjs-no-side-effect-in-get-handler";
|
|
@@ -8412,6 +8659,25 @@ declare const RULES: readonly [{
|
|
|
8412
8659
|
readonly recommendation?: string;
|
|
8413
8660
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8414
8661
|
};
|
|
8662
|
+
}, {
|
|
8663
|
+
readonly key: "react-doctor/nextjs-no-vercel-og-import";
|
|
8664
|
+
readonly id: "nextjs-no-vercel-og-import";
|
|
8665
|
+
readonly source: "react-doctor";
|
|
8666
|
+
readonly originallyExternal: false;
|
|
8667
|
+
readonly rule: {
|
|
8668
|
+
readonly framework: "nextjs";
|
|
8669
|
+
readonly category: "Bugs";
|
|
8670
|
+
readonly id: string;
|
|
8671
|
+
readonly title?: string;
|
|
8672
|
+
readonly severity: RuleSeverity;
|
|
8673
|
+
readonly requires?: ReadonlyArray<string>;
|
|
8674
|
+
readonly disabledBy?: ReadonlyArray<string>;
|
|
8675
|
+
readonly tags?: ReadonlyArray<string>;
|
|
8676
|
+
readonly defaultEnabled?: boolean;
|
|
8677
|
+
readonly lifecycle?: "retired";
|
|
8678
|
+
readonly recommendation?: string;
|
|
8679
|
+
readonly create: (context: RuleContext) => RuleVisitors;
|
|
8680
|
+
};
|
|
8415
8681
|
}, {
|
|
8416
8682
|
readonly key: "react-doctor/no-access-key";
|
|
8417
8683
|
readonly id: "no-access-key";
|
package/dist/index.js
CHANGED
|
@@ -12511,6 +12511,103 @@ const nextjsAsyncClientComponent = defineRule({
|
|
|
12511
12511
|
}
|
|
12512
12512
|
});
|
|
12513
12513
|
//#endregion
|
|
12514
|
+
//#region src/plugin/constants/nextjs.ts
|
|
12515
|
+
const PAGE_FILE_PATTERN = /\/page\.(tsx?|jsx?)$/;
|
|
12516
|
+
const PAGE_OR_LAYOUT_FILE_PATTERN = /\/(page|layout)\.(tsx?|jsx?)$/;
|
|
12517
|
+
const INTERNAL_PAGE_PATH_PATTERN = /\/(?:(?:\((?:dashboard|admin|settings|account|internal|manage|console|portal|auth|onboarding|app|ee|protected)\))|(?:dashboard|admin|settings|account|internal|manage|console|portal))\//i;
|
|
12518
|
+
const OG_ROUTE_PATTERN = /\/og\b/i;
|
|
12519
|
+
const PAGES_DIRECTORY_PATTERN = /\/pages\//;
|
|
12520
|
+
const NEXTJS_NAVIGATION_FUNCTIONS = new Set([
|
|
12521
|
+
"redirect",
|
|
12522
|
+
"permanentRedirect",
|
|
12523
|
+
"notFound",
|
|
12524
|
+
"forbidden",
|
|
12525
|
+
"unauthorized"
|
|
12526
|
+
]);
|
|
12527
|
+
const GOOGLE_FONTS_PATTERN = /fonts\.googleapis\.com/;
|
|
12528
|
+
const POLYFILL_SCRIPT_PATTERN = /polyfill\.io|polyfill\.min\.js|cdn\.polyfill/;
|
|
12529
|
+
const APP_DIRECTORY_PATTERN = /\/app\//;
|
|
12530
|
+
const ROUTE_HANDLER_FILE_PATTERN = /\/route\.(tsx?|jsx?)$/;
|
|
12531
|
+
const CRON_ROUTE_PATTERN = /\/(?:cron|jobs\/cron)(?:\/|$)/i;
|
|
12532
|
+
const MUTATING_ROUTE_SEGMENTS = new Set([
|
|
12533
|
+
"logout",
|
|
12534
|
+
"log-out",
|
|
12535
|
+
"signout",
|
|
12536
|
+
"sign-out",
|
|
12537
|
+
"unsubscribe",
|
|
12538
|
+
"delete",
|
|
12539
|
+
"remove",
|
|
12540
|
+
"revoke",
|
|
12541
|
+
"cancel",
|
|
12542
|
+
"deactivate"
|
|
12543
|
+
]);
|
|
12544
|
+
const ERROR_BOUNDARY_FILE_PATTERN = /\/(error|global-error)\.(tsx?|jsx?)$/;
|
|
12545
|
+
const GLOBAL_ERROR_FILE_PATTERN = /\/global-error\.(tsx?|jsx?)$/;
|
|
12546
|
+
const ROUTE_HANDLER_HTTP_METHODS = new Set([
|
|
12547
|
+
"GET",
|
|
12548
|
+
"POST",
|
|
12549
|
+
"PUT",
|
|
12550
|
+
"PATCH",
|
|
12551
|
+
"DELETE",
|
|
12552
|
+
"OPTIONS",
|
|
12553
|
+
"HEAD"
|
|
12554
|
+
]);
|
|
12555
|
+
const GOOGLE_ANALYTICS_SCRIPT_PATTERN = /google-analytics\.com|googletagmanager\.com\/gtag/;
|
|
12556
|
+
const OG_IMAGE_FILE_PATTERN = /\/(opengraph-image|twitter-image)\d*\.(tsx?|jsx?)$/;
|
|
12557
|
+
//#endregion
|
|
12558
|
+
//#region src/plugin/rules/nextjs/nextjs-error-boundary-missing-use-client.ts
|
|
12559
|
+
const nextjsErrorBoundaryMissingUseClient = defineRule({
|
|
12560
|
+
id: "nextjs-error-boundary-missing-use-client",
|
|
12561
|
+
title: "Error boundary missing 'use client'",
|
|
12562
|
+
tags: ["test-noise"],
|
|
12563
|
+
requires: ["nextjs"],
|
|
12564
|
+
severity: "error",
|
|
12565
|
+
recommendation: "Add `'use client'` at the top of this file. Error boundaries must be Client Components to catch and render fallback UI",
|
|
12566
|
+
create: (context) => ({ Program(programNode) {
|
|
12567
|
+
const filename = normalizeFilename$1(context.filename ?? "");
|
|
12568
|
+
if (!APP_DIRECTORY_PATTERN.test(filename)) return;
|
|
12569
|
+
if (!ERROR_BOUNDARY_FILE_PATTERN.test(filename)) return;
|
|
12570
|
+
if (hasDirective(programNode, "use client")) return;
|
|
12571
|
+
context.report({
|
|
12572
|
+
node: programNode,
|
|
12573
|
+
message: "This error boundary silently does nothing without 'use client'. Next.js requires error.tsx to be a Client Component."
|
|
12574
|
+
});
|
|
12575
|
+
} })
|
|
12576
|
+
});
|
|
12577
|
+
//#endregion
|
|
12578
|
+
//#region src/plugin/utils/file-contains-jsx-elements.ts
|
|
12579
|
+
const fileContainsJsxElements = (programNode, tagNames) => {
|
|
12580
|
+
const targetTagNames = new Set(tagNames);
|
|
12581
|
+
const foundTagNames = /* @__PURE__ */ new Set();
|
|
12582
|
+
walkAst(programNode, (child) => {
|
|
12583
|
+
if (foundTagNames.size === targetTagNames.size) return false;
|
|
12584
|
+
if (isNodeOfType(child, "JSXOpeningElement") && isNodeOfType(child.name, "JSXIdentifier") && targetTagNames.has(child.name.name)) foundTagNames.add(child.name.name);
|
|
12585
|
+
});
|
|
12586
|
+
return foundTagNames;
|
|
12587
|
+
};
|
|
12588
|
+
//#endregion
|
|
12589
|
+
//#region src/plugin/rules/nextjs/nextjs-global-error-missing-html-body.ts
|
|
12590
|
+
const REQUIRED_HTML_TAGS = ["html", "body"];
|
|
12591
|
+
const nextjsGlobalErrorMissingHtmlBody = defineRule({
|
|
12592
|
+
id: "nextjs-global-error-missing-html-body",
|
|
12593
|
+
title: "global-error.tsx missing <html>/<body>",
|
|
12594
|
+
tags: ["test-noise"],
|
|
12595
|
+
requires: ["nextjs"],
|
|
12596
|
+
severity: "error",
|
|
12597
|
+
recommendation: "Wrap your error UI in `<html><body>...</body></html>`. The root layout is unmounted when global-error renders",
|
|
12598
|
+
create: (context) => ({ Program(programNode) {
|
|
12599
|
+
const filename = normalizeFilename$1(context.filename ?? "");
|
|
12600
|
+
if (!APP_DIRECTORY_PATTERN.test(filename)) return;
|
|
12601
|
+
if (!GLOBAL_ERROR_FILE_PATTERN.test(filename)) return;
|
|
12602
|
+
const foundTags = fileContainsJsxElements(programNode, REQUIRED_HTML_TAGS);
|
|
12603
|
+
const missingTags = REQUIRED_HTML_TAGS.filter((tagName) => !foundTags.has(tagName)).map((tagName) => `<${tagName}>`);
|
|
12604
|
+
if (missingTags.length > 0) context.report({
|
|
12605
|
+
node: programNode,
|
|
12606
|
+
message: `global-error.tsx is missing ${missingTags.join(" and ")}. The root layout unmounts on error, so this page renders broken HTML.`
|
|
12607
|
+
});
|
|
12608
|
+
} })
|
|
12609
|
+
});
|
|
12610
|
+
//#endregion
|
|
12514
12611
|
//#region src/plugin/utils/has-jsx-attribute.ts
|
|
12515
12612
|
const hasJsxAttribute = (attributes, attributeName) => Boolean(findJsxAttribute(attributes, attributeName));
|
|
12516
12613
|
//#endregion
|
|
@@ -12554,37 +12651,6 @@ const nextjsInlineScriptMissingId = defineRule({
|
|
|
12554
12651
|
} })
|
|
12555
12652
|
});
|
|
12556
12653
|
//#endregion
|
|
12557
|
-
//#region src/plugin/constants/nextjs.ts
|
|
12558
|
-
const PAGE_FILE_PATTERN = /\/page\.(tsx?|jsx?)$/;
|
|
12559
|
-
const PAGE_OR_LAYOUT_FILE_PATTERN = /\/(page|layout)\.(tsx?|jsx?)$/;
|
|
12560
|
-
const INTERNAL_PAGE_PATH_PATTERN = /\/(?:(?:\((?:dashboard|admin|settings|account|internal|manage|console|portal|auth|onboarding|app|ee|protected)\))|(?:dashboard|admin|settings|account|internal|manage|console|portal))\//i;
|
|
12561
|
-
const OG_ROUTE_PATTERN = /\/og\b/i;
|
|
12562
|
-
const PAGES_DIRECTORY_PATTERN = /\/pages\//;
|
|
12563
|
-
const NEXTJS_NAVIGATION_FUNCTIONS = new Set([
|
|
12564
|
-
"redirect",
|
|
12565
|
-
"permanentRedirect",
|
|
12566
|
-
"notFound",
|
|
12567
|
-
"forbidden",
|
|
12568
|
-
"unauthorized"
|
|
12569
|
-
]);
|
|
12570
|
-
const GOOGLE_FONTS_PATTERN = /fonts\.googleapis\.com/;
|
|
12571
|
-
const POLYFILL_SCRIPT_PATTERN = /polyfill\.io|polyfill\.min\.js|cdn\.polyfill/;
|
|
12572
|
-
const APP_DIRECTORY_PATTERN = /\/app\//;
|
|
12573
|
-
const ROUTE_HANDLER_FILE_PATTERN = /\/route\.(tsx?|jsx?)$/;
|
|
12574
|
-
const CRON_ROUTE_PATTERN = /\/(?:cron|jobs\/cron)(?:\/|$)/i;
|
|
12575
|
-
const MUTATING_ROUTE_SEGMENTS = new Set([
|
|
12576
|
-
"logout",
|
|
12577
|
-
"log-out",
|
|
12578
|
-
"signout",
|
|
12579
|
-
"sign-out",
|
|
12580
|
-
"unsubscribe",
|
|
12581
|
-
"delete",
|
|
12582
|
-
"remove",
|
|
12583
|
-
"revoke",
|
|
12584
|
-
"cancel",
|
|
12585
|
-
"deactivate"
|
|
12586
|
-
]);
|
|
12587
|
-
//#endregion
|
|
12588
12654
|
//#region src/plugin/rules/nextjs/nextjs-missing-metadata.ts
|
|
12589
12655
|
const nextjsMissingMetadata = defineRule({
|
|
12590
12656
|
id: "nextjs-missing-metadata",
|
|
@@ -12734,6 +12800,89 @@ const nextjsNoCssLink = defineRule({
|
|
|
12734
12800
|
} })
|
|
12735
12801
|
});
|
|
12736
12802
|
//#endregion
|
|
12803
|
+
//#region src/plugin/rules/nextjs/nextjs-no-default-export-in-route-handler.ts
|
|
12804
|
+
const programHasNamedHttpMethodExport = (programNode) => {
|
|
12805
|
+
for (const statement of programNode.body ?? []) {
|
|
12806
|
+
if (!isNodeOfType(statement, "ExportNamedDeclaration")) continue;
|
|
12807
|
+
const declaration = statement.declaration;
|
|
12808
|
+
if (isNodeOfType(declaration, "FunctionDeclaration") && declaration.id?.name && ROUTE_HANDLER_HTTP_METHODS.has(declaration.id.name)) return true;
|
|
12809
|
+
if (isNodeOfType(declaration, "VariableDeclaration")) {
|
|
12810
|
+
for (const declarator of declaration.declarations ?? []) if (isNodeOfType(declarator.id, "Identifier") && ROUTE_HANDLER_HTTP_METHODS.has(declarator.id.name)) return true;
|
|
12811
|
+
}
|
|
12812
|
+
for (const specifier of statement.specifiers ?? []) if (isNodeOfType(specifier, "ExportSpecifier") && isNodeOfType(specifier.exported, "Identifier") && ROUTE_HANDLER_HTTP_METHODS.has(specifier.exported.name)) return true;
|
|
12813
|
+
}
|
|
12814
|
+
return false;
|
|
12815
|
+
};
|
|
12816
|
+
const nextjsNoDefaultExportInRouteHandler = defineRule({
|
|
12817
|
+
id: "nextjs-no-default-export-in-route-handler",
|
|
12818
|
+
title: "Default export in route handler",
|
|
12819
|
+
tags: ["test-noise"],
|
|
12820
|
+
requires: ["nextjs"],
|
|
12821
|
+
severity: "error",
|
|
12822
|
+
recommendation: "Replace `export default` with named HTTP method exports: `export async function GET(request) { … }`",
|
|
12823
|
+
create: (context) => {
|
|
12824
|
+
let isAppRouteHandler = false;
|
|
12825
|
+
let programNode = null;
|
|
12826
|
+
return {
|
|
12827
|
+
Program(node) {
|
|
12828
|
+
const filename = normalizeFilename$1(context.filename ?? "");
|
|
12829
|
+
isAppRouteHandler = APP_DIRECTORY_PATTERN.test(filename) && ROUTE_HANDLER_FILE_PATTERN.test(filename);
|
|
12830
|
+
programNode = node;
|
|
12831
|
+
},
|
|
12832
|
+
ExportDefaultDeclaration(node) {
|
|
12833
|
+
if (!isAppRouteHandler || !programNode) return;
|
|
12834
|
+
if (programHasNamedHttpMethodExport(programNode)) return;
|
|
12835
|
+
context.report({
|
|
12836
|
+
node,
|
|
12837
|
+
message: "Default exports in route.ts are silently ignored. Next.js only recognizes named HTTP method exports (GET, POST, etc.)."
|
|
12838
|
+
});
|
|
12839
|
+
},
|
|
12840
|
+
ExportNamedDeclaration(node) {
|
|
12841
|
+
if (!isAppRouteHandler || !programNode) return;
|
|
12842
|
+
if (!(node.specifiers ?? []).some((specifier) => isNodeOfType(specifier, "ExportSpecifier") && isNodeOfType(specifier.exported, "Identifier") && specifier.exported.name === "default")) return;
|
|
12843
|
+
if (programHasNamedHttpMethodExport(programNode)) return;
|
|
12844
|
+
context.report({
|
|
12845
|
+
node,
|
|
12846
|
+
message: "Default exports in route.ts are silently ignored. Next.js only recognizes named HTTP method exports (GET, POST, etc.)."
|
|
12847
|
+
});
|
|
12848
|
+
}
|
|
12849
|
+
};
|
|
12850
|
+
}
|
|
12851
|
+
});
|
|
12852
|
+
//#endregion
|
|
12853
|
+
//#region src/plugin/rules/nextjs/nextjs-no-edge-og-runtime.ts
|
|
12854
|
+
const nextjsNoEdgeOgRuntime = defineRule({
|
|
12855
|
+
id: "nextjs-no-edge-og-runtime",
|
|
12856
|
+
title: "Edge runtime in OG image route",
|
|
12857
|
+
tags: ["test-noise"],
|
|
12858
|
+
requires: ["nextjs"],
|
|
12859
|
+
severity: "warn",
|
|
12860
|
+
recommendation: "Remove `export const runtime = 'edge'` from OG image files. The default Node.js runtime supports more fonts and APIs",
|
|
12861
|
+
create: (context) => {
|
|
12862
|
+
let isOgImageFile = false;
|
|
12863
|
+
return {
|
|
12864
|
+
Program() {
|
|
12865
|
+
const filename = normalizeFilename$1(context.filename ?? "");
|
|
12866
|
+
isOgImageFile = OG_IMAGE_FILE_PATTERN.test(filename);
|
|
12867
|
+
},
|
|
12868
|
+
ExportNamedDeclaration(node) {
|
|
12869
|
+
if (!isOgImageFile) return;
|
|
12870
|
+
const declaration = node.declaration;
|
|
12871
|
+
if (!isNodeOfType(declaration, "VariableDeclaration")) return;
|
|
12872
|
+
for (const declarator of declaration.declarations ?? []) {
|
|
12873
|
+
if (!isNodeOfType(declarator, "VariableDeclarator")) continue;
|
|
12874
|
+
if (!isNodeOfType(declarator.id, "Identifier")) continue;
|
|
12875
|
+
if (declarator.id.name !== "runtime") continue;
|
|
12876
|
+
if ((isNodeOfType(declarator.init, "Literal") ? declarator.init.value : null) === "edge") context.report({
|
|
12877
|
+
node,
|
|
12878
|
+
message: "Edge runtime limits OG image generation. Node.js runtime supports more fonts, filesystem access, and larger response sizes."
|
|
12879
|
+
});
|
|
12880
|
+
}
|
|
12881
|
+
}
|
|
12882
|
+
};
|
|
12883
|
+
}
|
|
12884
|
+
});
|
|
12885
|
+
//#endregion
|
|
12737
12886
|
//#region src/plugin/rules/nextjs/nextjs-no-font-link.ts
|
|
12738
12887
|
const nextjsNoFontLink = defineRule({
|
|
12739
12888
|
id: "nextjs-no-font-link",
|
|
@@ -12754,6 +12903,27 @@ const nextjsNoFontLink = defineRule({
|
|
|
12754
12903
|
} })
|
|
12755
12904
|
});
|
|
12756
12905
|
//#endregion
|
|
12906
|
+
//#region src/plugin/rules/nextjs/nextjs-no-google-analytics-script.ts
|
|
12907
|
+
const nextjsNoGoogleAnalyticsScript = defineRule({
|
|
12908
|
+
id: "nextjs-no-google-analytics-script",
|
|
12909
|
+
title: "Manual Google Analytics script",
|
|
12910
|
+
tags: ["test-noise"],
|
|
12911
|
+
requires: ["nextjs"],
|
|
12912
|
+
severity: "warn",
|
|
12913
|
+
recommendation: "Use `import { GoogleAnalytics } from '@next/third-parties/google'` for automatic optimization & smaller bundles",
|
|
12914
|
+
create: (context) => ({ JSXOpeningElement(node) {
|
|
12915
|
+
if (!isNodeOfType(node.name, "JSXIdentifier")) return;
|
|
12916
|
+
if (node.name.name !== "script" && node.name.name !== "Script") return;
|
|
12917
|
+
const srcAttribute = findJsxAttribute(node.attributes ?? [], "src");
|
|
12918
|
+
if (!srcAttribute?.value) return;
|
|
12919
|
+
const srcValue = isNodeOfType(srcAttribute.value, "Literal") ? srcAttribute.value.value : null;
|
|
12920
|
+
if (typeof srcValue === "string" && GOOGLE_ANALYTICS_SCRIPT_PATTERN.test(srcValue)) context.report({
|
|
12921
|
+
node,
|
|
12922
|
+
message: "Manual Google Analytics script blocks rendering. Use @next/third-parties for optimal loading strategy."
|
|
12923
|
+
});
|
|
12924
|
+
} })
|
|
12925
|
+
});
|
|
12926
|
+
//#endregion
|
|
12757
12927
|
//#region src/plugin/rules/nextjs/nextjs-no-head-import.ts
|
|
12758
12928
|
const nextjsNoHeadImport = defineRule({
|
|
12759
12929
|
id: "nextjs-no-head-import",
|
|
@@ -12865,6 +13035,32 @@ const nextjsNoRedirectInTryCatch = defineRule({
|
|
|
12865
13035
|
}
|
|
12866
13036
|
});
|
|
12867
13037
|
//#endregion
|
|
13038
|
+
//#region src/plugin/rules/nextjs/nextjs-no-script-in-head.ts
|
|
13039
|
+
const nextjsNoScriptInHead = defineRule({
|
|
13040
|
+
id: "nextjs-no-script-in-head",
|
|
13041
|
+
title: "next/script inside next/head",
|
|
13042
|
+
tags: ["test-noise"],
|
|
13043
|
+
requires: ["nextjs"],
|
|
13044
|
+
severity: "error",
|
|
13045
|
+
recommendation: "Move `<Script>` outside of `<Head>`. next/script manages its own placement and ignores head context",
|
|
13046
|
+
create: (context) => {
|
|
13047
|
+
let insideHeadDepth = 0;
|
|
13048
|
+
return {
|
|
13049
|
+
JSXOpeningElement(node) {
|
|
13050
|
+
if (!isNodeOfType(node.name, "JSXIdentifier")) return;
|
|
13051
|
+
if (node.name.name === "Head" && !node.selfClosing) insideHeadDepth++;
|
|
13052
|
+
if (node.name.name === "Script" && insideHeadDepth > 0) context.report({
|
|
13053
|
+
node,
|
|
13054
|
+
message: "next/script inside next/head is silently ignored. Move <Script> outside <Head> so it actually loads."
|
|
13055
|
+
});
|
|
13056
|
+
},
|
|
13057
|
+
JSXClosingElement(node) {
|
|
13058
|
+
if (isNodeOfType(node.name, "JSXIdentifier") && node.name.name === "Head") insideHeadDepth = Math.max(0, insideHeadDepth - 1);
|
|
13059
|
+
}
|
|
13060
|
+
};
|
|
13061
|
+
}
|
|
13062
|
+
});
|
|
13063
|
+
//#endregion
|
|
12868
13064
|
//#region src/plugin/utils/is-cookies-call.ts
|
|
12869
13065
|
const isCookiesCall = (node) => isNodeOfType(node, "CallExpression") && isNodeOfType(node.callee, "Identifier") && node.callee.name === "cookies";
|
|
12870
13066
|
//#endregion
|
|
@@ -13213,6 +13409,23 @@ const nextjsNoUseSearchParamsWithoutSuspense = defineRule({
|
|
|
13213
13409
|
}
|
|
13214
13410
|
});
|
|
13215
13411
|
//#endregion
|
|
13412
|
+
//#region src/plugin/rules/nextjs/nextjs-no-vercel-og-import.ts
|
|
13413
|
+
const nextjsNoVercelOgImport = defineRule({
|
|
13414
|
+
id: "nextjs-no-vercel-og-import",
|
|
13415
|
+
title: "@vercel/og import instead of next/og",
|
|
13416
|
+
tags: ["test-noise"],
|
|
13417
|
+
requires: ["nextjs"],
|
|
13418
|
+
severity: "warn",
|
|
13419
|
+
recommendation: "Use `import { ImageResponse } from \"next/og\"`. The `@vercel/og` package is built into Next.js and should not be imported directly",
|
|
13420
|
+
create: (context) => ({ ImportDeclaration(node) {
|
|
13421
|
+
if (node.source?.value !== "@vercel/og") return;
|
|
13422
|
+
context.report({
|
|
13423
|
+
node,
|
|
13424
|
+
message: "@vercel/og is bundled into Next.js. Import from \"next/og\" instead to avoid duplicate code and version mismatch."
|
|
13425
|
+
});
|
|
13426
|
+
} })
|
|
13427
|
+
});
|
|
13428
|
+
//#endregion
|
|
13216
13429
|
//#region src/plugin/rules/a11y/no-access-key.ts
|
|
13217
13430
|
const MESSAGE$30 = "Screen reader users can lose their shortcuts because `accessKey` clashes with them, so remove it.";
|
|
13218
13431
|
const isUndefinedIdentifier = (expression) => isNodeOfType(expression, "Identifier") && expression.name === "undefined";
|
|
@@ -32917,15 +33130,6 @@ const serverFetchWithoutRevalidate = defineRule({
|
|
|
32917
33130
|
});
|
|
32918
33131
|
//#endregion
|
|
32919
33132
|
//#region src/plugin/rules/server/server-hoist-static-io.ts
|
|
32920
|
-
const ROUTE_HANDLER_HTTP_METHODS = new Set([
|
|
32921
|
-
"GET",
|
|
32922
|
-
"POST",
|
|
32923
|
-
"PUT",
|
|
32924
|
-
"PATCH",
|
|
32925
|
-
"DELETE",
|
|
32926
|
-
"OPTIONS",
|
|
32927
|
-
"HEAD"
|
|
32928
|
-
]);
|
|
32929
33133
|
const STATIC_IO_FUNCTIONS = new Set([
|
|
32930
33134
|
"readFileSync",
|
|
32931
33135
|
"readFile",
|
|
@@ -35440,6 +35644,28 @@ const reactDoctorRules = [
|
|
|
35440
35644
|
category: "Bugs"
|
|
35441
35645
|
}
|
|
35442
35646
|
},
|
|
35647
|
+
{
|
|
35648
|
+
key: "react-doctor/nextjs-error-boundary-missing-use-client",
|
|
35649
|
+
id: "nextjs-error-boundary-missing-use-client",
|
|
35650
|
+
source: "react-doctor",
|
|
35651
|
+
originallyExternal: false,
|
|
35652
|
+
rule: {
|
|
35653
|
+
...nextjsErrorBoundaryMissingUseClient,
|
|
35654
|
+
framework: "nextjs",
|
|
35655
|
+
category: "Bugs"
|
|
35656
|
+
}
|
|
35657
|
+
},
|
|
35658
|
+
{
|
|
35659
|
+
key: "react-doctor/nextjs-global-error-missing-html-body",
|
|
35660
|
+
id: "nextjs-global-error-missing-html-body",
|
|
35661
|
+
source: "react-doctor",
|
|
35662
|
+
originallyExternal: false,
|
|
35663
|
+
rule: {
|
|
35664
|
+
...nextjsGlobalErrorMissingHtmlBody,
|
|
35665
|
+
framework: "nextjs",
|
|
35666
|
+
category: "Bugs"
|
|
35667
|
+
}
|
|
35668
|
+
},
|
|
35443
35669
|
{
|
|
35444
35670
|
key: "react-doctor/nextjs-image-missing-sizes",
|
|
35445
35671
|
id: "nextjs-image-missing-sizes",
|
|
@@ -35517,6 +35743,28 @@ const reactDoctorRules = [
|
|
|
35517
35743
|
category: "Bugs"
|
|
35518
35744
|
}
|
|
35519
35745
|
},
|
|
35746
|
+
{
|
|
35747
|
+
key: "react-doctor/nextjs-no-default-export-in-route-handler",
|
|
35748
|
+
id: "nextjs-no-default-export-in-route-handler",
|
|
35749
|
+
source: "react-doctor",
|
|
35750
|
+
originallyExternal: false,
|
|
35751
|
+
rule: {
|
|
35752
|
+
...nextjsNoDefaultExportInRouteHandler,
|
|
35753
|
+
framework: "nextjs",
|
|
35754
|
+
category: "Bugs"
|
|
35755
|
+
}
|
|
35756
|
+
},
|
|
35757
|
+
{
|
|
35758
|
+
key: "react-doctor/nextjs-no-edge-og-runtime",
|
|
35759
|
+
id: "nextjs-no-edge-og-runtime",
|
|
35760
|
+
source: "react-doctor",
|
|
35761
|
+
originallyExternal: false,
|
|
35762
|
+
rule: {
|
|
35763
|
+
...nextjsNoEdgeOgRuntime,
|
|
35764
|
+
framework: "nextjs",
|
|
35765
|
+
category: "Bugs"
|
|
35766
|
+
}
|
|
35767
|
+
},
|
|
35520
35768
|
{
|
|
35521
35769
|
key: "react-doctor/nextjs-no-font-link",
|
|
35522
35770
|
id: "nextjs-no-font-link",
|
|
@@ -35528,6 +35776,17 @@ const reactDoctorRules = [
|
|
|
35528
35776
|
category: "Bugs"
|
|
35529
35777
|
}
|
|
35530
35778
|
},
|
|
35779
|
+
{
|
|
35780
|
+
key: "react-doctor/nextjs-no-google-analytics-script",
|
|
35781
|
+
id: "nextjs-no-google-analytics-script",
|
|
35782
|
+
source: "react-doctor",
|
|
35783
|
+
originallyExternal: false,
|
|
35784
|
+
rule: {
|
|
35785
|
+
...nextjsNoGoogleAnalyticsScript,
|
|
35786
|
+
framework: "nextjs",
|
|
35787
|
+
category: "Bugs"
|
|
35788
|
+
}
|
|
35789
|
+
},
|
|
35531
35790
|
{
|
|
35532
35791
|
key: "react-doctor/nextjs-no-head-import",
|
|
35533
35792
|
id: "nextjs-no-head-import",
|
|
@@ -35583,6 +35842,17 @@ const reactDoctorRules = [
|
|
|
35583
35842
|
category: "Bugs"
|
|
35584
35843
|
}
|
|
35585
35844
|
},
|
|
35845
|
+
{
|
|
35846
|
+
key: "react-doctor/nextjs-no-script-in-head",
|
|
35847
|
+
id: "nextjs-no-script-in-head",
|
|
35848
|
+
source: "react-doctor",
|
|
35849
|
+
originallyExternal: false,
|
|
35850
|
+
rule: {
|
|
35851
|
+
...nextjsNoScriptInHead,
|
|
35852
|
+
framework: "nextjs",
|
|
35853
|
+
category: "Bugs"
|
|
35854
|
+
}
|
|
35855
|
+
},
|
|
35586
35856
|
{
|
|
35587
35857
|
key: "react-doctor/nextjs-no-side-effect-in-get-handler",
|
|
35588
35858
|
id: "nextjs-no-side-effect-in-get-handler",
|
|
@@ -35605,6 +35875,17 @@ const reactDoctorRules = [
|
|
|
35605
35875
|
category: "Bugs"
|
|
35606
35876
|
}
|
|
35607
35877
|
},
|
|
35878
|
+
{
|
|
35879
|
+
key: "react-doctor/nextjs-no-vercel-og-import",
|
|
35880
|
+
id: "nextjs-no-vercel-og-import",
|
|
35881
|
+
source: "react-doctor",
|
|
35882
|
+
originallyExternal: false,
|
|
35883
|
+
rule: {
|
|
35884
|
+
...nextjsNoVercelOgImport,
|
|
35885
|
+
framework: "nextjs",
|
|
35886
|
+
category: "Bugs"
|
|
35887
|
+
}
|
|
35888
|
+
},
|
|
35608
35889
|
{
|
|
35609
35890
|
key: "react-doctor/no-access-key",
|
|
35610
35891
|
id: "no-access-key",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oxlint-plugin-react-doctor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-dev.a5c6993",
|
|
4
4
|
"description": "oxlint plugin for React Doctor: diagnose React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|