@dvukovic/style-guide 0.3.115 → 0.3.117

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dvukovic/style-guide",
3
- "version": "0.3.115",
3
+ "version": "0.3.117",
4
4
  "description": "My own style guide",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@eslint-community/eslint-plugin-eslint-comments": "4.5.0",
33
- "@eslint/compat": "^2.0.0",
33
+ "@eslint/compat": "2.0.0",
34
34
  "@next/eslint-plugin-next": "16.1.0",
35
35
  "@prettier/plugin-xml": "3.4.2",
36
36
  "@rimac-technology/eslint-plugin": "1.5.0",
@@ -42,6 +42,7 @@
42
42
  "eslint-plugin-jest": "29.4.0",
43
43
  "eslint-plugin-mobx": "0.0.13",
44
44
  "eslint-plugin-n": "17.23.1",
45
+ "eslint-plugin-package-json": "0.88.1",
45
46
  "eslint-plugin-playwright": "2.4.0",
46
47
  "eslint-plugin-promise": "7.2.1",
47
48
  "eslint-plugin-react": "7.37.5",
@@ -56,6 +57,7 @@
56
57
  "eslint-plugin-unicorn": "62.0.0",
57
58
  "eslint-plugin-unused-imports": "4.3.0",
58
59
  "globals": "16.5.0",
60
+ "jsonc-eslint-parser": "2.4.2",
59
61
  "prettier-plugin-embed": "0.5.1",
60
62
  "prettier-plugin-jsdoc": "1.8.0",
61
63
  "prettier-plugin-packagejson": "2.5.20",
@@ -77,19 +79,17 @@
77
79
  "cspell": "9.4.0",
78
80
  "eslint": "9.39.2",
79
81
  "jest": "30.2.0",
80
- "npm-package-json-lint": "9.0.0",
81
82
  "prettier": "3.7.4",
82
83
  "react": "19.2.3",
83
84
  "release-it": "19.1.0",
84
- "storybook": "^10.1.10",
85
+ "storybook": "10.1.10",
85
86
  "stylelint": "16.26.1",
86
87
  "typescript": "5.9.3",
87
- "vitest": "^4.0.16"
88
+ "vitest": "4.0.16"
88
89
  },
89
90
  "peerDependencies": {
90
91
  "cspell": "9",
91
92
  "eslint": "^9",
92
- "npm-package-json-lint": "9",
93
93
  "prettier": "3",
94
94
  "stylelint": "16"
95
95
  },
@@ -100,9 +100,6 @@
100
100
  "eslint": {
101
101
  "optional": true
102
102
  },
103
- "npm-package-json-lint": {
104
- "optional": true
105
- },
106
103
  "prettier": {
107
104
  "optional": true
108
105
  },
@@ -112,7 +109,7 @@
112
109
  },
113
110
  "packageManager": "yarn@4.12.0",
114
111
  "engines": {
115
- "node": ">=20.0.0"
112
+ "node": ">=24.0.0"
116
113
  },
