@harness-engineering/eslint-plugin 0.1.2 → 0.2.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.
- package/dist/index.d.ts +95 -32
- package/dist/index.js +929 -43
- package/package.json +4 -3
- package/dist/configs/index.d.ts +0 -5
- package/dist/configs/index.d.ts.map +0 -1
- package/dist/configs/index.js +0 -8
- package/dist/configs/index.js.map +0 -1
- package/dist/configs/recommended.d.ts +0 -4
- package/dist/configs/recommended.d.ts.map +0 -1
- package/dist/configs/recommended.js +0 -16
- package/dist/configs/recommended.js.map +0 -1
- package/dist/configs/strict.d.ts +0 -4
- package/dist/configs/strict.d.ts.map +0 -1
- package/dist/configs/strict.js +0 -16
- package/dist/configs/strict.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/rules/enforce-doc-exports.d.ts +0 -12
- package/dist/rules/enforce-doc-exports.d.ts.map +0 -1
- package/dist/rules/enforce-doc-exports.js +0 -78
- package/dist/rules/enforce-doc-exports.js.map +0 -1
- package/dist/rules/index.d.ts +0 -30
- package/dist/rules/index.d.ts.map +0 -1
- package/dist/rules/index.js +0 -20
- package/dist/rules/index.js.map +0 -1
- package/dist/rules/no-circular-deps.d.ts +0 -20
- package/dist/rules/no-circular-deps.d.ts.map +0 -1
- package/dist/rules/no-circular-deps.js +0 -110
- package/dist/rules/no-circular-deps.js.map +0 -1
- package/dist/rules/no-forbidden-imports.d.ts +0 -6
- package/dist/rules/no-forbidden-imports.d.ts.map +0 -1
- package/dist/rules/no-forbidden-imports.js +0 -58
- package/dist/rules/no-forbidden-imports.js.map +0 -1
- package/dist/rules/no-layer-violation.d.ts +0 -6
- package/dist/rules/no-layer-violation.d.ts.map +0 -1
- package/dist/rules/no-layer-violation.js +0 -62
- package/dist/rules/no-layer-violation.js.map +0 -1
- package/dist/rules/no-nested-loops-in-critical.d.ts +0 -6
- package/dist/rules/no-nested-loops-in-critical.d.ts.map +0 -1
- package/dist/rules/no-nested-loops-in-critical.js +0 -87
- package/dist/rules/no-nested-loops-in-critical.js.map +0 -1
- package/dist/rules/no-sync-io-in-async.d.ts +0 -6
- package/dist/rules/no-sync-io-in-async.d.ts.map +0 -1
- package/dist/rules/no-sync-io-in-async.js +0 -73
- package/dist/rules/no-sync-io-in-async.js.map +0 -1
- package/dist/rules/no-unbounded-array-chains.d.ts +0 -6
- package/dist/rules/no-unbounded-array-chains.d.ts.map +0 -1
- package/dist/rules/no-unbounded-array-chains.js +0 -71
- package/dist/rules/no-unbounded-array-chains.js.map +0 -1
- package/dist/rules/require-boundary-schema.d.ts +0 -6
- package/dist/rules/require-boundary-schema.d.ts.map +0 -1
- package/dist/rules/require-boundary-schema.js +0 -53
- package/dist/rules/require-boundary-schema.js.map +0 -1
- package/dist/utils/ast-helpers.d.ts +0 -14
- package/dist/utils/ast-helpers.d.ts.map +0 -1
- package/dist/utils/ast-helpers.js +0 -94
- package/dist/utils/ast-helpers.js.map +0 -1
- package/dist/utils/config-loader.d.ts +0 -10
- package/dist/utils/config-loader.d.ts.map +0 -1
- package/dist/utils/config-loader.js +0 -56
- package/dist/utils/config-loader.js.map +0 -1
- package/dist/utils/index.d.ts +0 -5
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -6
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/path-utils.d.ts +0 -24
- package/dist/utils/path-utils.d.ts.map +0 -1
- package/dist/utils/path-utils.js +0 -62
- package/dist/utils/path-utils.js.map +0 -1
- package/dist/utils/schema.d.ts +0 -117
- package/dist/utils/schema.d.ts.map +0 -1
- package/dist/utils/schema.js +0 -34
- package/dist/utils/schema.js.map +0 -1
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// src/rules/no-nested-loops-in-critical.ts
|
|
2
|
-
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
3
|
-
const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/harness-engineering/eslint-plugin/blob/main/docs/rules/${name}.md`);
|
|
4
|
-
export default createRule({
|
|
5
|
-
name: 'no-nested-loops-in-critical',
|
|
6
|
-
meta: {
|
|
7
|
-
type: 'suggestion',
|
|
8
|
-
docs: {
|
|
9
|
-
description: 'Disallow nested loops in @perf-critical functions',
|
|
10
|
-
},
|
|
11
|
-
messages: {
|
|
12
|
-
nestedLoopInCritical: 'Nested loop in @perf-critical code — consider alternative algorithm',
|
|
13
|
-
},
|
|
14
|
-
schema: [],
|
|
15
|
-
},
|
|
16
|
-
defaultOptions: [],
|
|
17
|
-
create(context) {
|
|
18
|
-
const sourceText = context.sourceCode.getText();
|
|
19
|
-
// Quick check: if the file has no @perf-critical at all, skip entirely
|
|
20
|
-
if (!sourceText.includes('@perf-critical')) {
|
|
21
|
-
return {};
|
|
22
|
-
}
|
|
23
|
-
// Stack tracks whether each nested function scope is @perf-critical
|
|
24
|
-
const criticalStack = [];
|
|
25
|
-
let loopDepth = 0;
|
|
26
|
-
function isCritical() {
|
|
27
|
-
return criticalStack.length > 0 && criticalStack[criticalStack.length - 1] === true;
|
|
28
|
-
}
|
|
29
|
-
function hasCriticalAnnotation(node) {
|
|
30
|
-
// Check the source lines immediately before this function for @perf-critical.
|
|
31
|
-
// For JSDoc: `/** @perf-critical */` is typically 1 line before.
|
|
32
|
-
// For line comment: `// @perf-critical` is 1 line before.
|
|
33
|
-
const target = node.parent?.type === 'ExportNamedDeclaration' ||
|
|
34
|
-
node.parent?.type === 'VariableDeclaration'
|
|
35
|
-
? node.parent
|
|
36
|
-
: node;
|
|
37
|
-
const startLine = target.loc.start.line; // 1-indexed
|
|
38
|
-
const lines = sourceText.split('\n');
|
|
39
|
-
// Only check the line immediately before the function (or same line for inline)
|
|
40
|
-
for (let i = Math.max(0, startLine - 2); i < startLine; i++) {
|
|
41
|
-
if (lines[i]?.includes('@perf-critical'))
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
function enterFunction(node) {
|
|
47
|
-
criticalStack.push(hasCriticalAnnotation(node));
|
|
48
|
-
loopDepth = 0;
|
|
49
|
-
}
|
|
50
|
-
function exitFunction() {
|
|
51
|
-
criticalStack.pop();
|
|
52
|
-
loopDepth = 0;
|
|
53
|
-
}
|
|
54
|
-
function enterLoop(node) {
|
|
55
|
-
if (!isCritical())
|
|
56
|
-
return;
|
|
57
|
-
loopDepth++;
|
|
58
|
-
if (loopDepth > 1) {
|
|
59
|
-
context.report({ node, messageId: 'nestedLoopInCritical' });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function exitLoop() {
|
|
63
|
-
if (!isCritical())
|
|
64
|
-
return;
|
|
65
|
-
loopDepth--;
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
FunctionDeclaration: enterFunction,
|
|
69
|
-
'FunctionDeclaration:exit': exitFunction,
|
|
70
|
-
FunctionExpression: enterFunction,
|
|
71
|
-
'FunctionExpression:exit': exitFunction,
|
|
72
|
-
ArrowFunctionExpression: enterFunction,
|
|
73
|
-
'ArrowFunctionExpression:exit': exitFunction,
|
|
74
|
-
ForStatement: enterLoop,
|
|
75
|
-
'ForStatement:exit': exitLoop,
|
|
76
|
-
ForInStatement: enterLoop,
|
|
77
|
-
'ForInStatement:exit': exitLoop,
|
|
78
|
-
ForOfStatement: enterLoop,
|
|
79
|
-
'ForOfStatement:exit': exitLoop,
|
|
80
|
-
WhileStatement: enterLoop,
|
|
81
|
-
'WhileStatement:exit': exitLoop,
|
|
82
|
-
DoWhileStatement: enterLoop,
|
|
83
|
-
'DoWhileStatement:exit': exitLoop,
|
|
84
|
-
};
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
//# sourceMappingURL=no-nested-loops-in-critical.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-nested-loops-in-critical.js","sourceRoot":"","sources":["../../src/rules/no-nested-loops-in-critical.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-sync-io-in-async.d.ts","sourceRoot":"","sources":["../../src/rules/no-sync-io-in-async.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAiB,MAAM,0BAA0B,CAAC;;;;AAqBtE,wBA2EG"}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
// src/rules/no-sync-io-in-async.ts
|
|
2
|
-
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
3
|
-
const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/harness-engineering/eslint-plugin/blob/main/docs/rules/${name}.md`);
|
|
4
|
-
const SYNC_FS_METHODS = new Set([
|
|
5
|
-
'readFileSync',
|
|
6
|
-
'writeFileSync',
|
|
7
|
-
'existsSync',
|
|
8
|
-
'readdirSync',
|
|
9
|
-
'statSync',
|
|
10
|
-
'mkdirSync',
|
|
11
|
-
'unlinkSync',
|
|
12
|
-
'copyFileSync',
|
|
13
|
-
'renameSync',
|
|
14
|
-
'accessSync',
|
|
15
|
-
]);
|
|
16
|
-
export default createRule({
|
|
17
|
-
name: 'no-sync-io-in-async',
|
|
18
|
-
meta: {
|
|
19
|
-
type: 'problem',
|
|
20
|
-
docs: {
|
|
21
|
-
description: 'Disallow synchronous fs operations inside async functions',
|
|
22
|
-
},
|
|
23
|
-
messages: {
|
|
24
|
-
syncIoInAsync: "Use async fs methods instead of '{{name}}' in async functions",
|
|
25
|
-
},
|
|
26
|
-
schema: [],
|
|
27
|
-
},
|
|
28
|
-
defaultOptions: [],
|
|
29
|
-
create(context) {
|
|
30
|
-
let asyncDepth = 0;
|
|
31
|
-
function enterFunction(node) {
|
|
32
|
-
if (node.async) {
|
|
33
|
-
asyncDepth++;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function exitFunction(node) {
|
|
37
|
-
if (node.async) {
|
|
38
|
-
asyncDepth--;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return {
|
|
42
|
-
FunctionDeclaration: enterFunction,
|
|
43
|
-
'FunctionDeclaration:exit': exitFunction,
|
|
44
|
-
FunctionExpression: enterFunction,
|
|
45
|
-
'FunctionExpression:exit': exitFunction,
|
|
46
|
-
ArrowFunctionExpression: enterFunction,
|
|
47
|
-
'ArrowFunctionExpression:exit': exitFunction,
|
|
48
|
-
CallExpression(node) {
|
|
49
|
-
if (asyncDepth === 0)
|
|
50
|
-
return;
|
|
51
|
-
let name;
|
|
52
|
-
// Handle: readFileSync(...)
|
|
53
|
-
if (node.callee.type === 'Identifier' && SYNC_FS_METHODS.has(node.callee.name)) {
|
|
54
|
-
name = node.callee.name;
|
|
55
|
-
}
|
|
56
|
-
// Handle: fs.readFileSync(...)
|
|
57
|
-
if (node.callee.type === 'MemberExpression' &&
|
|
58
|
-
node.callee.property.type === 'Identifier' &&
|
|
59
|
-
SYNC_FS_METHODS.has(node.callee.property.name)) {
|
|
60
|
-
name = node.callee.property.name;
|
|
61
|
-
}
|
|
62
|
-
if (name) {
|
|
63
|
-
context.report({
|
|
64
|
-
node,
|
|
65
|
-
messageId: 'syncIoInAsync',
|
|
66
|
-
data: { name },
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
//# sourceMappingURL=no-sync-io-in-async.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-sync-io-in-async.js","sourceRoot":"","sources":["../../src/rules/no-sync-io-in-async.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,OAAO,EAAE,WAAW,EAAiB,MAAM,0BAA0B,CAAC;AAEtE,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,6EAA6E,IAAI,KAAK,CACjG,CAAC;AAIF,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,cAAc;IACd,eAAe;IACf,YAAY;IACZ,aAAa;IACb,UAAU;IACV,WAAW;IACX,YAAY;IACZ,cAAc;IACd,YAAY;IACZ,YAAY;CACb,CAAC,CAAC;AAEH,eAAe,UAAU,CAAiB;IACxC,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,2DAA2D;SACzE;QACD,QAAQ,EAAE;YACR,aAAa,EAAE,+DAA+D;SAC/E;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,SAAS,aAAa,CACpB,IAGoC;YAEpC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,UAAU,EAAE,CAAC;YACf,CAAC;QACH,CAAC;QAED,SAAS,YAAY,CACnB,IAGoC;YAEpC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,UAAU,EAAE,CAAC;YACf,CAAC;QACH,CAAC;QAED,OAAO;YACL,mBAAmB,EAAE,aAAa;YAClC,0BAA0B,EAAE,YAAY;YACxC,kBAAkB,EAAE,aAAa;YACjC,yBAAyB,EAAE,YAAY;YACvC,uBAAuB,EAAE,aAAa;YACtC,8BAA8B,EAAE,YAAY;YAE5C,cAAc,CAAC,IAA6B;gBAC1C,IAAI,UAAU,KAAK,CAAC;oBAAE,OAAO;gBAE7B,IAAI,IAAwB,CAAC;gBAE7B,4BAA4B;gBAC5B,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/E,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC1B,CAAC;gBAED,+BAA+B;gBAC/B,IACE,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBAC1C,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAC9C,CAAC;oBACD,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACnC,CAAC;gBAED,IAAI,IAAI,EAAE,CAAC;oBACT,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,eAAe;wBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE;qBACf,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
declare const _default: ESLintUtils.RuleModule<"unboundedArrayChain", [], unknown, ESLintUtils.RuleListener> & {
|
|
3
|
-
name: string;
|
|
4
|
-
};
|
|
5
|
-
export default _default;
|
|
6
|
-
//# sourceMappingURL=no-unbounded-array-chains.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-unbounded-array-chains.d.ts","sourceRoot":"","sources":["../../src/rules/no-unbounded-array-chains.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAiB,MAAM,0BAA0B,CAAC;;;;AAoBtE,wBA+DG"}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// src/rules/no-unbounded-array-chains.ts
|
|
2
|
-
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
3
|
-
const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/harness-engineering/eslint-plugin/blob/main/docs/rules/${name}.md`);
|
|
4
|
-
const ARRAY_METHODS = new Set([
|
|
5
|
-
'filter',
|
|
6
|
-
'map',
|
|
7
|
-
'reduce',
|
|
8
|
-
'sort',
|
|
9
|
-
'flatMap',
|
|
10
|
-
'find',
|
|
11
|
-
'some',
|
|
12
|
-
'every',
|
|
13
|
-
'forEach',
|
|
14
|
-
]);
|
|
15
|
-
export default createRule({
|
|
16
|
-
name: 'no-unbounded-array-chains',
|
|
17
|
-
meta: {
|
|
18
|
-
type: 'suggestion',
|
|
19
|
-
docs: {
|
|
20
|
-
description: 'Disallow 3+ chained array operations',
|
|
21
|
-
},
|
|
22
|
-
messages: {
|
|
23
|
-
unboundedArrayChain: '3+ chained array operations — consider a single-pass approach',
|
|
24
|
-
},
|
|
25
|
-
schema: [],
|
|
26
|
-
},
|
|
27
|
-
defaultOptions: [],
|
|
28
|
-
create(context) {
|
|
29
|
-
return {
|
|
30
|
-
'CallExpression > MemberExpression.callee'(node) {
|
|
31
|
-
// Only care about array method calls
|
|
32
|
-
if (node.property.type !== 'Identifier' || !ARRAY_METHODS.has(node.property.name)) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
// Skip if this call is itself the object of another array method call
|
|
36
|
-
// (i.e., not the outermost in the chain). Only report on the outermost.
|
|
37
|
-
const callExpr = node.parent;
|
|
38
|
-
if (callExpr.parent &&
|
|
39
|
-
callExpr.parent.type === 'MemberExpression' &&
|
|
40
|
-
callExpr.parent.property.type === 'Identifier' &&
|
|
41
|
-
ARRAY_METHODS.has(callExpr.parent.property.name)) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
// Count the chain length by walking down through the object
|
|
45
|
-
let chainLength = 1;
|
|
46
|
-
let current = node;
|
|
47
|
-
while (true) {
|
|
48
|
-
const memberExpr = current;
|
|
49
|
-
const obj = memberExpr.object;
|
|
50
|
-
if (obj.type === 'CallExpression' &&
|
|
51
|
-
obj.callee.type === 'MemberExpression' &&
|
|
52
|
-
obj.callee.property.type === 'Identifier' &&
|
|
53
|
-
ARRAY_METHODS.has(obj.callee.property.name)) {
|
|
54
|
-
chainLength++;
|
|
55
|
-
current = obj.callee;
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (chainLength >= 3) {
|
|
62
|
-
context.report({
|
|
63
|
-
node: callExpr,
|
|
64
|
-
messageId: 'unboundedArrayChain',
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
//# sourceMappingURL=no-unbounded-array-chains.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-unbounded-array-chains.js","sourceRoot":"","sources":["../../src/rules/no-unbounded-array-chains.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,OAAO,EAAE,WAAW,EAAiB,MAAM,0BAA0B,CAAC;AAEtE,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,6EAA6E,IAAI,KAAK,CACjG,CAAC;AAIF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,QAAQ;IACR,KAAK;IACL,QAAQ;IACR,MAAM;IACN,SAAS;IACT,MAAM;IACN,MAAM;IACN,OAAO;IACP,SAAS;CACV,CAAC,CAAC;AAEH,eAAe,UAAU,CAAiB;IACxC,IAAI,EAAE,2BAA2B;IACjC,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,sCAAsC;SACpD;QACD,QAAQ,EAAE;YACR,mBAAmB,EAAE,+DAA+D;SACrF;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,0CAA0C,CAAC,IAA+B;gBACxE,qCAAqC;gBACrC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBAClF,OAAO;gBACT,CAAC;gBAED,sEAAsE;gBACtE,wEAAwE;gBACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAO,CAAC;gBAC9B,IACE,QAAQ,CAAC,MAAM;oBACf,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAC3C,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBAC9C,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAChD,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,4DAA4D;gBAC5D,IAAI,WAAW,GAAG,CAAC,CAAC;gBACpB,IAAI,OAAO,GAAkB,IAAI,CAAC;gBAElC,OAAO,IAAI,EAAE,CAAC;oBACZ,MAAM,UAAU,GAAG,OAAoC,CAAC;oBACxD,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC;oBAE9B,IACE,GAAG,CAAC,IAAI,KAAK,gBAAgB;wBAC7B,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;wBACtC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;wBACzC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAC3C,CAAC;wBACD,WAAW,EAAE,CAAC;wBACd,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;oBACvB,CAAC;yBAAM,CAAC;wBACN,MAAM;oBACR,CAAC;gBACH,CAAC;gBAED,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;oBACrB,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,QAAQ;wBACd,SAAS,EAAE,qBAAqB;qBACjC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"require-boundary-schema.d.ts","sourceRoot":"","sources":["../../src/rules/require-boundary-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAiC,MAAM,0BAA0B,CAAC;;;;AAWtF,wBAsDG"}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// src/rules/require-boundary-schema.ts
|
|
2
|
-
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
3
|
-
import { getConfig } from '../utils/config-loader';
|
|
4
|
-
import { matchesPattern, normalizePath } from '../utils/path-utils';
|
|
5
|
-
import { hasZodValidation } from '../utils/ast-helpers';
|
|
6
|
-
const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/harness-engineering/eslint-plugin/blob/main/docs/rules/${name}.md`);
|
|
7
|
-
export default createRule({
|
|
8
|
-
name: 'require-boundary-schema',
|
|
9
|
-
meta: {
|
|
10
|
-
type: 'problem',
|
|
11
|
-
docs: {
|
|
12
|
-
description: 'Require Zod schema validation at API boundaries',
|
|
13
|
-
},
|
|
14
|
-
messages: {
|
|
15
|
-
missingSchema: 'Exported function "{{name}}" at API boundary must validate input with Zod schema',
|
|
16
|
-
},
|
|
17
|
-
schema: [],
|
|
18
|
-
},
|
|
19
|
-
defaultOptions: [],
|
|
20
|
-
create(context) {
|
|
21
|
-
const config = getConfig(context.filename);
|
|
22
|
-
if (!config?.boundaries?.requireSchema?.length) {
|
|
23
|
-
return {}; // No-op if no boundaries configured
|
|
24
|
-
}
|
|
25
|
-
const filePath = normalizePath(context.filename);
|
|
26
|
-
// Check if file matches any boundary pattern
|
|
27
|
-
const isBoundaryFile = config.boundaries.requireSchema.some((pattern) => matchesPattern(filePath, pattern));
|
|
28
|
-
if (!isBoundaryFile) {
|
|
29
|
-
return {}; // Not a boundary file
|
|
30
|
-
}
|
|
31
|
-
return {
|
|
32
|
-
ExportNamedDeclaration(node) {
|
|
33
|
-
const decl = node.declaration;
|
|
34
|
-
// Only check function declarations
|
|
35
|
-
if (!decl || decl.type !== AST_NODE_TYPES.FunctionDeclaration) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
const fn = decl;
|
|
39
|
-
if (!fn.id || !fn.body)
|
|
40
|
-
return;
|
|
41
|
-
// Check if function has Zod validation
|
|
42
|
-
if (!hasZodValidation(fn.body)) {
|
|
43
|
-
context.report({
|
|
44
|
-
node: fn,
|
|
45
|
-
messageId: 'missingSchema',
|
|
46
|
-
data: { name: fn.id.name },
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
//# sourceMappingURL=require-boundary-schema.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"require-boundary-schema.js","sourceRoot":"","sources":["../../src/rules/require-boundary-schema.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAiB,MAAM,0BAA0B,CAAC;AACtF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CACxC,CAAC,IAAI,EAAE,EAAE,CAAC,6EAA6E,IAAI,KAAK,CACjG,CAAC;AAIF,eAAe,UAAU,CAAiB;IACxC,IAAI,EAAE,yBAAyB;IAC/B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,iDAAiD;SAC/D;QACD,QAAQ,EAAE;YACR,aAAa,EACX,kFAAkF;SACrF;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;YAC/C,OAAO,EAAE,CAAC,CAAC,oCAAoC;QACjD,CAAC;QAED,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAEjD,6CAA6C;QAC7C,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CACtE,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAClC,CAAC;QAEF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC,CAAC,sBAAsB;QACnC,CAAC;QAED,OAAO;YACL,sBAAsB,CAAC,IAAqC;gBAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;gBAE9B,mCAAmC;gBACnC,IAAI,CAAC,IAAI,IAAK,IAAI,CAAC,IAAuB,KAAK,cAAc,CAAC,mBAAmB,EAAE,CAAC;oBAClF,OAAO;gBACT,CAAC;gBAED,MAAM,EAAE,GAAG,IAAoC,CAAC;gBAChD,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI;oBAAE,OAAO;gBAE/B,uCAAuC;gBACvC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/B,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,EAAE;wBACR,SAAS,EAAE,eAAe;wBAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE;qBAC3B,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
-
/**
|
|
3
|
-
* Check if a node has a preceding JSDoc comment
|
|
4
|
-
*/
|
|
5
|
-
export declare function hasJSDocComment(node: TSESTree.Node, sourceCode: string): boolean;
|
|
6
|
-
/**
|
|
7
|
-
* Check if a function body contains Zod validation (.parse or .safeParse)
|
|
8
|
-
*/
|
|
9
|
-
export declare function hasZodValidation(body: TSESTree.BlockStatement): boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Check if a node is marked with @internal
|
|
12
|
-
*/
|
|
13
|
-
export declare function isMarkedInternal(node: TSESTree.Node, sourceCode: string): boolean;
|
|
14
|
-
//# sourceMappingURL=ast-helpers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ast-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/ast-helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzE;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CA+BhF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,cAAc,GAAG,OAAO,CA+CvE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAYjF"}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
// src/utils/ast-helpers.ts
|
|
2
|
-
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
3
|
-
/**
|
|
4
|
-
* Check if a node has a preceding JSDoc comment
|
|
5
|
-
*/
|
|
6
|
-
export function hasJSDocComment(node, sourceCode) {
|
|
7
|
-
if (!node.range)
|
|
8
|
-
return false;
|
|
9
|
-
// Get text before the node
|
|
10
|
-
const textBefore = sourceCode.slice(0, node.range[0]);
|
|
11
|
-
const lines = textBefore.split('\n');
|
|
12
|
-
// Look backwards for /** ... */
|
|
13
|
-
let foundJSDoc = false;
|
|
14
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
15
|
-
const line = lines[i]?.trim() ?? '';
|
|
16
|
-
// Empty line or whitespace - keep looking
|
|
17
|
-
if (line === '')
|
|
18
|
-
continue;
|
|
19
|
-
// Found JSDoc end
|
|
20
|
-
if (line.endsWith('*/')) {
|
|
21
|
-
// Check if it's JSDoc (starts with /**)
|
|
22
|
-
const startIdx = textBefore.lastIndexOf('/**');
|
|
23
|
-
const endIdx = textBefore.lastIndexOf('*/');
|
|
24
|
-
if (startIdx !== -1 && endIdx > startIdx) {
|
|
25
|
-
foundJSDoc = true;
|
|
26
|
-
}
|
|
27
|
-
break;
|
|
28
|
-
}
|
|
29
|
-
// Found something else - no JSDoc
|
|
30
|
-
break;
|
|
31
|
-
}
|
|
32
|
-
return foundJSDoc;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Check if a function body contains Zod validation (.parse or .safeParse)
|
|
36
|
-
*/
|
|
37
|
-
export function hasZodValidation(body) {
|
|
38
|
-
let found = false;
|
|
39
|
-
// Keys to skip to avoid circular references
|
|
40
|
-
const skipKeys = new Set(['parent', 'loc', 'range', 'tokens', 'comments']);
|
|
41
|
-
function visit(node) {
|
|
42
|
-
if (found)
|
|
43
|
-
return;
|
|
44
|
-
if (node.type === AST_NODE_TYPES.CallExpression &&
|
|
45
|
-
node.callee.type ===
|
|
46
|
-
AST_NODE_TYPES.MemberExpression) {
|
|
47
|
-
const prop = node.callee.property;
|
|
48
|
-
const propType = prop.type;
|
|
49
|
-
if (propType === AST_NODE_TYPES.Identifier &&
|
|
50
|
-
(prop.name === 'parse' ||
|
|
51
|
-
prop.name === 'safeParse')) {
|
|
52
|
-
found = true;
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
// Recursively visit children
|
|
57
|
-
for (const key of Object.keys(node)) {
|
|
58
|
-
if (skipKeys.has(key))
|
|
59
|
-
continue;
|
|
60
|
-
const value = node[key];
|
|
61
|
-
if (value && typeof value === 'object') {
|
|
62
|
-
if (Array.isArray(value)) {
|
|
63
|
-
for (const item of value) {
|
|
64
|
-
if (item && typeof item === 'object' && 'type' in item) {
|
|
65
|
-
visit(item);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
else if ('type' in value) {
|
|
70
|
-
visit(value);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
visit(body);
|
|
76
|
-
return found;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Check if a node is marked with @internal
|
|
80
|
-
*/
|
|
81
|
-
export function isMarkedInternal(node, sourceCode) {
|
|
82
|
-
if (!node.range)
|
|
83
|
-
return false;
|
|
84
|
-
const textBefore = sourceCode.slice(0, node.range[0]);
|
|
85
|
-
const lastComment = textBefore.lastIndexOf('/**');
|
|
86
|
-
if (lastComment === -1)
|
|
87
|
-
return false;
|
|
88
|
-
const commentEnd = textBefore.lastIndexOf('*/');
|
|
89
|
-
if (commentEnd === -1 || commentEnd < lastComment)
|
|
90
|
-
return false;
|
|
91
|
-
const comment = textBefore.slice(lastComment, commentEnd + 2);
|
|
92
|
-
return comment.includes('@internal');
|
|
93
|
-
}
|
|
94
|
-
//# sourceMappingURL=ast-helpers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ast-helpers.js","sourceRoot":"","sources":["../../src/utils/ast-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type HarnessConfig } from './schema';
|
|
2
|
-
/**
|
|
3
|
-
* Load and validate config, with caching
|
|
4
|
-
*/
|
|
5
|
-
export declare function getConfig(filePath: string): HarnessConfig | null;
|
|
6
|
-
/**
|
|
7
|
-
* Clear the config cache (for testing)
|
|
8
|
-
*/
|
|
9
|
-
export declare function clearConfigCache(): void;
|
|
10
|
-
//# sourceMappingURL=config-loader.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAwBnE;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAuBhE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// src/utils/config-loader.ts
|
|
2
|
-
import * as fs from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
import { HarnessConfigSchema } from './schema';
|
|
5
|
-
const CONFIG_FILENAME = 'harness.config.json';
|
|
6
|
-
let cachedConfig = null;
|
|
7
|
-
let cachedConfigPath = null;
|
|
8
|
-
/**
|
|
9
|
-
* Find harness.config.json by walking up from the given directory
|
|
10
|
-
*/
|
|
11
|
-
function findConfigFile(startDir) {
|
|
12
|
-
let currentDir = path.resolve(startDir);
|
|
13
|
-
const root = path.parse(currentDir).root;
|
|
14
|
-
while (currentDir !== root) {
|
|
15
|
-
const configPath = path.join(currentDir, CONFIG_FILENAME);
|
|
16
|
-
if (fs.existsSync(configPath)) {
|
|
17
|
-
return configPath;
|
|
18
|
-
}
|
|
19
|
-
currentDir = path.dirname(currentDir);
|
|
20
|
-
}
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Load and validate config, with caching
|
|
25
|
-
*/
|
|
26
|
-
export function getConfig(filePath) {
|
|
27
|
-
const configPath = findConfigFile(path.dirname(filePath));
|
|
28
|
-
if (!configPath) {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
// Return cached config if same path
|
|
32
|
-
if (cachedConfigPath === configPath && cachedConfig) {
|
|
33
|
-
return cachedConfig;
|
|
34
|
-
}
|
|
35
|
-
try {
|
|
36
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
37
|
-
const parsed = HarnessConfigSchema.safeParse(JSON.parse(content));
|
|
38
|
-
if (!parsed.success) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
cachedConfig = parsed.data;
|
|
42
|
-
cachedConfigPath = configPath;
|
|
43
|
-
return cachedConfig;
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Clear the config cache (for testing)
|
|
51
|
-
*/
|
|
52
|
-
export function clearConfigCache() {
|
|
53
|
-
cachedConfig = null;
|
|
54
|
-
cachedConfigPath = null;
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=config-loader.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/utils/config-loader.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAsB,MAAM,UAAU,CAAC;AAEnE,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAE9C,IAAI,YAAY,GAAyB,IAAI,CAAC;AAC9C,IAAI,gBAAgB,GAAkB,IAAI,CAAC;AAE3C;;GAEG;AACH,SAAS,cAAc,CAAC,QAAgB;IACtC,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC;IAEzC,OAAO,UAAU,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;QAC1D,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oCAAoC;IACpC,IAAI,gBAAgB,KAAK,UAAU,IAAI,YAAY,EAAE,CAAC;QACpD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC;QAC3B,gBAAgB,GAAG,UAAU,CAAC;QAC9B,OAAO,YAAY,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,YAAY,GAAG,IAAI,CAAC;IACpB,gBAAgB,GAAG,IAAI,CAAC;AAC1B,CAAC"}
|
package/dist/utils/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
|
package/dist/utils/index.js
DELETED
package/dist/utils/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { Layer } from './schema';
|
|
2
|
-
/**
|
|
3
|
-
* Resolve an import path relative to the importing file
|
|
4
|
-
* Returns path relative to project root (assumes /project/ prefix)
|
|
5
|
-
*/
|
|
6
|
-
export declare function resolveImportPath(importPath: string, importingFile: string): string;
|
|
7
|
-
/**
|
|
8
|
-
* Check if a file path matches a glob pattern
|
|
9
|
-
*/
|
|
10
|
-
export declare function matchesPattern(filePath: string, pattern: string): boolean;
|
|
11
|
-
/**
|
|
12
|
-
* Find which layer a file belongs to
|
|
13
|
-
*/
|
|
14
|
-
export declare function getLayerForFile(filePath: string, layers: Layer[]): string | null;
|
|
15
|
-
/**
|
|
16
|
-
* Get layer definition by name
|
|
17
|
-
*/
|
|
18
|
-
export declare function getLayerByName(name: string, layers: Layer[]): Layer | undefined;
|
|
19
|
-
/**
|
|
20
|
-
* Normalize a file path to project-relative format
|
|
21
|
-
* Extracts path from /any/path/src/... to src/...
|
|
22
|
-
*/
|
|
23
|
-
export declare function normalizePath(filePath: string): string;
|
|
24
|
-
//# sourceMappingURL=path-utils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../src/utils/path-utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEtC;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAmBnF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAMzE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,IAAI,CAOhF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,GAAG,SAAS,CAE/E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtD"}
|