ark-runtime-kernel 1.3.0 → 1.4.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/eslint/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["type RuleContext = {\n report(descriptor: Record<string, unknown>): void;\n getFilename?: () => string;\n};\n\ntype RuleListener = Record<string, (node: AstNode) => void>;\n\ntype AstNode = {\n type?: string;\n name?: string;\n value?: unknown;\n source?: AstNode;\n callee?: AstNode;\n property?: AstNode;\n key?: AstNode;\n arguments?: AstNode[];\n properties?: AstNode[];\n};\n\ntype ArkRule = {\n meta: {\n type: 'problem';\n docs: { description: string };\n messages: Record<string, string>;\n schema: unknown[];\n };\n create(context: RuleContext): RuleListener;\n};\n\ntype ArkEslintPlugin = {\n rules: Record<string, ArkRule>;\n configs?: Record<string, unknown>;\n};\n\nfunction stringValue(node: AstNode | undefined): string | undefined {\n return typeof node?.value === 'string' ? node.value : undefined;\n}\n\nfunction propertyName(node: AstNode | undefined): string | undefined {\n return node?.name ?? stringValue(node);\n}\n\nfunction calleePropertyName(node: AstNode): string | undefined {\n return propertyName(node.callee?.property);\n}\n\nfunction objectProperty(node: AstNode | undefined, name: string): AstNode | undefined {\n return node?.properties?.find((property) => propertyName(property.key) === name);\n}\n\nfunction objectHasProperty(node: AstNode | undefined, name: string): boolean {\n return objectProperty(node, name) !== undefined;\n}\n\nfunction objectHasMetadataSource(node: AstNode | undefined): boolean {\n const metadata = objectProperty(node, 'metadata')?.value as AstNode | undefined;\n return objectHasProperty(metadata, 'source');\n}\n\nfunction looksLikeIntent(value: string): boolean {\n return /^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\\.[A-Za-z0-9_.]+$/.test(value);\n}\n\nfunction isDomainFile(context: RuleContext): boolean {\n const filename = context.getFilename?.() ?? '';\n const normalized = filename.split('\\\\').join('/').toLowerCase();\n return normalized.includes('/domain/') || normalized.endsWith('/domain.ts');\n}\n\nfunction isInfraImport(specifier: string): boolean {\n const normalized = specifier.toLowerCase();\n return [\n 'adapter',\n 'adapters',\n 'infrastructure',\n 'persistence',\n 'repository',\n 'repositories',\n 'integration',\n 'database',\n 'db',\n ].some((token) => normalized.includes(token));\n}\n\nfunction isPublishCall(node: AstNode): boolean {\n return calleePropertyName(node) === 'publish';\n}\n\nexport const noDomainInfraImports: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow importing infrastructure or adapters from domain files.',\n },\n messages: {\n forbiddenImport: 'Domain code must not import infrastructure, adapters, repositories, or database modules.',\n },\n schema: [],\n },\n create(context) {\n const check = (node: AstNode) => {\n if (!isDomainFile(context)) return;\n const source = stringValue(node.source);\n if (source && isInfraImport(source)) {\n context.report({ node, messageId: 'forbiddenImport' });\n }\n };\n\n return {\n ImportDeclaration: check,\n ExportNamedDeclaration: check,\n ExportAllDeclaration: check,\n };\n },\n};\n\nexport const noRawEventPublish: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings.',\n },\n messages: {\n rawPublish: 'Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n if (!isPublishCall(node)) return;\n const firstArg = node.arguments?.[0];\n const firstValue = stringValue(firstArg);\n if (\n firstValue && looksLikeIntent(firstValue) ||\n objectHasProperty(firstArg, 'intent')\n ) {\n context.report({ node, messageId: 'rawPublish' });\n }\n },\n };\n },\n};\n\nexport const requirePublishSource: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require event bus publish calls to include source metadata.',\n },\n messages: {\n missingSource: 'Strict Ark publish calls must include metadata.source.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n if (!isPublishCall(node)) return;\n const firstArg = node.arguments?.[0];\n const metadataArg = node.arguments?.[2];\n if (objectHasMetadataSource(firstArg) || objectHasProperty(metadataArg, 'source')) {\n return;\n }\n context.report({ node, messageId: 'missingSource' });\n },\n };\n },\n};\n\nconst rules = {\n 'no-domain-infra-imports': noDomainInfraImports,\n 'no-raw-event-publish': noRawEventPublish,\n 'require-publish-source': requirePublishSource,\n};\n\nconst plugin: ArkEslintPlugin = { rules };\n\nplugin.configs = {\n recommended: {\n plugins: { ark: plugin },\n rules: {\n 'ark/no-domain-infra-imports': 'error',\n 'ark/no-raw-event-publish': 'error',\n 'ark/require-publish-source': 'error',\n },\n },\n};\n\nexport { plugin };\nexport default plugin;\n"]}
1
+ {"version":3,"sources":["../../src/eslint/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["type RuleContext = {\n report(descriptor: Record<string, unknown>): void;\n getFilename?: () => string;\n options?: unknown[];\n};\n\ntype RuleListener = Record<string, (node: AstNode) => void>;\n\ntype AstNode = {\n type?: string;\n name?: string;\n value?: unknown;\n source?: AstNode;\n callee?: AstNode;\n object?: AstNode;\n property?: AstNode;\n key?: AstNode;\n arguments?: AstNode[];\n properties?: AstNode[];\n};\n\ntype ArkRule = {\n meta: {\n type: 'problem';\n docs: { description: string };\n messages: Record<string, string>;\n schema: unknown[];\n };\n create(context: RuleContext): RuleListener;\n};\n\ntype ArkEslintPlugin = {\n rules: Record<string, ArkRule>;\n configs?: Record<string, unknown>;\n};\n\nfunction stringValue(node: AstNode | undefined): string | undefined {\n return typeof node?.value === 'string' ? node.value : undefined;\n}\n\nfunction propertyName(node: AstNode | undefined): string | undefined {\n return node?.name ?? stringValue(node);\n}\n\nfunction calleePropertyName(node: AstNode): string | undefined {\n return propertyName(node.callee?.property);\n}\n\nfunction objectProperty(node: AstNode | undefined, name: string): AstNode | undefined {\n return node?.properties?.find((property) => propertyName(property.key) === name);\n}\n\nfunction objectHasProperty(node: AstNode | undefined, name: string): boolean {\n return objectProperty(node, name) !== undefined;\n}\n\nfunction objectHasMetadataSource(node: AstNode | undefined): boolean {\n const metadata = objectProperty(node, 'metadata')?.value as AstNode | undefined;\n return objectHasProperty(metadata, 'source');\n}\n\nfunction looksLikeIntent(value: string): boolean {\n return /^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\\.[A-Za-z0-9_.]+$/.test(value);\n}\n\nfunction isDomainFile(context: RuleContext): boolean {\n const filename = context.getFilename?.() ?? '';\n const normalized = filename.split('\\\\').join('/').toLowerCase();\n return normalized.includes('/domain/') || normalized.endsWith('/domain.ts');\n}\n\nfunction isInfraImport(specifier: string): boolean {\n const normalized = specifier.toLowerCase();\n return [\n 'adapter',\n 'adapters',\n 'infrastructure',\n 'persistence',\n 'repository',\n 'repositories',\n 'integration',\n 'database',\n 'db',\n ].some((token) => normalized.includes(token));\n}\n\nfunction isPublishCall(node: AstNode): boolean {\n return calleePropertyName(node) === 'publish';\n}\n\nexport const noDomainInfraImports: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow importing infrastructure or adapters from domain files.',\n },\n messages: {\n forbiddenImport: 'Domain code must not import infrastructure, adapters, repositories, or database modules.',\n },\n schema: [],\n },\n create(context) {\n const check = (node: AstNode) => {\n if (!isDomainFile(context)) return;\n const source = stringValue(node.source);\n if (source && isInfraImport(source)) {\n context.report({ node, messageId: 'forbiddenImport' });\n }\n };\n\n return {\n ImportDeclaration: check,\n ExportNamedDeclaration: check,\n ExportAllDeclaration: check,\n };\n },\n};\n\nexport const noRawEventPublish: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings.',\n },\n messages: {\n rawPublish: 'Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n if (!isPublishCall(node)) return;\n const firstArg = node.arguments?.[0];\n const firstValue = stringValue(firstArg);\n if (\n firstValue && looksLikeIntent(firstValue) ||\n objectHasProperty(firstArg, 'intent')\n ) {\n context.report({ node, messageId: 'rawPublish' });\n }\n },\n };\n },\n};\n\nexport const requirePublishSource: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require event bus publish calls to include source metadata.',\n },\n messages: {\n missingSource: 'Strict Ark publish calls must include metadata.source.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n if (!isPublishCall(node)) return;\n const firstArg = node.arguments?.[0];\n const metadataArg = node.arguments?.[2];\n if (objectHasMetadataSource(firstArg) || objectHasProperty(metadataArg, 'source')) {\n return;\n }\n context.report({ node, messageId: 'missingSource' });\n },\n };\n },\n};\n\nconst DEFAULT_FORBIDDEN_GLOBALS = ['fetch', 'process', 'Date.now', 'Math.random'];\n\nexport const noForbiddenGlobals: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow ambient globals (e.g. fetch, Date.now) in architecture-governed code; scope the rule to layer directories via ESLint \"files\" patterns.',\n },\n messages: {\n forbiddenGlobal: 'Ambient global \"{{name}}\" is forbidden here; inject the capability through a port instead.',\n },\n schema: [\n {\n type: 'object',\n properties: {\n globals: { type: 'array', items: { type: 'string' } },\n },\n additionalProperties: false,\n },\n ],\n },\n create(context) {\n const option = context.options?.[0] as { globals?: string[] } | undefined;\n const globals = new Set(option?.globals ?? DEFAULT_FORBIDDEN_GLOBALS);\n const report = (node: AstNode, name: string) =>\n context.report({ node, messageId: 'forbiddenGlobal', data: { name } });\n\n return {\n // Same positional detection as ark-check's FORBIDDEN_GLOBAL: property accesses on a\n // forbidden base (console.log, Date.now), direct calls, and constructions. Bare\n // identifier mentions elsewhere are not flagged (avoids shadowed-local false positives).\n MemberExpression(node) {\n const base = node.object?.type === 'Identifier' ? node.object.name : undefined;\n if (!base) return;\n const dotted = `${base}.${propertyName(node.property) ?? ''}`;\n if (globals.has(dotted)) report(node, dotted);\n else if (globals.has(base)) report(node, base);\n },\n CallExpression(node) {\n const callee = node.callee?.type === 'Identifier' ? node.callee.name : undefined;\n if (callee && globals.has(callee)) report(node, callee);\n },\n NewExpression(node) {\n const callee = node.callee?.type === 'Identifier' ? node.callee.name : undefined;\n if (callee && globals.has(callee)) report(node, callee);\n },\n };\n },\n};\n\nconst rules = {\n 'no-domain-infra-imports': noDomainInfraImports,\n 'no-raw-event-publish': noRawEventPublish,\n 'require-publish-source': requirePublishSource,\n 'no-forbidden-globals': noForbiddenGlobals,\n};\n\nconst plugin: ArkEslintPlugin = { rules };\n\nplugin.configs = {\n recommended: {\n plugins: { ark: plugin },\n rules: {\n 'ark/no-domain-infra-imports': 'error',\n 'ark/no-raw-event-publish': 'error',\n 'ark/require-publish-source': 'error',\n },\n },\n};\n\nexport { plugin };\nexport default plugin;\n"]}
@@ -1,6 +1,7 @@
1
1
  type RuleContext = {
2
2
  report(descriptor: Record<string, unknown>): void;
3
3
  getFilename?: () => string;
4
+ options?: unknown[];
4
5
  };
5
6
  type RuleListener = Record<string, (node: AstNode) => void>;
6
7
  type AstNode = {
@@ -9,6 +10,7 @@ type AstNode = {
9
10
  value?: unknown;
10
11
  source?: AstNode;
11
12
  callee?: AstNode;
13
+ object?: AstNode;
12
14
  property?: AstNode;
13
15
  key?: AstNode;
14
16
  arguments?: AstNode[];
@@ -32,6 +34,7 @@ type ArkEslintPlugin = {
32
34
  declare const noDomainInfraImports: ArkRule;
33
35
  declare const noRawEventPublish: ArkRule;
34
36
  declare const requirePublishSource: ArkRule;
37
+ declare const noForbiddenGlobals: ArkRule;
35
38
  declare const plugin: ArkEslintPlugin;
36
39
 
37
- export { plugin as default, noDomainInfraImports, noRawEventPublish, plugin, requirePublishSource };
40
+ export { plugin as default, noDomainInfraImports, noForbiddenGlobals, noRawEventPublish, plugin, requirePublishSource };
@@ -1,6 +1,7 @@
1
1
  type RuleContext = {
2
2
  report(descriptor: Record<string, unknown>): void;
3
3
  getFilename?: () => string;
4
+ options?: unknown[];
4
5
  };
5
6
  type RuleListener = Record<string, (node: AstNode) => void>;
6
7
  type AstNode = {
@@ -9,6 +10,7 @@ type AstNode = {
9
10
  value?: unknown;
10
11
  source?: AstNode;
11
12
  callee?: AstNode;
13
+ object?: AstNode;
12
14
  property?: AstNode;
13
15
  key?: AstNode;
14
16
  arguments?: AstNode[];
@@ -32,6 +34,7 @@ type ArkEslintPlugin = {
32
34
  declare const noDomainInfraImports: ArkRule;
33
35
  declare const noRawEventPublish: ArkRule;
34
36
  declare const requirePublishSource: ArkRule;
37
+ declare const noForbiddenGlobals: ArkRule;
35
38
  declare const plugin: ArkEslintPlugin;
36
39
 
37
- export { plugin as default, noDomainInfraImports, noRawEventPublish, plugin, requirePublishSource };
40
+ export { plugin as default, noDomainInfraImports, noForbiddenGlobals, noRawEventPublish, plugin, requirePublishSource };
@@ -118,10 +118,57 @@ var requirePublishSource = {
118
118
  };
119
119
  }
120
120
  };
121
+ var DEFAULT_FORBIDDEN_GLOBALS = ["fetch", "process", "Date.now", "Math.random"];
122
+ var noForbiddenGlobals = {
123
+ meta: {
124
+ type: "problem",
125
+ docs: {
126
+ description: 'Disallow ambient globals (e.g. fetch, Date.now) in architecture-governed code; scope the rule to layer directories via ESLint "files" patterns.'
127
+ },
128
+ messages: {
129
+ forbiddenGlobal: 'Ambient global "{{name}}" is forbidden here; inject the capability through a port instead.'
130
+ },
131
+ schema: [
132
+ {
133
+ type: "object",
134
+ properties: {
135
+ globals: { type: "array", items: { type: "string" } }
136
+ },
137
+ additionalProperties: false
138
+ }
139
+ ]
140
+ },
141
+ create(context) {
142
+ const option = context.options?.[0];
143
+ const globals = new Set(option?.globals ?? DEFAULT_FORBIDDEN_GLOBALS);
144
+ const report = (node, name) => context.report({ node, messageId: "forbiddenGlobal", data: { name } });
145
+ return {
146
+ // Same positional detection as ark-check's FORBIDDEN_GLOBAL: property accesses on a
147
+ // forbidden base (console.log, Date.now), direct calls, and constructions. Bare
148
+ // identifier mentions elsewhere are not flagged (avoids shadowed-local false positives).
149
+ MemberExpression(node) {
150
+ const base = node.object?.type === "Identifier" ? node.object.name : void 0;
151
+ if (!base) return;
152
+ const dotted = `${base}.${propertyName(node.property) ?? ""}`;
153
+ if (globals.has(dotted)) report(node, dotted);
154
+ else if (globals.has(base)) report(node, base);
155
+ },
156
+ CallExpression(node) {
157
+ const callee = node.callee?.type === "Identifier" ? node.callee.name : void 0;
158
+ if (callee && globals.has(callee)) report(node, callee);
159
+ },
160
+ NewExpression(node) {
161
+ const callee = node.callee?.type === "Identifier" ? node.callee.name : void 0;
162
+ if (callee && globals.has(callee)) report(node, callee);
163
+ }
164
+ };
165
+ }
166
+ };
121
167
  var rules = {
122
168
  "no-domain-infra-imports": noDomainInfraImports,
123
169
  "no-raw-event-publish": noRawEventPublish,
124
- "require-publish-source": requirePublishSource
170
+ "require-publish-source": requirePublishSource,
171
+ "no-forbidden-globals": noForbiddenGlobals
125
172
  };
126
173
  var plugin = { rules };
127
174
  plugin.configs = {
@@ -136,6 +183,6 @@ plugin.configs = {
136
183
  };
137
184
  var eslint_default = plugin;
138
185
 
139
- export { eslint_default as default, noDomainInfraImports, noRawEventPublish, plugin, requirePublishSource };
186
+ export { eslint_default as default, noDomainInfraImports, noForbiddenGlobals, noRawEventPublish, plugin, requirePublishSource };
140
187
  //# sourceMappingURL=index.js.map
141
188
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/eslint/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["type RuleContext = {\n report(descriptor: Record<string, unknown>): void;\n getFilename?: () => string;\n};\n\ntype RuleListener = Record<string, (node: AstNode) => void>;\n\ntype AstNode = {\n type?: string;\n name?: string;\n value?: unknown;\n source?: AstNode;\n callee?: AstNode;\n property?: AstNode;\n key?: AstNode;\n arguments?: AstNode[];\n properties?: AstNode[];\n};\n\ntype ArkRule = {\n meta: {\n type: 'problem';\n docs: { description: string };\n messages: Record<string, string>;\n schema: unknown[];\n };\n create(context: RuleContext): RuleListener;\n};\n\ntype ArkEslintPlugin = {\n rules: Record<string, ArkRule>;\n configs?: Record<string, unknown>;\n};\n\nfunction stringValue(node: AstNode | undefined): string | undefined {\n return typeof node?.value === 'string' ? node.value : undefined;\n}\n\nfunction propertyName(node: AstNode | undefined): string | undefined {\n return node?.name ?? stringValue(node);\n}\n\nfunction calleePropertyName(node: AstNode): string | undefined {\n return propertyName(node.callee?.property);\n}\n\nfunction objectProperty(node: AstNode | undefined, name: string): AstNode | undefined {\n return node?.properties?.find((property) => propertyName(property.key) === name);\n}\n\nfunction objectHasProperty(node: AstNode | undefined, name: string): boolean {\n return objectProperty(node, name) !== undefined;\n}\n\nfunction objectHasMetadataSource(node: AstNode | undefined): boolean {\n const metadata = objectProperty(node, 'metadata')?.value as AstNode | undefined;\n return objectHasProperty(metadata, 'source');\n}\n\nfunction looksLikeIntent(value: string): boolean {\n return /^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\\.[A-Za-z0-9_.]+$/.test(value);\n}\n\nfunction isDomainFile(context: RuleContext): boolean {\n const filename = context.getFilename?.() ?? '';\n const normalized = filename.split('\\\\').join('/').toLowerCase();\n return normalized.includes('/domain/') || normalized.endsWith('/domain.ts');\n}\n\nfunction isInfraImport(specifier: string): boolean {\n const normalized = specifier.toLowerCase();\n return [\n 'adapter',\n 'adapters',\n 'infrastructure',\n 'persistence',\n 'repository',\n 'repositories',\n 'integration',\n 'database',\n 'db',\n ].some((token) => normalized.includes(token));\n}\n\nfunction isPublishCall(node: AstNode): boolean {\n return calleePropertyName(node) === 'publish';\n}\n\nexport const noDomainInfraImports: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow importing infrastructure or adapters from domain files.',\n },\n messages: {\n forbiddenImport: 'Domain code must not import infrastructure, adapters, repositories, or database modules.',\n },\n schema: [],\n },\n create(context) {\n const check = (node: AstNode) => {\n if (!isDomainFile(context)) return;\n const source = stringValue(node.source);\n if (source && isInfraImport(source)) {\n context.report({ node, messageId: 'forbiddenImport' });\n }\n };\n\n return {\n ImportDeclaration: check,\n ExportNamedDeclaration: check,\n ExportAllDeclaration: check,\n };\n },\n};\n\nexport const noRawEventPublish: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings.',\n },\n messages: {\n rawPublish: 'Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n if (!isPublishCall(node)) return;\n const firstArg = node.arguments?.[0];\n const firstValue = stringValue(firstArg);\n if (\n firstValue && looksLikeIntent(firstValue) ||\n objectHasProperty(firstArg, 'intent')\n ) {\n context.report({ node, messageId: 'rawPublish' });\n }\n },\n };\n },\n};\n\nexport const requirePublishSource: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require event bus publish calls to include source metadata.',\n },\n messages: {\n missingSource: 'Strict Ark publish calls must include metadata.source.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n if (!isPublishCall(node)) return;\n const firstArg = node.arguments?.[0];\n const metadataArg = node.arguments?.[2];\n if (objectHasMetadataSource(firstArg) || objectHasProperty(metadataArg, 'source')) {\n return;\n }\n context.report({ node, messageId: 'missingSource' });\n },\n };\n },\n};\n\nconst rules = {\n 'no-domain-infra-imports': noDomainInfraImports,\n 'no-raw-event-publish': noRawEventPublish,\n 'require-publish-source': requirePublishSource,\n};\n\nconst plugin: ArkEslintPlugin = { rules };\n\nplugin.configs = {\n recommended: {\n plugins: { ark: plugin },\n rules: {\n 'ark/no-domain-infra-imports': 'error',\n 'ark/no-raw-event-publish': 'error',\n 'ark/require-publish-source': 'error',\n },\n },\n};\n\nexport { plugin };\nexport default plugin;\n"]}
1
+ {"version":3,"sources":["../../src/eslint/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["type RuleContext = {\n report(descriptor: Record<string, unknown>): void;\n getFilename?: () => string;\n options?: unknown[];\n};\n\ntype RuleListener = Record<string, (node: AstNode) => void>;\n\ntype AstNode = {\n type?: string;\n name?: string;\n value?: unknown;\n source?: AstNode;\n callee?: AstNode;\n object?: AstNode;\n property?: AstNode;\n key?: AstNode;\n arguments?: AstNode[];\n properties?: AstNode[];\n};\n\ntype ArkRule = {\n meta: {\n type: 'problem';\n docs: { description: string };\n messages: Record<string, string>;\n schema: unknown[];\n };\n create(context: RuleContext): RuleListener;\n};\n\ntype ArkEslintPlugin = {\n rules: Record<string, ArkRule>;\n configs?: Record<string, unknown>;\n};\n\nfunction stringValue(node: AstNode | undefined): string | undefined {\n return typeof node?.value === 'string' ? node.value : undefined;\n}\n\nfunction propertyName(node: AstNode | undefined): string | undefined {\n return node?.name ?? stringValue(node);\n}\n\nfunction calleePropertyName(node: AstNode): string | undefined {\n return propertyName(node.callee?.property);\n}\n\nfunction objectProperty(node: AstNode | undefined, name: string): AstNode | undefined {\n return node?.properties?.find((property) => propertyName(property.key) === name);\n}\n\nfunction objectHasProperty(node: AstNode | undefined, name: string): boolean {\n return objectProperty(node, name) !== undefined;\n}\n\nfunction objectHasMetadataSource(node: AstNode | undefined): boolean {\n const metadata = objectProperty(node, 'metadata')?.value as AstNode | undefined;\n return objectHasProperty(metadata, 'source');\n}\n\nfunction looksLikeIntent(value: string): boolean {\n return /^(Domain|Application|Adapter|Workflow|Job|Presentation|Reporting|Metadata|Security|Audit|Observability|Kernel)\\.[A-Za-z0-9_.]+$/.test(value);\n}\n\nfunction isDomainFile(context: RuleContext): boolean {\n const filename = context.getFilename?.() ?? '';\n const normalized = filename.split('\\\\').join('/').toLowerCase();\n return normalized.includes('/domain/') || normalized.endsWith('/domain.ts');\n}\n\nfunction isInfraImport(specifier: string): boolean {\n const normalized = specifier.toLowerCase();\n return [\n 'adapter',\n 'adapters',\n 'infrastructure',\n 'persistence',\n 'repository',\n 'repositories',\n 'integration',\n 'database',\n 'db',\n ].some((token) => normalized.includes(token));\n}\n\nfunction isPublishCall(node: AstNode): boolean {\n return calleePropertyName(node) === 'publish';\n}\n\nexport const noDomainInfraImports: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallow importing infrastructure or adapters from domain files.',\n },\n messages: {\n forbiddenImport: 'Domain code must not import infrastructure, adapters, repositories, or database modules.',\n },\n schema: [],\n },\n create(context) {\n const check = (node: AstNode) => {\n if (!isDomainFile(context)) return;\n const source = stringValue(node.source);\n if (source && isInfraImport(source)) {\n context.report({ node, messageId: 'forbiddenImport' });\n }\n };\n\n return {\n ImportDeclaration: check,\n ExportNamedDeclaration: check,\n ExportAllDeclaration: check,\n };\n },\n};\n\nexport const noRawEventPublish: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require event bus publish calls to use registered intent creators instead of raw event objects or intent strings.',\n },\n messages: {\n rawPublish: 'Publish through a registered intent creator; raw event objects or intent strings bypass Ark contracts.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n if (!isPublishCall(node)) return;\n const firstArg = node.arguments?.[0];\n const firstValue = stringValue(firstArg);\n if (\n firstValue && looksLikeIntent(firstValue) ||\n objectHasProperty(firstArg, 'intent')\n ) {\n context.report({ node, messageId: 'rawPublish' });\n }\n },\n };\n },\n};\n\nexport const requirePublishSource: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require event bus publish calls to include source metadata.',\n },\n messages: {\n missingSource: 'Strict Ark publish calls must include metadata.source.',\n },\n schema: [],\n },\n create(context) {\n return {\n CallExpression(node) {\n if (!isPublishCall(node)) return;\n const firstArg = node.arguments?.[0];\n const metadataArg = node.arguments?.[2];\n if (objectHasMetadataSource(firstArg) || objectHasProperty(metadataArg, 'source')) {\n return;\n }\n context.report({ node, messageId: 'missingSource' });\n },\n };\n },\n};\n\nconst DEFAULT_FORBIDDEN_GLOBALS = ['fetch', 'process', 'Date.now', 'Math.random'];\n\nexport const noForbiddenGlobals: ArkRule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow ambient globals (e.g. fetch, Date.now) in architecture-governed code; scope the rule to layer directories via ESLint \"files\" patterns.',\n },\n messages: {\n forbiddenGlobal: 'Ambient global \"{{name}}\" is forbidden here; inject the capability through a port instead.',\n },\n schema: [\n {\n type: 'object',\n properties: {\n globals: { type: 'array', items: { type: 'string' } },\n },\n additionalProperties: false,\n },\n ],\n },\n create(context) {\n const option = context.options?.[0] as { globals?: string[] } | undefined;\n const globals = new Set(option?.globals ?? DEFAULT_FORBIDDEN_GLOBALS);\n const report = (node: AstNode, name: string) =>\n context.report({ node, messageId: 'forbiddenGlobal', data: { name } });\n\n return {\n // Same positional detection as ark-check's FORBIDDEN_GLOBAL: property accesses on a\n // forbidden base (console.log, Date.now), direct calls, and constructions. Bare\n // identifier mentions elsewhere are not flagged (avoids shadowed-local false positives).\n MemberExpression(node) {\n const base = node.object?.type === 'Identifier' ? node.object.name : undefined;\n if (!base) return;\n const dotted = `${base}.${propertyName(node.property) ?? ''}`;\n if (globals.has(dotted)) report(node, dotted);\n else if (globals.has(base)) report(node, base);\n },\n CallExpression(node) {\n const callee = node.callee?.type === 'Identifier' ? node.callee.name : undefined;\n if (callee && globals.has(callee)) report(node, callee);\n },\n NewExpression(node) {\n const callee = node.callee?.type === 'Identifier' ? node.callee.name : undefined;\n if (callee && globals.has(callee)) report(node, callee);\n },\n };\n },\n};\n\nconst rules = {\n 'no-domain-infra-imports': noDomainInfraImports,\n 'no-raw-event-publish': noRawEventPublish,\n 'require-publish-source': requirePublishSource,\n 'no-forbidden-globals': noForbiddenGlobals,\n};\n\nconst plugin: ArkEslintPlugin = { rules };\n\nplugin.configs = {\n recommended: {\n plugins: { ark: plugin },\n rules: {\n 'ark/no-domain-infra-imports': 'error',\n 'ark/no-raw-event-publish': 'error',\n 'ark/require-publish-source': 'error',\n },\n },\n};\n\nexport { plugin };\nexport default plugin;\n"]}
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  // src/version.ts
4
- var version = "1.3.0";
4
+ var version = "1.4.0";
5
5
 
6
6
  // src/kernel/intent/IntentRegistry.ts
7
7
  var IntentRegistry = class {
@@ -2101,6 +2101,33 @@ function tsPublishSourceLiteral(ts, node) {
2101
2101
  const rawMetadata = tsObjectPropertyValue(ts, firstArg, "metadata");
2102
2102
  return tsStringLiteralText(ts, tsObjectPropertyValue(ts, rawMetadata, "source")) ?? tsStringLiteralText(ts, tsObjectPropertyValue(ts, secondArg, "source")) ?? tsStringLiteralText(ts, tsObjectPropertyValue(ts, thirdArg, "source"));
2103
2103
  }
2104
+ function analyzeForbiddenGlobals(ts, source, filePath, layer, forbidden) {
2105
+ const entries = new Set(forbidden);
2106
+ if (entries.size === 0) return [];
2107
+ const sourceFile = ts.createSourceFile("generated.ts", source, ts.ScriptTarget.Latest, true);
2108
+ const violations = [];
2109
+ const flag = (name, node) => violations.push(
2110
+ violation("FORBIDDEN_GLOBAL", `${layer} must not use the ambient global "${name}".`, {
2111
+ line: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
2112
+ filePath,
2113
+ target: name,
2114
+ fromLayer: layer,
2115
+ suggestion: "Inject the capability through a port (e.g. a Clock, IdGenerator, or HttpPort) instead of reaching for the ambient global."
2116
+ })
2117
+ );
2118
+ const visit = (node) => {
2119
+ if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
2120
+ const dotted = `${node.expression.text}.${node.name.text}`;
2121
+ if (entries.has(dotted)) flag(dotted, node);
2122
+ else if (entries.has(node.expression.text)) flag(node.expression.text, node);
2123
+ } else if ((ts.isCallExpression(node) || ts.isNewExpression(node)) && node.expression && ts.isIdentifier(node.expression) && entries.has(node.expression.text)) {
2124
+ flag(node.expression.text, node);
2125
+ }
2126
+ ts.forEachChild(node, visit);
2127
+ };
2128
+ visit(sourceFile);
2129
+ return violations;
2130
+ }
2104
2131
  function analyzePublishAst(ts, source, context, profile) {
2105
2132
  const sourceFile = ts.createSourceFile(
2106
2133
  "generated.ts",
@@ -2299,6 +2326,26 @@ function createAICodeGate(options = {}) {
2299
2326
  }
2300
2327
  }
2301
2328
  }
2329
+ if (options.typescript && contextLayer && options.forbiddenGlobals?.[contextLayer]?.length) {
2330
+ try {
2331
+ violations.push(
2332
+ ...analyzeForbiddenGlobals(
2333
+ options.typescript,
2334
+ source,
2335
+ filePath,
2336
+ contextLayer,
2337
+ options.forbiddenGlobals[contextLayer]
2338
+ )
2339
+ );
2340
+ } catch (err) {
2341
+ violations.push(
2342
+ violation(
2343
+ "AST_ANALYZER_ERROR",
2344
+ `TypeScript AST analyzer failed: ${err instanceof Error ? err.message : String(err)}`
2345
+ )
2346
+ );
2347
+ }
2348
+ }
2302
2349
  if (options.typescript) {
2303
2350
  try {
2304
2351
  violations.push(