117
114
  "publishConfig": {
118
115
  "access": "public",
@@ -0,0 +1,17 @@
1
+ import { packageJson as packageJsonRules } from "../plugins/package-json.js"
2
+
3
+ export const packageJsonConfigs = [packageJsonRules]
4
+
5
+ /**
6
+ * Package.json ESLint configuration
7
+ *
8
+ * @param {import("@eslint/config-helpers").ConfigWithExtends} [config]
9
+ * @returns {import("@eslint/config-helpers").ConfigWithExtends}
10
+ */
11
+ export function packageJson(config) {
12
+ return {
13
+ extends: [...packageJsonConfigs, ...(config?.extends ?? [])],
14
+ files: ["**/package.json"],
15
+ ...config,
16
+ }
17
+ }
@@ -0,0 +1,50 @@
1
+ import { ESLint } from "eslint"
2
+
3
+ import { packageJsonConfigs } from "./package-json.js"
4
+
5
+ const eslint = new ESLint({
6
+ overrideConfig: [...packageJsonConfigs, { files: ["**/package.json"] }],
7
+ overrideConfigFile: true,
8
+ })
9
+
10
+ describe("package-json", () => {
11
+ test("loads without errors", async () => {
12
+ const validPackageJson = JSON.stringify(
13
+ {
14
+ author: "Test Author",
15
+ description: "A test package",
16
+ engines: {
17
+ node: ">=20.0.0",
18
+ },
19
+ license: "MIT",
20
+ name: "test-package",
21
+ repository: {
22
+ type: "git",
23
+ url: "https://github.com/test/test",
24
+ },
25
+ version: "1.0.0",
26
+ },
27
+ null,
28
+ 4,
29
+ )
30
+
31
+ const results = await eslint.lintText(validPackageJson, { filePath: "package.json" })
32
+
33
+ expect(results).toBeDefined()
34
+ expect(results[0]?.fatalErrorCount).toBe(0)
35
+ })
36
+
37
+ test("detects missing required fields", async () => {
38
+ const invalidPackageJson = JSON.stringify(
39
+ {
40
+ name: "test-package",
41
+ },
42
+ null,
43
+ 4,
44
+ )
45
+
46
+ const results = await eslint.lintText(invalidPackageJson, { filePath: "package.json" })
47
+
48
+ expect(results[0]?.errorCount).toBeGreaterThan(0)
49
+ })
50
+ })
@@ -30,6 +30,7 @@ export * from "./configs/jest.js"
30
30
  export * from "./configs/mobx.js"
31
31
  export * from "./configs/next.js"
32
32
  export * from "./configs/node.js"
33
+ export * from "./configs/package-json.js"
33
34
  export * from "./configs/playwright.js"
34
35
  export * from "./configs/react.js"
35
36
  export * from "./configs/typescript.js"
@@ -70,7 +70,6 @@ export const eslint = {
70
70
  "no-extra-bind": "error",
71
71
  "no-extra-boolean-cast": "error",
72
72
  "no-extra-label": "error",
73
- "no-fallthrough": "error",
74
73
  "no-global-assign": "error",
75
74
  "no-implicit-coercion": "error",
76
75
  "no-implied-eval": "error",
@@ -0,0 +1,97 @@
1
+ import plugin from "eslint-plugin-package-json"
2
+ import jsoncParser from "jsonc-eslint-parser"
3
+
4
+ import { noRestrictedDependencies } from "../rules/no-restricted-dependencies/no-restricted-dependencies.js"
5
+ import { validEnginesNode } from "../rules/valid-engines-node/valid-engines-node.js"
6
+
7
+ /** @type {import("@eslint/config-helpers").Config} */
8
+ export const packageJson = {
9
+ languageOptions: {
10
+ parser: jsoncParser,
11
+ },
12
+ plugins: {
13
+ dvukovic: {
14
+ rules: {
15
+ "no-restricted-dependencies": noRestrictedDependencies,
16
+ "valid-engines-node": validEnginesNode,
17
+ },
18
+ },
19
+ "package-json": plugin,
20
+ },
21
+ rules: {
22
+ "dvukovic/no-restricted-dependencies": [
23
+ "error",
24
+ {
25
+ packages: [
26
+ "@types/*",
27
+ "cspell",
28
+ "eslint",
29
+ "lodash",
30
+ "npm-package-json-lint",
31
+ "prettier",
32
+ "ramda",
33
+ "stylelint",
34
+ "typeorm",
35
+ ],
36
+ },
37
+ ],
38
+ "dvukovic/valid-engines-node": ["error", { versions: ["24"] }],
39
+ "package-json/bin-name-casing": "error",
40
+ "package-json/no-empty-fields": "error",
41
+ "package-json/no-redundant-files": "error",
42
+ "package-json/no-redundant-publishConfig": "error",
43
+ "package-json/order-properties": "error",
44
+ "package-json/repository-shorthand": "error",
45
+ "package-json/require-author": "error",
46
+ "package-json/require-description": "error",
47
+ "package-json/require-engines": "error",
48
+ "package-json/require-license": "error",
49
+ "package-json/require-name": "error",
50
+ "package-json/require-repository": "error",
51
+ "package-json/require-version": "error",
52
+ "package-json/restrict-dependency-ranges": [
53
+ "error",
54
+ {
55
+ forDependencyTypes: ["dependencies", "devDependencies", "optionalDependencies"],
56
+ rangeType: "pin",
57
+ },
58
+ ],
59
+ "package-json/scripts-name-casing": "error",
60
+ "package-json/sort-collections": "error",
61
+ "package-json/specify-peers-locally": "error",
62
+ "package-json/unique-dependencies": "error",
63
+ "package-json/valid-author": "error",
64
+ "package-json/valid-bin": "error",
65
+ "package-json/valid-bundleDependencies": "error",
66
+ "package-json/valid-config": "error",
67
+ "package-json/valid-contributors": "error",
68
+ "package-json/valid-cpu": "error",
69
+ "package-json/valid-dependencies": "error",
70
+ "package-json/valid-description": "error",
71
+ "package-json/valid-devDependencies": "error",
72
+ "package-json/valid-directories": "error",
73
+ "package-json/valid-engines": "error",
74
+ "package-json/valid-exports": "error",
75
+ "package-json/valid-files": "error",
76
+ "package-json/valid-homepage": "error",
77
+ "package-json/valid-keywords": "error",
78
+ "package-json/valid-license": "error",
79
+ "package-json/valid-main": "error",
80
+ "package-json/valid-man": "error",
81
+ "package-json/valid-module": "error",
82
+ "package-json/valid-name": "error",
83
+ "package-json/valid-optionalDependencies": "error",
84
+ "package-json/valid-os": "error",
85
+ "package-json/valid-package-definition": "error",
86
+ "package-json/valid-peerDependencies": "error",
87
+ "package-json/valid-private": "error",
88
+ "package-json/valid-publishConfig": "error",
89
+ "package-json/valid-repository": "error",
90
+ "package-json/valid-repository-directory": "error",
91
+ "package-json/valid-scripts": "error",
92
+ "package-json/valid-sideEffects": "error",
93
+ "package-json/valid-type": "error",
94
+ "package-json/valid-version": "error",
95
+ "package-json/valid-workspaces": "error",
96
+ },
97
+ }
@@ -109,7 +109,6 @@ export const sonarjs = {
109
109
  "sonarjs/no-equals-in-for-termination": "error",
110
110
  "sonarjs/no-exclusive-tests": "error",
111
111
  "sonarjs/no-extra-arguments": "error",
112
- "sonarjs/no-fallthrough": "error",
113
112
  "sonarjs/no-for-in-iterable": "error",
114
113
  "sonarjs/no-function-declaration-in-block": "error",
115
114
  "sonarjs/no-global-this": "error",
@@ -0,0 +1,101 @@
1
+ const DEPENDENCY_TYPES = new Set([
2
+ "dependencies",
3
+ "devDependencies",
4
+ "optionalDependencies",
5
+ "peerDependencies",
6
+ ])
7
+
8
+ /**
9
+ * Checks if a package name matches a restriction pattern. Supports exact matches and glob-like
10
+ * patterns with * wildcard.
11
+ *
12
+ * @param {string} packageName - The package name to check
13
+ * @param {string} pattern - The restriction pattern
14
+ * @returns {boolean} True if the package matches the pattern
15
+ */
16
+ function matchesPattern(packageName, pattern) {
17
+ if (pattern.includes("*")) {
18
+ const regexPattern = pattern.replaceAll("*", ".*").replaceAll("/", String.raw`\/`)
19
+ // eslint-disable-next-line security-node/non-literal-reg-expr -- Pattern comes from trusted ESLint config
20
+ const regex = new RegExp(`^${regexPattern}$`)
21
+
22
+ return regex.test(packageName)
23
+ }
24
+
25
+ return packageName === pattern
26
+ }
27
+
28
+ export const noRestrictedDependencies = {
29
+ create(context) {
30
+ const options = context.options[0] || {}
31
+ const restricted = options.packages || []
32
+
33
+ if (restricted.length === 0) {
34
+ return {}
35
+ }
36
+
37
+ return {
38
+ JSONProperty(node) {
39
+ if (node.key.type !== "JSONLiteral" || typeof node.key.value !== "string") {
40
+ return
41
+ }
42
+
43
+ const propertyName = node.key.value
44
+
45
+ if (!DEPENDENCY_TYPES.has(propertyName)) {
46
+ return
47
+ }
48
+
49
+ if (node.value.type !== "JSONObjectExpression") {
50
+ return
51
+ }
52
+
53
+ for (const dep of node.value.properties) {
54
+ if (dep.key.type !== "JSONLiteral" || typeof dep.key.value !== "string") {
55
+ continue
56
+ }
57
+
58
+ const packageName = dep.key.value
59
+
60
+ for (const pattern of restricted) {
61
+ if (matchesPattern(packageName, pattern)) {
62
+ context.report({
63
+ data: {
64
+ dependencyType: propertyName,
65
+ package: packageName,
66
+ pattern,
67
+ },
68
+ messageId: "restricted",
69
+ node: dep.key,
70
+ })
71
+ break
72
+ }
73
+ }
74
+ }
75
+ },
76
+ }
77
+ },
78
+ meta: {
79
+ docs: {
80
+ description: "Disallow specified packages from being used as dependencies.",
81
+ },
82
+ messages: {
83
+ restricted: `Package "{{package}}" is restricted (matched pattern: "{{pattern}}") in {{dependencyType}}.`,
84
+ },
85
+ schema: [
86
+ {
87
+ additionalProperties: false,
88
+ properties: {
89
+ packages: {
90
+ description:
91
+ "List of restricted package names or patterns (supports * wildcard)",
92
+ items: { type: "string" },
93
+ type: "array",
94
+ },
95
+ },
96
+ type: "object",
97
+ },
98
+ ],
99
+ type: "problem",
100
+ },
101
+ }
@@ -0,0 +1,160 @@
1
+ import { ESLint } from "eslint"
2
+ import jsoncParser from "jsonc-eslint-parser"
3
+
4
+ import { noRestrictedDependencies } from "./no-restricted-dependencies.js"
5
+
6
+ const createEslint = (packages) => {
7
+ return new ESLint({
8
+ overrideConfig: [
9
+ {
10
+ files: ["**/package.json"],
11
+ languageOptions: {
12
+ parser: jsoncParser,
13
+ },
14
+ plugins: {
15
+ custom: {
16
+ rules: {
17
+ "no-restricted-dependencies": noRestrictedDependencies,
18
+ },
19
+ },
20
+ },
21
+ rules: {
22
+ "custom/no-restricted-dependencies": ["error", { packages }],
23
+ },
24
+ },
25
+ ],
26
+ overrideConfigFile: true,
27
+ })
28
+ }
29
+
30
+ describe("no-restricted-dependencies", () => {
31
+ test("detects restricted package in dependencies", async () => {
32
+ const eslint = createEslint(["lodash"])
33
+ const packageJson = JSON.stringify(
34
+ {
35
+ dependencies: {
36
+ lodash: "^4.0.0",
37
+ },
38
+ name: "test",
39
+ },
40
+ null,
41
+ 4,
42
+ )
43
+
44
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
45
+ const errors = results[0]?.messages.filter((message) => {
46
+ return message.ruleId === "custom/no-restricted-dependencies"
47
+ })
48
+
49
+ expect(errors?.length).toBe(1)
50
+ expect(errors?.[0]?.message).toContain("lodash")
51
+ })
52
+
53
+ test("detects restricted package in devDependencies", async () => {
54
+ const eslint = createEslint(["jest"])
55
+ const packageJson = JSON.stringify(
56
+ {
57
+ devDependencies: {
58
+ jest: "^29.0.0",
59
+ },
60
+ name: "test",
61
+ },
62
+ null,
63
+ 4,
64
+ )
65
+
66
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
67
+ const errors = results[0]?.messages.filter((message) => {
68
+ return message.ruleId === "custom/no-restricted-dependencies"
69
+ })
70
+
71
+ expect(errors?.length).toBe(1)
72
+ })
73
+
74
+ test("detects pattern with wildcard", async () => {
75
+ const eslint = createEslint(["@types/*"])
76
+ const packageJson = JSON.stringify(
77
+ {
78
+ devDependencies: {
79
+ "@types/node": "^20.0.0",
80
+ "@types/react": "^18.0.0",
81
+ },
82
+ name: "test",
83
+ },
84
+ null,
85
+ 4,
86
+ )
87
+
88
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
89
+ const errors = results[0]?.messages.filter((message) => {
90
+ return message.ruleId === "custom/no-restricted-dependencies"
91
+ })
92
+
93
+ expect(errors?.length).toBe(2)
94
+ })
95
+
96
+ test("allows non-restricted packages", async () => {
97
+ const eslint = createEslint(["lodash"])
98
+ const packageJson = JSON.stringify(
99
+ {
100
+ dependencies: {
101
+ react: "^18.0.0",
102
+ },
103
+ name: "test",
104
+ },
105
+ null,
106
+ 4,
107
+ )
108
+
109
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
110
+ const errors = results[0]?.messages.filter((message) => {
111
+ return message.ruleId === "custom/no-restricted-dependencies"
112
+ })
113
+
114
+ expect(errors?.length).toBe(0)
115
+ })
116
+
117
+ test("detects multiple restricted packages", async () => {
118
+ const eslint = createEslint(["lodash", "ramda", "underscore"])
119
+ const packageJson = JSON.stringify(
120
+ {
121
+ dependencies: {
122
+ lodash: "^4.0.0",
123
+ ramda: "^0.29.0",
124
+ react: "^18.0.0",
125
+ },
126
+ name: "test",
127
+ },
128
+ null,
129
+ 4,
130
+ )
131
+
132
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
133
+ const errors = results[0]?.messages.filter((message) => {
134
+ return message.ruleId === "custom/no-restricted-dependencies"
135
+ })
136
+
137
+ expect(errors?.length).toBe(2)
138
+ })
139
+
140
+ test("handles empty packages list", async () => {
141
+ const eslint = createEslint([])
142
+ const packageJson = JSON.stringify(
143
+ {
144
+ dependencies: {
145
+ lodash: "^4.0.0",
146
+ },
147
+ name: "test",
148
+ },
149
+ null,
150
+ 4,
151
+ )
152
+
153
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
154
+ const errors = results[0]?.messages.filter((message) => {
155
+ return message.ruleId === "custom/no-restricted-dependencies"
156
+ })
157
+
158
+ expect(errors?.length).toBe(0)
159
+ })
160
+ })
@@ -0,0 +1,86 @@
1
+ const DEFAULT_ALLOWED_VERSIONS = ["24"]
2
+
3
+ /**
4
+ * Extracts the major version number from a node engine string. Handles formats like ">=20",
5
+ * ">=20.0.0", "^20", "20.x", "20", etc.
6
+ *
7
+ * @param {string} engineValue - The engines.node value
8
+ * @returns {string | null} The major version number or null if not parsable
9
+ */
10
+ function extractMajorVersion(engineValue) {
11
+ const match = /(\d+)/.exec(engineValue)
12
+
13
+ return match?.[1] ?? null
14
+ }
15
+
16
+ export const validEnginesNode = {
17
+ create(context) {
18
+ const options = context.options[0] || {}
19
+ const allowedVersions = options.versions || DEFAULT_ALLOWED_VERSIONS
20
+
21
+ return {
22
+ JSONProperty(node) {
23
+ if (node.key.type !== "JSONLiteral" || node.key.value !== "engines") {
24
+ return
25
+ }
26
+
27
+ if (node.value.type !== "JSONObjectExpression") {
28
+ return
29
+ }
30
+
31
+ const nodeEngine = node.value.properties.find((prop) => {
32
+ return prop.key.type === "JSONLiteral" && prop.key.value === "node"
33
+ })
34
+
35
+ if (!nodeEngine) {
36
+ return
37
+ }
38
+
39
+ if (nodeEngine.value.type !== "JSONLiteral") {
40
+ return
41
+ }
42
+
43
+ const engineValue = nodeEngine.value.value
44
+
45
+ if (typeof engineValue !== "string") {
46
+ return
47
+ }
48
+
49
+ const majorVersion = extractMajorVersion(engineValue)
50
+
51
+ if (!majorVersion || !allowedVersions.includes(majorVersion)) {
52
+ context.report({
53
+ data: {
54
+ allowed: allowedVersions.join(", "),
55
+ value: engineValue,
56
+ },
57
+ messageId: "invalidVersion",
58
+ node: nodeEngine.value,
59
+ })
60
+ }
61
+ },
62
+ }
63
+ },
64
+ meta: {
65
+ docs: {
66
+ description: "Restrict engines.node to specific LTS versions.",
67
+ },
68
+ messages: {
69
+ invalidVersion: `Node engine "{{value}}" is not allowed. Use one of the LTS versions: {{allowed}}.`,
70
+ },
71
+ schema: [
72
+ {
73
+ additionalProperties: false,
74
+ properties: {
75
+ versions: {
76
+ description: "List of allowed major Node.js versions",
77
+ items: { type: "string" },
78
+ type: "array",
79
+ },
80
+ },
81
+ type: "object",
82
+ },
83
+ ],
84
+ type: "problem",
85
+ },
86
+ }
@@ -0,0 +1,154 @@
1
+ import { ESLint } from "eslint"
2
+ import jsoncParser from "jsonc-eslint-parser"
3
+
4
+ import { validEnginesNode } from "./valid-engines-node.js"
5
+
6
+ const createEslint = (versions) => {
7
+ return new ESLint({
8
+ overrideConfig: [
9
+ {
10
+ files: ["**/package.json"],
11
+ languageOptions: {
12
+ parser: jsoncParser,
13
+ },
14
+ plugins: {
15
+ custom: {
16
+ rules: {
17
+ "valid-engines-node": validEnginesNode,
18
+ },
19
+ },
20
+ },
21
+ rules: {
22
+ "custom/valid-engines-node": ["error", { versions }],
23
+ },
24
+ },
25
+ ],
26
+ overrideConfigFile: true,
27
+ })
28
+ }
29
+
30
+ describe("valid-engines-node", () => {
31
+ test("allows valid LTS version", async () => {
32
+ const eslint = createEslint(["24"])
33
+ const packageJson = JSON.stringify(
34
+ {
35
+ engines: {
36
+ node: ">=24.0.0",
37
+ },
38
+ name: "test",
39
+ },
40
+ null,
41
+ 4,
42
+ )
43
+
44
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
45
+ const errors = results[0]?.messages.filter((message) => {
46
+ return message.ruleId === "custom/valid-engines-node"
47
+ })
48
+
49
+ expect(errors?.length).toBe(0)
50
+ })
51
+
52
+ test("allows version with just major number", async () => {
53
+ const eslint = createEslint(["24"])
54
+ const packageJson = JSON.stringify(
55
+ {
56
+ engines: {
57
+ node: ">=24",
58
+ },
59
+ name: "test",
60
+ },
61
+ null,
62
+ 4,
63
+ )
64
+
65
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
66
+ const errors = results[0]?.messages.filter((message) => {
67
+ return message.ruleId === "custom/valid-engines-node"
68
+ })
69
+
70
+ expect(errors?.length).toBe(0)
71
+ })
72
+
73
+ test("rejects non-LTS version", async () => {
74
+ const eslint = createEslint(["24"])
75
+ const packageJson = JSON.stringify(
76
+ {
77
+ engines: {
78
+ node: ">=18.0.0",
79
+ },
80
+ name: "test",
81
+ },
82
+ null,
83
+ 4,
84
+ )
85
+
86
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
87
+ const errors = results[0]?.messages.filter((message) => {
88
+ return message.ruleId === "custom/valid-engines-node"
89
+ })
90
+
91
+ expect(errors?.length).toBe(1)
92
+ expect(errors?.[0]?.message).toContain("18.0.0")
93
+ })
94
+
95
+ test("rejects odd version numbers", async () => {
96
+ const eslint = createEslint(["24"])
97
+ const packageJson = JSON.stringify(
98
+ {
99
+ engines: {
100
+ node: ">=21.0.0",
101
+ },
102
+ name: "test",
103
+ },
104
+ null,
105
+ 4,
106
+ )
107
+
108
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
109
+ const errors = results[0]?.messages.filter((message) => {
110
+ return message.ruleId === "custom/valid-engines-node"
111
+ })
112
+
113
+ expect(errors?.length).toBe(1)
114
+ })
115
+
116
+ test("handles missing engines field", async () => {
117
+ const eslint = createEslint(["24"])
118
+ const packageJson = JSON.stringify(
119
+ {
120
+ name: "test",
121
+ },
122
+ null,
123
+ 4,
124
+ )
125
+
126
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
127
+ const errors = results[0]?.messages.filter((message) => {
128
+ return message.ruleId === "custom/valid-engines-node"
129
+ })
130
+
131
+ expect(errors?.length).toBe(0)
132
+ })
133
+
134
+ test("handles missing node in engines", async () => {
135
+ const eslint = createEslint(["24"])
136
+ const packageJson = JSON.stringify(
137
+ {
138
+ engines: {
139
+ npm: ">=9",
140
+ },
141
+ name: "test",
142
+ },
143
+ null,
144
+ 4,
145
+ )
146
+
147
+ const results = await eslint.lintText(packageJson, { filePath: "package.json" })
148
+ const errors = results[0]?.messages.filter((message) => {
149
+ return message.ruleId === "custom/valid-engines-node"
150
+ })
151
+
152
+ expect(errors?.length).toBe(0)
153
+ })
154
+ })
@@ -1,8 +0,0 @@
1
- import packageJsonCore from "../plugins/package-json.js"
2
-
3
- /** @type {import("npm-package-json-lint/dist/src/configuration").Config} */
4
- const config = {
5
- ...packageJsonCore,
6
- }
7
-
8
- export default config
@@ -1,81 +0,0 @@
1
- /** @type {import("npm-package-json-lint/dist/src/configuration").Config} */
2
- const plugin = {
3
- rules: {
4
- "bin-type": "error",
5
- "bundledDependencies-type": "error",
6
- "config-type": "error",
7
- "cpu-type": "error",
8
- "dependencies-type": "error",
9
- "description-format": [
10
- "error",
11
- {
12
- "name-format": "error",
13
- "no-duplicate-properties": "error",
14
- requireCapitalFirstLetter: true,
15
- requireEndingPeriod: false,
16
-
17
- "version-format": "error",
18
- },
19
- ],
20
- "description-type": "error",
21
- "devDependencies-type": "error",
22
- "directories-type": "error",
23
- "engines-type": "error",
24
- "files-type": "error",
25
- "homepage-type": "error",
26
- "keywords-type": "error",
27
- "license-type": "error",
28
- "main-type": "error",
29
- "man-type": "error",
30
- "name-type": "error",
31
- "no-archive-dependencies": "error",
32
- "no-archive-devDependencies": "error",
33
- "no-caret-version-dependencies": "error",
34
- "no-caret-version-devDependencies": "error",
35
- "no-file-dependencies": "error",
36
- "no-file-devDependencies": "error",
37
- "no-git-dependencies": "error",
38
- "no-git-devDependencies": "error",
39
- "no-repeated-dependencies": "error",
40
- "no-restricted-dependencies": [
41
- "error",
42
- [
43
- "typeorm",
44
- "ramda",
45
- "lodash",
46
- "@types/*",
47
- "eslint",
48
- "prettier",
49
- "cspell",
50
- "npm-package-json-lint",
51
- "stylelint",
52
- ],
53
- ],
54
- "no-tilde-version-dependencies": "error",
55
- "no-tilde-version-devDependencies": "error",
56
- "optionalDependencies-type": "error",
57
- "os-type": "error",
58
- "peerDependencies-type": "error",
59
- "prefer-absolute-version-devDependencies": "error",
60
- "prefer-alphabetical-dependencies": "error",
61
- "preferGlobal-type": "error",
62
- "private-type": "error",
63
- "repository-type": "error",
64
- "require-author": "error",
65
- "require-description": "error",
66
- "require-engines": "error",
67
- "require-license": "error",
68
- "require-name": "error",
69
- "require-repository": "error",
70
- "require-version": "error",
71
- "scripts-type": "error",
72
- "type-type": "error",
73
- "valid-values-engines": [
74
- "error",
75
- [{ node: ">=18.0.0" }, { node: ">=20.0.0" }, { node: ">=22.0.0" }],
76
- ],
77
- "version-type": "error",
78
- },
79
- }
80
-
81
- export default plugin