entkapp 4.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 (46) hide show
  1. package/.scaffold-ignore +22 -0
  2. package/LICENSE +211 -0
  3. package/NOTICE +13 -0
  4. package/README.md +33 -0
  5. package/bin/cli.js +174 -0
  6. package/entkapp/config.json +42 -0
  7. package/entkapp/plugins/README.md +19 -0
  8. package/index.js +2254 -0
  9. package/logo.png +0 -0
  10. package/package.json +96 -0
  11. package/src/EngineContext.js +185 -0
  12. package/src/api/HeadlessAPI.js +376 -0
  13. package/src/api/PluginSDK.js +299 -0
  14. package/src/ast/ASTAnalyzer.js +492 -0
  15. package/src/ast/BarrelParser.js +221 -0
  16. package/src/ast/DeadCodeDetector.js +73 -0
  17. package/src/ast/MagicDetector.js +203 -0
  18. package/src/ast/OxcAnalyzer.js +337 -0
  19. package/src/ast/SecretScanner.js +304 -0
  20. package/src/healing/GitSandbox.js +82 -0
  21. package/src/healing/SelfHealer.js +52 -0
  22. package/src/index.js +723 -0
  23. package/src/performance/GraphCache.js +87 -0
  24. package/src/performance/SupplyChainGuard.js +92 -0
  25. package/src/performance/WorkerPool.js +109 -0
  26. package/src/plugins/BasePlugin.js +71 -0
  27. package/src/plugins/KnipAdapter.js +106 -0
  28. package/src/plugins/PluginRegistry.js +197 -0
  29. package/src/plugins/ecosystems/BackendServices.js +61 -0
  30. package/src/plugins/ecosystems/GenericPlugins.js +64 -0
  31. package/src/plugins/ecosystems/ModernFrameworks.js +159 -0
  32. package/src/plugins/ecosystems/MorePlugins.js +184 -0
  33. package/src/plugins/ecosystems/NextJsPlugin.js +33 -0
  34. package/src/plugins/ecosystems/PluginLoader.js +20 -0
  35. package/src/plugins/ecosystems/TypeScriptPlugin.js +56 -0
  36. package/src/refractor/ImpactAnalyzer.js +92 -0
  37. package/src/refractor/SourceRewriter.js +86 -0
  38. package/src/refractor/TransactionManager.js +138 -0
  39. package/src/refractor/TypeIntegrity.js +75 -0
  40. package/src/resolution/CircularDetector.js +91 -0
  41. package/src/resolution/ConfigLoader.js +87 -0
  42. package/src/resolution/DepencyResolver.js +133 -0
  43. package/src/resolution/DependencyProfiler.js +268 -0
  44. package/src/resolution/PathMapper.js +125 -0
  45. package/src/resolution/WorkSpaceGraph.js +474 -0
  46. package/tsconfig.json +26 -0
