@harness-engineering/eslint-plugin 0.1.0

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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +91 -0
  3. package/dist/configs/index.d.ts +5 -0
  4. package/dist/configs/index.d.ts.map +1 -0
  5. package/dist/configs/index.js +8 -0
  6. package/dist/configs/index.js.map +1 -0
  7. package/dist/configs/recommended.d.ts +4 -0
  8. package/dist/configs/recommended.d.ts.map +1 -0
  9. package/dist/configs/recommended.js +16 -0
  10. package/dist/configs/recommended.js.map +1 -0
  11. package/dist/configs/strict.d.ts +4 -0
  12. package/dist/configs/strict.d.ts.map +1 -0
  13. package/dist/configs/strict.js +16 -0
  14. package/dist/configs/strict.js.map +1 -0
  15. package/dist/index.d.ts +134 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +46 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/rules/enforce-doc-exports.d.ts +12 -0
  20. package/dist/rules/enforce-doc-exports.d.ts.map +1 -0
  21. package/dist/rules/enforce-doc-exports.js +78 -0
  22. package/dist/rules/enforce-doc-exports.js.map +1 -0
  23. package/dist/rules/index.d.ts +21 -0
  24. package/dist/rules/index.d.ts.map +1 -0
  25. package/dist/rules/index.js +14 -0
  26. package/dist/rules/index.js.map +1 -0
  27. package/dist/rules/no-circular-deps.d.ts +20 -0
  28. package/dist/rules/no-circular-deps.d.ts.map +1 -0
  29. package/dist/rules/no-circular-deps.js +110 -0
  30. package/dist/rules/no-circular-deps.js.map +1 -0
  31. package/dist/rules/no-forbidden-imports.d.ts +6 -0
  32. package/dist/rules/no-forbidden-imports.d.ts.map +1 -0
  33. package/dist/rules/no-forbidden-imports.js +58 -0
  34. package/dist/rules/no-forbidden-imports.js.map +1 -0
  35. package/dist/rules/no-layer-violation.d.ts +6 -0
  36. package/dist/rules/no-layer-violation.d.ts.map +1 -0
  37. package/dist/rules/no-layer-violation.js +62 -0
  38. package/dist/rules/no-layer-violation.js.map +1 -0
  39. package/dist/rules/require-boundary-schema.d.ts +6 -0
  40. package/dist/rules/require-boundary-schema.d.ts.map +1 -0
  41. package/dist/rules/require-boundary-schema.js +53 -0
  42. package/dist/rules/require-boundary-schema.js.map +1 -0
  43. package/dist/utils/ast-helpers.d.ts +14 -0
  44. package/dist/utils/ast-helpers.d.ts.map +1 -0
  45. package/dist/utils/ast-helpers.js +94 -0
  46. package/dist/utils/ast-helpers.js.map +1 -0
  47. package/dist/utils/config-loader.d.ts +10 -0
  48. package/dist/utils/config-loader.d.ts.map +1 -0
  49. package/dist/utils/config-loader.js +56 -0
  50. package/dist/utils/config-loader.js.map +1 -0
  51. package/dist/utils/index.d.ts +5 -0
  52. package/dist/utils/index.d.ts.map +1 -0
  53. package/dist/utils/index.js +6 -0
  54. package/dist/utils/index.js.map +1 -0
  55. package/dist/utils/path-utils.d.ts +24 -0
  56. package/dist/utils/path-utils.d.ts.map +1 -0
  57. package/dist/utils/path-utils.js +62 -0
  58. package/dist/utils/path-utils.js.map +1 -0
  59. package/dist/utils/schema.d.ts +117 -0
  60. package/dist/utils/schema.d.ts.map +1 -0
  61. package/dist/utils/schema.js +34 -0
  62. package/dist/utils/schema.js.map +1 -0
  63. package/package.json +62 -0