@@ -0,0 +1,61 @@
1
+ /**
2
+ * ============================================================================
3
+ * Backend Services Plugins for entkapp v4.1.0
4
+ * ============================================================================
5
+ * Built-in support for GraphQL, REST APIs, and Databases.
6
+ */
7
+
8
+ import { BasePlugin } from '../BasePlugin.js';
9
+ import fs from 'fs/promises';
10
+ import path from 'path';
11
+
12
+ /**
13
+ * GraphQL Ecosystem Plugin
14
+ */
15
+ export class GraphQLPlugin extends BasePlugin {
16
+ get name() {
17
+ return 'graphql';
18
+ }
19
+
20
+ getConfigFiles() {
21
+ return ['package.json', 'graphql.config.js', '.graphqlconfig'];
22
+ }
23
+
24
+ async isActive(baseDir) {
25
+ try {
26
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
27
+ return !!(pkgJson.dependencies?.graphql || pkgJson.devDependencies?.graphql || pkgJson.dependencies?.['@apollo/client']);
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+
33
+ async analyze(node, filePath) {
34
+ // Detect GraphQL tagged templates
35
+ const gqlPattern = /gql\s*`([\s\S]*?)`/g;
36
+ const matches = node.rawCode?.match(gqlPattern) || [];
37
+ if (matches.length > 0) {
38
+ node.graphqlQueries = matches;
39
+ }
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Database Ecosystem Plugin (Prisma, Drizzle, TypeORM)
45
+ */
46
+ export class DatabasePlugin extends BasePlugin {
47
+ get name() {
48
+ return 'database';
49
+ }
50
+
51
+ getConfigFiles() {
52
+ return ['package.json', 'prisma/schema.prisma', 'drizzle.config.ts', 'ormconfig.json'];
53
+ }
54
+
55
+ async analyze(node, filePath) {
56
+ // Detect DB usage
57
+ if (node.explicitImports.has('@prisma/client') || node.explicitImports.has('drizzle-orm')) {
58
+ node.usesDatabase = true;
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,64 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import { BasePlugin } from '../BasePlugin.js';
4
+
5
+ export class NuxtPlugin extends BasePlugin {
6
+ get name() { return 'nuxt'; }
7
+ getConfigFiles() { return ['nuxt.config.js', 'nuxt.config.ts']; }
8
+ getRoutePatterns() {
9
+ return [/\/pages\//, /\/server\/(api|routes|middleware)\//, /\/components\/[a-zA-Z0-9_\-\/]+\.vue$/];
10
+ }
11
+ getRequiredSystemContracts() { return ['default']; }
12
+ async isActive(baseDir) {
13
+ for (const file of this.getConfigFiles()) {
14
+ try { await fs.access(path.join(baseDir, file)); return true; } catch {}
15
+ }
16
+ return false;
17
+ }
18
+ }
19
+
20
+ export class RemixPlugin extends BasePlugin {
21
+ get name() { return 'remix'; }
22
+ getConfigFiles() { return ['remix.config.js', 'vite.config.js', 'vite.config.ts']; }
23
+ getRoutePatterns() { return [/\/app\/routes\//, /\/app\/root\.(tsx|jsx)$/]; }
24
+ getRequiredSystemContracts() { return ['default', 'loader', 'action', 'meta', 'links']; }
25
+ async isActive(baseDir) {
26
+ for (const file of this.getConfigFiles()) {
27
+ try {
28
+ const content = await fs.readFile(path.join(baseDir, file), 'utf8');
29
+ if (content.includes('@remix-run/') || content.includes('remix')) return true;
30
+ } catch {}
31
+ }
32
+ return false;
33
+ }
34
+ }
35
+
36
+ export class SvelteKitPlugin extends BasePlugin {
37
+ get name() { return 'sveltekit'; }
38
+ getConfigFiles() { return ['svelte.config.js', 'vite.config.ts']; }
39
+ getRoutePatterns() {
40
+ return [/\+page\.(svelte|ts|js)$/, /\+page\.server\.(ts|js)$/, /\+layout\.(svelte|ts|js)$/, /\+server\.(ts|js)$/];
41
+ }
42
+ getRequiredSystemContracts() { return ['load', 'actions', 'GET', 'POST', 'PUT', 'DELETE', 'PATCH']; }
43
+ async isActive(baseDir) {
44
+ try {
45
+ await fs.access(path.join(baseDir, 'svelte.config.js'));
46
+ return true;
47
+ } catch {
48
+ return false;
49
+ }
50
+ }
51
+ }
52
+
53
+ export class AstroPlugin extends BasePlugin {
54
+ get name() { return 'astro'; }
55
+ getConfigFiles() { return ['astro.config.mjs', 'astro.config.cjs', 'astro.config.ts']; }
56
+ getRoutePatterns() { return [/\/src\/pages\/.*\.astro$/, /\/src\/pages\/.*\.(ts|js)$/]; }
57
+ getRequiredSystemContracts() { return ['default', 'getStaticPaths']; }
58
+ async isActive(baseDir) {
59
+ for (const file of this.getConfigFiles()) {
60
+ try { await fs.access(path.join(baseDir, file)); return true; } catch {}
61
+ }
62
+ return false;
63
+ }
64
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * ============================================================================
3
+ * Modern Frameworks Plugins for entkapp v4.0.0
4
+ * ============================================================================
5
+ * Built-in support for React, Vue, Svelte, and Angular.
6
+ */
7
+
8
+ import { BasePlugin } from '../BasePlugin.js';
9
+ import fs from 'fs/promises';
10
+ import path from 'path';
11
+
12
+ /**
13
+ * React Ecosystem Plugin
14
+ */
15
+ export class ReactPlugin extends BasePlugin {
16
+ get name() {
17
+ return 'react';
18
+ }
19
+
20
+ getConfigFiles() {
21
+ return ['package.json'];
22
+ }
23
+
24
+ async isActive(baseDir) {
25
+ try {
26
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
27
+ return !!(pkgJson.dependencies?.react || pkgJson.devDependencies?.react);
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+
33
+ getRoutePatterns() {
34
+ return [/\.(tsx?|jsx?)$/];
35
+ }
36
+
37
+ getRequiredSystemContracts() {
38
+ return ['default', 'Component', 'PureComponent', 'Fragment', 'useEffect', 'useState', 'useContext', 'useReducer', 'useCallback', 'useMemo', 'useRef', 'useImperativeHandle', 'useLayoutEffect', 'useDebugValue'];
39
+ }
40
+
41
+ async analyze(node, filePath) {
42
+ if (node.explicitImports.has('react')) {
43
+ node.isReactComponent = true;
44
+ }
45
+
46
+ // Detect JSX
47
+ if (node.rawCode && (node.rawCode.includes('</') || node.rawCode.includes('/>'))) {
48
+ node.hasJSX = true;
49
+ }
50
+
51
+ // Detect Hooks
52
+ const hookMatches = node.rawCode?.match(/use[A-Z]\w+/g) || [];
53
+ if (hookMatches.length > 0) {
54
+ node.reactHooks = new Set(hookMatches);
55
+ }
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Vue Ecosystem Plugin
61
+ */
62
+ export class VuePlugin extends BasePlugin {
63
+ get name() {
64
+ return 'vue';
65
+ }
66
+
67
+ getConfigFiles() {
68
+ return ['package.json', 'vue.config.js', 'vite.config.ts', 'vite.config.js'];
69
+ }
70
+
71
+ async isActive(baseDir) {
72
+ try {
73
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
74
+ return !!(pkgJson.dependencies?.vue || pkgJson.devDependencies?.vue);
75
+ } catch {
76
+ return false;
77
+ }
78
+ }
79
+
80
+ getRoutePatterns() {
81
+ return [/\.vue$/, /\.(tsx?|jsx?)$/];
82
+ }
83
+
84
+ async analyze(node, filePath) {
85
+ if (filePath.endsWith('.vue')) {
86
+ node.isVueSFC = true;
87
+ // Extract template/script/style sections
88
+ const templateMatch = node.rawCode?.match(/<template>([\s\S]*)<\/template>/);
89
+ if (templateMatch) node.vueTemplate = templateMatch[1];
90
+
91
+ const scriptMatch = node.rawCode?.match(/<script(?: setup)?(?: lang=['"]\w+['"])?>([\s\S]*)<\/script>/);
92
+ if (scriptMatch) node.vueScript = scriptMatch[1];
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Svelte Ecosystem Plugin
99
+ */
100
+ export class SveltePlugin extends BasePlugin {
101
+ get name() {
102
+ return 'svelte';
103
+ }
104
+
105
+ getConfigFiles() {
106
+ return ['package.json', 'svelte.config.js'];
107
+ }
108
+
109
+ async isActive(baseDir) {
110
+ try {
111
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
112
+ return !!(pkgJson.dependencies?.svelte || pkgJson.devDependencies?.svelte);
113
+ } catch {
114
+ return false;
115
+ }
116
+ }
117
+
118
+ getRoutePatterns() {
119
+ return [/\.svelte$/, /\.(tsx?|jsx?)$/];
120
+ }
121
+
122
+ async analyze(node, filePath) {
123
+ if (filePath.endsWith('.svelte')) {
124
+ node.isSvelteComponent = true;
125
+ }
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Angular Ecosystem Plugin
131
+ */
132
+ export class AngularPlugin extends BasePlugin {
133
+ get name() {
134
+ return 'angular';
135
+ }
136
+
137
+ getConfigFiles() {
138
+ return ['package.json', 'angular.json'];
139
+ }
140
+
141
+ async isActive(baseDir) {
142
+ try {
143
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
144
+ return !!(pkgJson.dependencies?.['@angular/core'] || pkgJson.devDependencies?.['@angular/core']);
145
+ } catch {
146
+ return false;
147
+ }
148
+ }
149
+
150
+ getRoutePatterns() {
151
+ return [/\.ts$/];
152
+ }
153
+
154
+ async analyze(node, filePath) {
155
+ if (node.rawCode?.includes('@Component') || node.rawCode?.includes('@Injectable') || node.rawCode?.includes('@NgModule')) {
156
+ node.isAngularEntity = true;
157
+ }
158
+ }
159
+ }
@@ -0,0 +1,184 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { BasePlugin } from '../BasePlugin.js';
4
+
5
+ export class TailwindPlugin extends BasePlugin {
6
+ get name() { return 'tailwind'; }
7
+ getConfigFiles() { return ['tailwind.config.js', 'tailwind.config.ts', 'tailwind.config.cjs', 'tailwind.config.mjs']; }
8
+ async isActive(baseDir) {
9
+ try {
10
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
11
+ return !!(pkgJson.dependencies?.tailwindcss || pkgJson.devDependencies?.tailwindcss);
12
+ } catch { return false; }
13
+ }
14
+ }
15
+
16
+ export class PostcssPlugin extends BasePlugin {
17
+ get name() { return 'postcss'; }
18
+ getConfigFiles() { return ['postcss.config.js', 'postcss.config.cjs', 'postcss.config.mjs']; }
19
+ async isActive(baseDir) {
20
+ try {
21
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
22
+ return !!(pkgJson.dependencies?.postcss || pkgJson.devDependencies?.postcss);
23
+ } catch { return false; }
24
+ }
25
+ }
26
+
27
+ export class JestPlugin extends BasePlugin {
28
+ get name() { return 'jest'; }
29
+ getConfigFiles() { return ['jest.config.js', 'jest.config.ts', 'jest.config.mjs', 'jest.config.cjs', 'package.json']; }
30
+ getRoutePatterns() { return [/\.(test|spec)\.[jt]sx?$/]; }
31
+ async isActive(baseDir) {
32
+ try {
33
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
34
+ return !!(pkgJson.dependencies?.jest || pkgJson.devDependencies?.jest);
35
+ } catch { return false; }
36
+ }
37
+ }
38
+
39
+ export class VitestPlugin extends BasePlugin {
40
+ get name() { return 'vitest'; }
41
+ getConfigFiles() { return ['vitest.config.ts', 'vitest.config.js', 'vitest.config.mjs', 'vitest.workspace.ts']; }
42
+ getRoutePatterns() { return [/\.(test|spec)\.[jt]sx?$/]; }
43
+ async isActive(baseDir) {
44
+ try {
45
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
46
+ return !!(pkgJson.dependencies?.vitest || pkgJson.devDependencies?.vitest);
47
+ } catch { return false; }
48
+ }
49
+ }
50
+
51
+ export class PlaywrightPlugin extends BasePlugin {
52
+ get name() { return 'playwright'; }
53
+ getConfigFiles() { return ['playwright.config.ts', 'playwright.config.js']; }
54
+ getRoutePatterns() { return [/.*\.spec\.[jt]s$/]; }
55
+ async isActive(baseDir) {
56
+ try {
57
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
58
+ return !!(pkgJson.dependencies?.['@playwright/test'] || pkgJson.devDependencies?.['@playwright/test']);
59
+ } catch { return false; }
60
+ }
61
+ }
62
+
63
+ export class CypressPlugin extends BasePlugin {
64
+ get name() { return 'cypress'; }
65
+ getConfigFiles() { return ['cypress.config.ts', 'cypress.config.js']; }
66
+ getRoutePatterns() { return [/cypress\/e2e\/.*\.cy\.[jt]s$/]; }
67
+ async isActive(baseDir) {
68
+ try {
69
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
70
+ return !!(pkgJson.dependencies?.cypress || pkgJson.devDependencies?.cypress);
71
+ } catch { return false; }
72
+ }
73
+ }
74
+
75
+ export class StorybookPlugin extends BasePlugin {
76
+ get name() { return 'storybook'; }
77
+ getConfigFiles() { return ['.storybook/main.js', '.storybook/main.ts', '.storybook/preview.js', '.storybook/preview.ts']; }
78
+ getRoutePatterns() { return [/\.stories\.[jt]sx?$/]; }
79
+ async isActive(baseDir) {
80
+ try {
81
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
82
+ return !!(pkgJson.dependencies?.storybook || pkgJson.devDependencies?.storybook || pkgJson.devDependencies?.['@storybook/react']);
83
+ } catch { return false; }
84
+ }
85
+ }
86
+
87
+ export class EslintPlugin extends BasePlugin {
88
+ get name() { return 'eslint'; }
89
+ getConfigFiles() { return ['.eslintrc', '.eslintrc.js', '.eslintrc.cjs', '.eslintrc.json', 'eslint.config.js', 'eslint.config.mjs']; }
90
+ async isActive(baseDir) {
91
+ try {
92
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
93
+ return !!(pkgJson.dependencies?.eslint || pkgJson.devDependencies?.eslint);
94
+ } catch { return false; }
95
+ }
96
+ }
97
+
98
+ export class PrettierPlugin extends BasePlugin {
99
+ get name() { return 'prettier'; }
100
+ getConfigFiles() { return ['.prettierrc', '.prettierrc.js', '.prettierrc.cjs', '.prettierrc.json', 'prettier.config.js']; }
101
+ async isActive(baseDir) {
102
+ try {
103
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
104
+ return !!(pkgJson.dependencies?.prettier || pkgJson.devDependencies?.prettier);
105
+ } catch { return false; }
106
+ }
107
+ }
108
+
109
+ export class HuskyPlugin extends BasePlugin {
110
+ get name() { return 'husky'; }
111
+ getConfigFiles() { return ['.husky/pre-commit', '.husky/pre-push']; }
112
+ async isActive(baseDir) {
113
+ try {
114
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
115
+ return !!(pkgJson.dependencies?.husky || pkgJson.devDependencies?.husky);
116
+ } catch { return false; }
117
+ }
118
+ }
119
+
120
+ export class LintStagedPlugin extends BasePlugin {
121
+ get name() { return 'lint-staged'; }
122
+ getConfigFiles() { return ['.lintstagedrc', '.lintstagedrc.js', '.lintstagedrc.json', 'lint-staged.config.js', 'package.json']; }
123
+ async isActive(baseDir) {
124
+ try {
125
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
126
+ return !!(pkgJson.dependencies?.['lint-staged'] || pkgJson.devDependencies?.['lint-staged']);
127
+ } catch { return false; }
128
+ }
129
+ }
130
+
131
+ export class CommitlintPlugin extends BasePlugin {
132
+ get name() { return 'commitlint'; }
133
+ getConfigFiles() { return ['.commitlintrc', '.commitlintrc.js', '.commitlintrc.json', 'commitlint.config.js', 'package.json']; }
134
+ async isActive(baseDir) {
135
+ try {
136
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
137
+ return !!(pkgJson.dependencies?.['@commitlint/cli'] || pkgJson.devDependencies?.['@commitlint/cli']);
138
+ } catch { return false; }
139
+ }
140
+ }
141
+
142
+ export class BabelPlugin extends BasePlugin {
143
+ get name() { return 'babel'; }
144
+ getConfigFiles() { return ['.babelrc', '.babelrc.js', '.babelrc.json', 'babel.config.js', 'babel.config.json', 'package.json']; }
145
+ async isActive(baseDir) {
146
+ try {
147
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
148
+ return !!(pkgJson.dependencies?.['@babel/core'] || pkgJson.devDependencies?.['@babel/core']);
149
+ } catch { return false; }
150
+ }
151
+ }
152
+
153
+ export class RollupPlugin extends BasePlugin {
154
+ get name() { return 'rollup'; }
155
+ getConfigFiles() { return ['rollup.config.js', 'rollup.config.mjs', 'rollup.config.ts']; }
156
+ async isActive(baseDir) {
157
+ try {
158
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
159
+ return !!(pkgJson.dependencies?.rollup || pkgJson.devDependencies?.rollup);
160
+ } catch { return false; }
161
+ }
162
+ }
163
+
164
+ export class WebpackPlugin extends BasePlugin {
165
+ get name() { return 'webpack'; }
166
+ getConfigFiles() { return ['webpack.config.js', 'webpack.config.ts', 'webpack.config.mjs', 'webpack.config.cjs']; }
167
+ async isActive(baseDir) {
168
+ try {
169
+ const pkgJson = JSON.parse(await fs.readFile(path.join(baseDir, 'package.json'), 'utf8'));
170
+ return !!(pkgJson.dependencies?.webpack || pkgJson.devDependencies?.webpack);
171
+ } catch { return false; }
172
+ }
173
+ }
174
+
175
+ export class GithubActionsPlugin extends BasePlugin {
176
+ get name() { return 'github-actions'; }
177
+ getConfigFiles() { return ['.github/workflows/*.yml', '.github/workflows/*.yaml']; }
178
+ async isActive(baseDir) {
179
+ try {
180
+ await fs.access(path.join(baseDir, '.github/workflows'));
181
+ return true;
182
+ } catch { return false; }
183
+ }
184
+ }
@@ -0,0 +1,33 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import { BasePlugin } from '../BasePlugin.js';
4
+
5
+ export class NextJsPlugin extends BasePlugin {
6
+ get name() { return 'nextjs'; }
7
+
8
+ getConfigFiles() {
9
+ return ['next.config.js', 'next.config.mjs', 'next.config.ts'];
10
+ }
11
+
12
+ getRoutePatterns() {
13
+ return [
14
+ /\/pages\/api\//,
15
+ /\/pages\/[a-zA-Z0-9_\-\[\]]+/i,
16
+ /\/app\/([\w\-\[\]]+\/)+(page|route|layout|loading|error|not-found)\.(ts|tsx|js|jsx)$/
17
+ ];
18
+ }
19
+
20
+ getRequiredSystemContracts() {
21
+ return ['default', 'getServerSideProps', 'getStaticProps', 'getStaticPaths', 'generateMetadata', 'middleware'];
22
+ }
23
+
24
+ async isActive(baseDir) {
25
+ for (const file of this.getConfigFiles()) {
26
+ try {
27
+ await fs.access(path.join(baseDir, file));
28
+ return true;
29
+ } catch {}
30
+ }
31
+ return false;
32
+ }
33
+ }
@@ -0,0 +1,20 @@
1
+ import { TailwindPlugin, PostcssPlugin, JestPlugin, VitestPlugin, PlaywrightPlugin, CypressPlugin, StorybookPlugin, EslintPlugin, PrettierPlugin, HuskyPlugin, LintStagedPlugin, CommitlintPlugin, BabelPlugin, RollupPlugin, WebpackPlugin, GithubActionsPlugin } from './MorePlugins.js';
2
+
3
+ export function loadAdditionalPlugins(registry) {
4
+ registry.register(new TailwindPlugin(registry.context));
5
+ registry.register(new PostcssPlugin(registry.context));
6
+ registry.register(new JestPlugin(registry.context));
7
+ registry.register(new VitestPlugin(registry.context));
8
+ registry.register(new PlaywrightPlugin(registry.context));
9
+ registry.register(new CypressPlugin(registry.context));
10
+ registry.register(new StorybookPlugin(registry.context));
11
+ registry.register(new EslintPlugin(registry.context));
12
+ registry.register(new PrettierPlugin(registry.context));
13
+ registry.register(new HuskyPlugin(registry.context));
14
+ registry.register(new LintStagedPlugin(registry.context));
15
+ registry.register(new CommitlintPlugin(registry.context));
16
+ registry.register(new BabelPlugin(registry.context));
17
+ registry.register(new RollupPlugin(registry.context));
18
+ registry.register(new WebpackPlugin(registry.context));
19
+ registry.register(new GithubActionsPlugin(registry.context));
20
+ }
@@ -0,0 +1,56 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import { BasePlugin } from '../BasePlugin.js';
4
+
5
+ /**
6
+ * TypeScript Plugin for entkapp.
7
+ * Handles tsconfig.json detection and TypeScript-specific entry points.
8
+ */
9
+ export class TypeScriptPlugin extends BasePlugin {
10
+ get name() {
11
+ return 'typescript';
12
+ }
13
+
14
+ getConfigFiles() {
15
+ return ['tsconfig.json', 'tsconfig.base.json', 'tsconfig.eslint.json'];
16
+ }
17
+
18
+ getRoutePatterns() {
19
+ // Common TypeScript entry points and declaration files
20
+ return [
21
+ /src\/index\.ts$/,
22
+ /src\/main\.ts$/,
23
+ /src\/lib\.ts$/,
24
+ /.*\.d\.ts$/
25
+ ];
26
+ }
27
+
28
+ getRequiredSystemContracts() {
29
+ // TypeScript specific implicit exports or requirements
30
+ return ['default'];
31
+ }
32
+
33
+ /**
34
+ * Custom Getter for v3.2.0: Get the compiler version from the project.
35
+ */
36
+ async getCompilerVersion() {
37
+ try {
38
+ const packageJsonPath = path.join(this.context.cwd, 'package.json');
39
+ const content = await fs.readFile(packageJsonPath, 'utf8');
40
+ const pkg = JSON.parse(content);
41
+ return pkg.devDependencies?.typescript || pkg.dependencies?.typescript || 'unknown';
42
+ } catch {
43
+ return 'not installed';
44
+ }
45
+ }
46
+
47
+ async isActive(baseDir) {
48
+ for (const file of this.getConfigFiles()) {
49
+ try {
50
+ await fs.access(path.join(baseDir, file));
51
+ return true;
52
+ } catch {}
53
+ }
54
+ return false;
55
+ }
56
+ }
@@ -0,0 +1,92 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+
4
+ /**
5
+ * Cross-Reference Dependency Matrix & Breakage Risk Auditor
6
+ * Traces dynamic runtime usage patterns to prevent code pruning from breaking downstream systems.
7
+ */
8
+ export class ImpactAnalyzer {
9
+ constructor(context) {
10
+ this.context = context;
11
+ this.safetyOverlays = [/\.json$/, /\.json5$/, /\.html$/, /\.yaml$/, /\.yml$/];
12
+ }
13
+
14
+ /**
15
+ * Scans non-code assets and dynamic lookups to check if an unused export is needed elsewhere.
16
+ * @param {string} originFile - Absolute path of component housing target symbol
17
+ * @param {string} symbolName - Literal identifier being evaluated for deletion
18
+ * @param {Map} projectGraph - Full project structural graph representation
19
+ */
20
+ async verifyRefactorSafety(originFile, symbolName, projectGraph) {
21
+ // Avoid dropping generic single letter tokens or framework primitives
22
+ if (symbolName === 'default' || symbolName.length <= 2) {
23
+ return { isSafeToPrune: false, blockReason: 'PROTECTED_SYSTEM_CONTRACT_KEYWORD' };
24
+ }
25
+
26
+ // Rule 1: Check across all code files for loose string-based token references
27
+ for (const [filePath, fileNode] of projectGraph.entries()) {
28
+ if (filePath === originFile) continue;
29
+
30
+ // If the symbol name is explicitly referenced in an element lookup or template slice, flag it as risky
31
+ if (fileNode.rawStringReferences && fileNode.rawStringReferences.has(symbolName)) {
32
+ return {
33
+ isSafeToPrune: false,
34
+ blockReason: `LOOSE_STRING_ACCESS_MATCH_FOUND_IN: ${path.relative(this.context.cwd, filePath)}`
35
+ };
36
+ }
37
+
38
+ // Check member property chain lookups: customer.profile.billingAddress
39
+ if (fileNode.propertyAccessChains) {
40
+ for (const chain of fileNode.propertyAccessChains) {
41
+ if (chain.endsWith(`.${symbolName}`) || chain.includes(`.${symbolName}.`)) {
42
+ return {
43
+ isSafeToPrune: false,
44
+ blockReason: `DYNAMIC_PROPERTY_ACCESS_CHAIN_HIT: ${chain}`
45
+ };
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ // Rule 2: Crawl through external static manifests (JSON metadata, HTML routing templates, workflow files)
52
+ const configurations = await this.gatherMetadataFiles(this.context.cwd);
53
+
54
+ for (const confPath of configurations) {
55
+ try {
56
+ const payload = await fs.readFile(confPath, 'utf8');
57
+
58
+ // Match string references inside configuration boundaries
59
+ if (payload.includes(`"${symbolName}"`) || payload.includes(`'${symbolName}'`) || payload.includes(`data-${symbolName}`)) {
60
+ return {
61
+ isSafeToPrune: false,
62
+ blockReason: `METADATA_MANIFEST_DEPENDENCY_FOUND_IN: ${path.relative(this.context.cwd, confPath)}`
63
+ };
64
+ }
65
+ } catch {
66
+ // Read step error; skip unreadable descriptors
67
+ }
68
+ }
69
+
70
+ return { isSafeToPrune: true, blockReason: null };
71
+ }
72
+
73
+ async gatherMetadataFiles(dir, collected = []) {
74
+ try {
75
+ const entities = await fs.readdir(dir, { withFileTypes: true });
76
+ for (const ent of entities) {
77
+ const resolutionPath = path.join(dir, ent.name);
78
+
79
+ if (ent.isDirectory()) {
80
+ if (ent.name === 'node_modules' || ent.name === '.git' || ent.name === '.entkapp-cache' || ent.name === 'dist') continue;
81
+ await this.gatherMetadataFiles(resolutionPath, collected);
82
+ } else if (ent.isFile()) {
83
+ const actsAsMetaAsset = this.safetyOverlays.some(regex => regex.test(ent.name));
84
+ if (actsAsMetaAsset) {
85
+ collected.push(resolutionPath);
86
+ }
87
+ }
88
+ }
89
+ } catch {}
90
+ return collected;
91
+ }
92
+ }