@@ -0,0 +1,62 @@
1
+ // src/utils/path-utils.ts
2
+ import * as path from 'path';
3
+ import { minimatch } from 'minimatch';
4
+ /**
5
+ * Resolve an import path relative to the importing file
6
+ * Returns path relative to project root (assumes /project/ prefix)
7
+ */
8
+ export function resolveImportPath(importPath, importingFile) {
9
+ // External/absolute imports stay as-is
10
+ if (!importPath.startsWith('.')) {
11
+ return importPath;
12
+ }
13
+ // Resolve relative to importing file's directory
14
+ const importingDir = path.dirname(importingFile);
15
+ const resolved = path.resolve(importingDir, importPath);
16
+ // Extract path relative to project root
17
+ // Assumes paths like /project/src/... or /path/to/project/src/...
18
+ const srcIndex = resolved.indexOf('/src/');
19
+ if (srcIndex !== -1) {
20
+ return resolved.slice(srcIndex + 1); // Remove leading /
21
+ }
22
+ // Fallback: return as-is if no src/ found
23
+ return importPath;
24
+ }
25
+ /**
26
+ * Check if a file path matches a glob pattern
27
+ */
28
+ export function matchesPattern(filePath, pattern) {
29
+ // Normalize path separators
30
+ const normalizedPath = filePath.replace(/\\/g, '/');
31
+ const normalizedPattern = pattern.replace(/\\/g, '/');
32
+ return minimatch(normalizedPath, normalizedPattern, { matchBase: false });
33
+ }
34
+ /**
35
+ * Find which layer a file belongs to
36
+ */
37
+ export function getLayerForFile(filePath, layers) {
38
+ for (const layer of layers) {
39
+ if (matchesPattern(filePath, layer.pattern)) {
40
+ return layer.name;
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ /**
46
+ * Get layer definition by name
47
+ */
48
+ export function getLayerByName(name, layers) {
49
+ return layers.find((l) => l.name === name);
50
+ }
51
+ /**
52
+ * Normalize a file path to project-relative format
53
+ * Extracts path from /any/path/src/... to src/...
54
+ */
55
+ export function normalizePath(filePath) {
56
+ const srcIndex = filePath.indexOf('/src/');
57
+ if (srcIndex !== -1) {
58
+ return filePath.slice(srcIndex + 1);
59
+ }
60
+ return filePath;
61
+ }
62
+ //# sourceMappingURL=path-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../../src/utils/path-utils.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB,EAAE,aAAqB;IACzE,uCAAuC;IACvC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,iDAAiD;IACjD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAExD,wCAAwC;IACxC,kEAAkE;IAClE,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB;IAC1D,CAAC;IAED,0CAA0C;IAC1C,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,OAAe;IAC9D,4BAA4B;IAC5B,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACpD,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEtD,OAAO,SAAS,CAAC,cAAc,EAAE,iBAAiB,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,MAAe;IAC/D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5C,OAAO,KAAK,CAAC,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAAe;IAC1D,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,117 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Layer definition for architectural boundaries
4
+ */
5
+ export declare const LayerSchema: z.ZodObject<{
6
+ name: z.ZodString;
7
+ pattern: z.ZodString;
8
+ allowedDependencies: z.ZodArray<z.ZodString, "many">;
9
+ }, "strip", z.ZodTypeAny, {
10
+ name: string;
11
+ pattern: string;
12
+ allowedDependencies: string[];
13
+ }, {
14
+ name: string;
15
+ pattern: string;
16
+ allowedDependencies: string[];
17
+ }>;
18
+ /**
19
+ * Forbidden import rule
20
+ */
21
+ export declare const ForbiddenImportSchema: z.ZodObject<{
22
+ from: z.ZodString;
23
+ disallow: z.ZodArray<z.ZodString, "many">;
24
+ message: z.ZodOptional<z.ZodString>;
25
+ }, "strip", z.ZodTypeAny, {
26
+ from: string;
27
+ disallow: string[];
28
+ message?: string | undefined;
29
+ }, {
30
+ from: string;
31
+ disallow: string[];
32
+ message?: string | undefined;
33
+ }>;
34
+ /**
35
+ * Boundary validation config
36
+ */
37
+ export declare const BoundaryConfigSchema: z.ZodObject<{
38
+ requireSchema: z.ZodArray<z.ZodString, "many">;
39
+ }, "strip", z.ZodTypeAny, {
40
+ requireSchema: string[];
41
+ }, {
42
+ requireSchema: string[];
43
+ }>;
44
+ /**
45
+ * Complete harness.config.json schema
46
+ * Duplicated from @harness-engineering/cli to avoid circular dependency
47
+ */
48
+ export declare const HarnessConfigSchema: z.ZodObject<{
49
+ version: z.ZodLiteral<1>;
50
+ layers: z.ZodOptional<z.ZodArray<z.ZodObject<{
51
+ name: z.ZodString;
52
+ pattern: z.ZodString;
53
+ allowedDependencies: z.ZodArray<z.ZodString, "many">;
54
+ }, "strip", z.ZodTypeAny, {
55
+ name: string;
56
+ pattern: string;
57
+ allowedDependencies: string[];
58
+ }, {
59
+ name: string;
60
+ pattern: string;
61
+ allowedDependencies: string[];
62
+ }>, "many">>;
63
+ forbiddenImports: z.ZodOptional<z.ZodArray<z.ZodObject<{
64
+ from: z.ZodString;
65
+ disallow: z.ZodArray<z.ZodString, "many">;
66
+ message: z.ZodOptional<z.ZodString>;
67
+ }, "strip", z.ZodTypeAny, {
68
+ from: string;
69
+ disallow: string[];
70
+ message?: string | undefined;
71
+ }, {
72
+ from: string;
73
+ disallow: string[];
74
+ message?: string | undefined;
75
+ }>, "many">>;
76
+ boundaries: z.ZodOptional<z.ZodObject<{
77
+ requireSchema: z.ZodArray<z.ZodString, "many">;
78
+ }, "strip", z.ZodTypeAny, {
79
+ requireSchema: string[];
80
+ }, {
81
+ requireSchema: string[];
82
+ }>>;
83
+ }, "strip", z.ZodTypeAny, {
84
+ version: 1;
85
+ layers?: {
86
+ name: string;
87
+ pattern: string;
88
+ allowedDependencies: string[];
89
+ }[] | undefined;
90
+ forbiddenImports?: {
91
+ from: string;
92
+ disallow: string[];
93
+ message?: string | undefined;
94
+ }[] | undefined;
95
+ boundaries?: {
96
+ requireSchema: string[];
97
+ } | undefined;
98
+ }, {
99
+ version: 1;
100
+ layers?: {
101
+ name: string;
102
+ pattern: string;
103
+ allowedDependencies: string[];
104
+ }[] | undefined;
105
+ forbiddenImports?: {
106
+ from: string;
107
+ disallow: string[];
108
+ message?: string | undefined;
109
+ }[] | undefined;
110
+ boundaries?: {
111
+ requireSchema: string[];
112
+ } | undefined;
113
+ }>;
114
+ export type HarnessConfig = z.infer<typeof HarnessConfigSchema>;
115
+ export type Layer = z.infer<typeof LayerSchema>;
116
+ export type ForbiddenImport = z.infer<typeof ForbiddenImportSchema>;
117
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/utils/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;EAItB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;EAIhC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;EAE/B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAK9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAChD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Layer definition for architectural boundaries
4
+ */
5
+ export const LayerSchema = z.object({
6
+ name: z.string(),
7
+ pattern: z.string(),
8
+ allowedDependencies: z.array(z.string()),
9
+ });
10
+ /**
11
+ * Forbidden import rule
12
+ */
13
+ export const ForbiddenImportSchema = z.object({
14
+ from: z.string(),
15
+ disallow: z.array(z.string()),
16
+ message: z.string().optional(),
17
+ });
18
+ /**
19
+ * Boundary validation config
20
+ */
21
+ export const BoundaryConfigSchema = z.object({
22
+ requireSchema: z.array(z.string()),
23
+ });
24
+ /**
25
+ * Complete harness.config.json schema
26
+ * Duplicated from @harness-engineering/cli to avoid circular dependency
27
+ */
28
+ export const HarnessConfigSchema = z.object({
29
+ version: z.literal(1),
30
+ layers: z.array(LayerSchema).optional(),
31
+ forbiddenImports: z.array(ForbiddenImportSchema).optional(),
32
+ boundaries: BoundaryConfigSchema.optional(),
33
+ });
34
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/utils/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,mBAAmB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACzC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC7B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACnC,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE;IACvC,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,QAAQ,EAAE;IAC3D,UAAU,EAAE,oBAAoB,CAAC,QAAQ,EAAE;CAC5C,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@harness-engineering/eslint-plugin",
3
+ "version": "0.1.0",
4
+ "description": "ESLint plugin for harness engineering architectural constraints",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "dependencies": {
19
+ "@typescript-eslint/utils": "^8.0.0",
20
+ "minimatch": "^9.0.0",
21
+ "zod": "^3.22.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.0.0",
25
+ "@typescript-eslint/parser": "^8.57.0",
26
+ "@typescript-eslint/rule-tester": "^8.0.0",
27
+ "eslint": "^10.0.0",
28
+ "typescript": "^5.0.0",
29
+ "vitest": "^2.0.0"
30
+ },
31
+ "peerDependencies": {
32
+ "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0",
33
+ "typescript": "^5.0.0"
34
+ },
35
+ "keywords": [
36
+ "eslint",
37
+ "eslint-plugin",
38
+ "harness",
39
+ "architecture",
40
+ "layers"
41
+ ],
42
+ "license": "MIT",
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/Intense-Visions/harness-engineering.git",
49
+ "directory": "packages/eslint-plugin"
50
+ },
51
+ "bugs": {
52
+ "url": "https://github.com/Intense-Visions/harness-engineering/issues"
53
+ },
54
+ "homepage": "https://github.com/Intense-Visions/harness-engineering/tree/main/packages/eslint-plugin#readme",
55
+ "scripts": {
56
+ "build": "tsc",
57
+ "test": "vitest run",
58
+ "test:watch": "vitest",
59
+ "lint": "eslint src",
60
+ "clean": "rm -rf dist"
61
+ }
62
+ }