@getpara/paramedic 2.7.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/README.md +131 -0
- package/dist/checks/chain-dependencies.check.d.ts +2 -0
- package/dist/checks/chain-dependencies.check.d.ts.map +1 -0
- package/dist/checks/chain-dependencies.check.js +129 -0
- package/dist/checks/css-import.check.d.ts +2 -0
- package/dist/checks/css-import.check.d.ts.map +1 -0
- package/dist/checks/css-import.check.js +57 -0
- package/dist/checks/deprecated-packages.check.d.ts +2 -0
- package/dist/checks/deprecated-packages.check.d.ts.map +1 -0
- package/dist/checks/deprecated-packages.check.js +52 -0
- package/dist/checks/env-api-key.check.d.ts +2 -0
- package/dist/checks/env-api-key.check.d.ts.map +1 -0
- package/dist/checks/env-api-key.check.js +75 -0
- package/dist/checks/env-var-prefix.check.d.ts +2 -0
- package/dist/checks/env-var-prefix.check.d.ts.map +1 -0
- package/dist/checks/env-var-prefix.check.js +52 -0
- package/dist/checks/index.d.ts +12 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +33 -0
- package/dist/checks/para-provider.check.d.ts +2 -0
- package/dist/checks/para-provider.check.d.ts.map +1 -0
- package/dist/checks/para-provider.check.js +42 -0
- package/dist/checks/query-client.check.d.ts +2 -0
- package/dist/checks/query-client.check.d.ts.map +1 -0
- package/dist/checks/query-client.check.js +58 -0
- package/dist/checks/use-client-directive.check.d.ts +2 -0
- package/dist/checks/use-client-directive.check.d.ts.map +1 -0
- package/dist/checks/use-client-directive.check.js +82 -0
- package/dist/checks/version-consistency.check.d.ts +2 -0
- package/dist/checks/version-consistency.check.d.ts.map +1 -0
- package/dist/checks/version-consistency.check.js +93 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +96 -0
- package/dist/core/check.d.ts +21 -0
- package/dist/core/check.d.ts.map +1 -0
- package/dist/core/check.js +10 -0
- package/dist/core/context.d.ts +3 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +56 -0
- package/dist/core/registry.d.ts +18 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +38 -0
- package/dist/core/reporter.d.ts +5 -0
- package/dist/core/reporter.d.ts.map +1 -0
- package/dist/core/reporter.js +82 -0
- package/dist/core/runner.d.ts +3 -0
- package/dist/core/runner.d.ts.map +1 -0
- package/dist/core/runner.js +38 -0
- package/dist/detectors/framework.d.ts +5 -0
- package/dist/detectors/framework.d.ts.map +1 -0
- package/dist/detectors/framework.js +67 -0
- package/dist/detectors/package-manager.d.ts +3 -0
- package/dist/detectors/package-manager.d.ts.map +1 -0
- package/dist/detectors/package-manager.js +17 -0
- package/dist/detectors/sdk.d.ts +7 -0
- package/dist/detectors/sdk.d.ts.map +1 -0
- package/dist/detectors/sdk.js +42 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/utils/ast-parser.d.ts +10 -0
- package/dist/utils/ast-parser.d.ts.map +1 -0
- package/dist/utils/ast-parser.js +98 -0
- package/dist/utils/file-system.d.ts +9 -0
- package/dist/utils/file-system.d.ts.map +1 -0
- package/dist/utils/file-system.js +81 -0
- package/dist/utils/package-json.d.ts +10 -0
- package/dist/utils/package-json.d.ts.map +1 -0
- package/dist/utils/package-json.js +39 -0
- package/package.json +52 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { defineCheck } from "../core/check.js";
|
|
2
|
+
import { findPatternInFiles } from "../utils/ast-parser.js";
|
|
3
|
+
import { hasDependency } from "../utils/package-json.js";
|
|
4
|
+
const queryClientCheck = defineCheck({
|
|
5
|
+
metadata: {
|
|
6
|
+
id: "query-client",
|
|
7
|
+
name: "QueryClientProvider Setup",
|
|
8
|
+
description: "Checks if QueryClientProvider wraps ParaProvider",
|
|
9
|
+
category: "setup",
|
|
10
|
+
severity: "error",
|
|
11
|
+
enabled: true
|
|
12
|
+
},
|
|
13
|
+
shouldRun(context) {
|
|
14
|
+
return context.sdkType === "@getpara/react-sdk" || context.sdkType === "@getpara/react-sdk-lite";
|
|
15
|
+
},
|
|
16
|
+
async run(context) {
|
|
17
|
+
if (!context.packageJson) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
const hasReactQuery = hasDependency(context.packageJson, "@tanstack/react-query");
|
|
21
|
+
if (!hasReactQuery) {
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
checkId: this.metadata.id,
|
|
25
|
+
passed: false,
|
|
26
|
+
severity: this.metadata.severity,
|
|
27
|
+
message: "@tanstack/react-query is not installed",
|
|
28
|
+
recommendation: "Install: npm install @tanstack/react-query"
|
|
29
|
+
}
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
const queryClientPattern = /QueryClientProvider|QueryClient\(/;
|
|
33
|
+
const locations = await findPatternInFiles(context.files, queryClientPattern, context.shouldIgnoreFile);
|
|
34
|
+
if (locations.length > 0) {
|
|
35
|
+
return [
|
|
36
|
+
{
|
|
37
|
+
checkId: this.metadata.id,
|
|
38
|
+
passed: true,
|
|
39
|
+
severity: this.metadata.severity,
|
|
40
|
+
message: "QueryClientProvider is configured",
|
|
41
|
+
location: locations[0]
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
return [
|
|
46
|
+
{
|
|
47
|
+
checkId: this.metadata.id,
|
|
48
|
+
passed: false,
|
|
49
|
+
severity: this.metadata.severity,
|
|
50
|
+
message: "QueryClientProvider not found",
|
|
51
|
+
recommendation: "Wrap ParaProvider with QueryClientProvider from @tanstack/react-query"
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
export {
|
|
57
|
+
queryClientCheck
|
|
58
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-client-directive.check.d.ts","sourceRoot":"","sources":["../../src/checks/use-client-directive.check.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,uBAAuB,kCAwElC,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { defineCheck } from "../core/check.js";
|
|
2
|
+
import { fileStartsWithDirective } from "../utils/ast-parser.js";
|
|
3
|
+
import { readFile } from "../utils/file-system.js";
|
|
4
|
+
const useClientDirectiveCheck = defineCheck({
|
|
5
|
+
metadata: {
|
|
6
|
+
id: "use-client-directive",
|
|
7
|
+
name: '"use client" Directive',
|
|
8
|
+
description: 'Checks for "use client" directive in Next.js App Router Para components',
|
|
9
|
+
category: "setup",
|
|
10
|
+
severity: "error",
|
|
11
|
+
enabled: true
|
|
12
|
+
},
|
|
13
|
+
shouldRun(context) {
|
|
14
|
+
return context.framework === "nextjs" && (context.sdkType === "@getpara/react-sdk" || context.sdkType === "@getpara/react-sdk-lite");
|
|
15
|
+
},
|
|
16
|
+
async run(context) {
|
|
17
|
+
const results = [];
|
|
18
|
+
const missingDirective = [];
|
|
19
|
+
const hasDirective = [];
|
|
20
|
+
for (const file of context.files) {
|
|
21
|
+
if (!file.endsWith(".tsx") && !file.endsWith(".jsx")) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (context.shouldIgnoreFile(file)) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const content = await readFile(file);
|
|
28
|
+
if (!content) continue;
|
|
29
|
+
const needsUseClient = checkIfNeedsUseClient(content);
|
|
30
|
+
if (!needsUseClient) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const hasUseClient = await fileStartsWithDirective(file, "use client");
|
|
34
|
+
if (hasUseClient) {
|
|
35
|
+
hasDirective.push(file);
|
|
36
|
+
} else {
|
|
37
|
+
missingDirective.push(file);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (missingDirective.length > 0) {
|
|
41
|
+
for (const file of missingDirective) {
|
|
42
|
+
results.push({
|
|
43
|
+
checkId: this.metadata.id,
|
|
44
|
+
passed: false,
|
|
45
|
+
severity: this.metadata.severity,
|
|
46
|
+
message: `Missing "use client" directive`,
|
|
47
|
+
details: "This file defines Para components or uses Para hooks",
|
|
48
|
+
location: { file, line: 1 },
|
|
49
|
+
recommendation: 'Add "use client" at the top of the file'
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (hasDirective.length > 0 && missingDirective.length === 0) {
|
|
54
|
+
results.push({
|
|
55
|
+
checkId: this.metadata.id,
|
|
56
|
+
passed: true,
|
|
57
|
+
severity: this.metadata.severity,
|
|
58
|
+
message: `All ${hasDirective.length} Para component file(s) have "use client" directive`
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return results;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
function checkIfNeedsUseClient(content) {
|
|
65
|
+
const definesParaProvider = /(?:function|const|let|var)\s+(?:ParaProvider|ParaSDKProvider)\s*[=(]/.test(content) || /export\s+(?:function|const)\s+(?:ParaProvider|ParaSDKProvider)/.test(content);
|
|
66
|
+
if (definesParaProvider) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
const usesParaHooks = /\b(?:usePara|useParaModal|useParaClient|useParaSelector|useParaWallet)\s*\(/.test(content);
|
|
70
|
+
if (usesParaHooks) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
const importsFromReactSdkLite = /@getpara\/react-sdk-lite/.test(content);
|
|
74
|
+
const usesDirectParaImport = importsFromReactSdkLite && /import\s+\{[^}]*(?:Para|usePara)[^}]*\}\s+from\s+['"]@getpara/.test(content);
|
|
75
|
+
if (usesDirectParaImport) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
useClientDirectiveCheck
|
|
82
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-consistency.check.d.ts","sourceRoot":"","sources":["../../src/checks/version-consistency.check.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,uBAAuB,kCAoGlC,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { defineCheck } from "../core/check.js";
|
|
2
|
+
import { getParaPackages } from "../utils/package-json.js";
|
|
3
|
+
function normalizeVersion(v) {
|
|
4
|
+
return v.replace(/^[\^~]/, "");
|
|
5
|
+
}
|
|
6
|
+
function isAlphaVersion(version) {
|
|
7
|
+
return /^2\.0\.0-alpha/.test(normalizeVersion(version));
|
|
8
|
+
}
|
|
9
|
+
function isV1Version(version) {
|
|
10
|
+
return /^1\./.test(normalizeVersion(version));
|
|
11
|
+
}
|
|
12
|
+
const versionConsistencyCheck = defineCheck({
|
|
13
|
+
metadata: {
|
|
14
|
+
id: "version-consistency",
|
|
15
|
+
name: "Package Version Consistency",
|
|
16
|
+
description: "Checks if all @getpara/* packages have matching and up-to-date versions",
|
|
17
|
+
category: "dependencies",
|
|
18
|
+
severity: "warning",
|
|
19
|
+
enabled: true
|
|
20
|
+
},
|
|
21
|
+
shouldRun(context) {
|
|
22
|
+
return context.sdkType !== "none" && context.packageJson !== null;
|
|
23
|
+
},
|
|
24
|
+
async run(context) {
|
|
25
|
+
if (!context.packageJson) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
const paraPackages = getParaPackages(context.packageJson);
|
|
29
|
+
if (paraPackages.length === 0) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const results = [];
|
|
33
|
+
const alphaPackages = paraPackages.filter((p) => isAlphaVersion(p.version));
|
|
34
|
+
const v1Packages = paraPackages.filter((p) => isV1Version(p.version));
|
|
35
|
+
if (alphaPackages.length > 0) {
|
|
36
|
+
results.push({
|
|
37
|
+
checkId: this.metadata.id,
|
|
38
|
+
passed: false,
|
|
39
|
+
severity: "error",
|
|
40
|
+
message: "Deprecated alpha version detected",
|
|
41
|
+
details: alphaPackages.map((p) => `${p.name}@${p.version}`).join(", "),
|
|
42
|
+
recommendation: "Upgrade to latest stable 2.x.x version"
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
if (v1Packages.length > 0) {
|
|
46
|
+
results.push({
|
|
47
|
+
checkId: this.metadata.id,
|
|
48
|
+
passed: false,
|
|
49
|
+
severity: "error",
|
|
50
|
+
message: "Outdated v1 version detected",
|
|
51
|
+
details: v1Packages.map((p) => `${p.name}@${p.version}`).join(", "),
|
|
52
|
+
recommendation: "Upgrade to latest 2.x.x version"
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (paraPackages.length > 1) {
|
|
56
|
+
const versions = new Set(paraPackages.map((p) => normalizeVersion(p.version)));
|
|
57
|
+
if (versions.size > 1) {
|
|
58
|
+
const versionGroups = /* @__PURE__ */ new Map();
|
|
59
|
+
paraPackages.forEach(({ name, version }) => {
|
|
60
|
+
const normalized = normalizeVersion(version);
|
|
61
|
+
if (!versionGroups.has(normalized)) {
|
|
62
|
+
versionGroups.set(normalized, []);
|
|
63
|
+
}
|
|
64
|
+
versionGroups.get(normalized).push(name);
|
|
65
|
+
});
|
|
66
|
+
const details = Array.from(versionGroups.entries()).map(([version, packages]) => ` ${version}: ${packages.join(", ")}`).join("\n");
|
|
67
|
+
results.push({
|
|
68
|
+
checkId: this.metadata.id,
|
|
69
|
+
passed: false,
|
|
70
|
+
severity: this.metadata.severity,
|
|
71
|
+
message: "Inconsistent @getpara/* package versions",
|
|
72
|
+
details: `Version mismatch:
|
|
73
|
+
${details}`,
|
|
74
|
+
recommendation: "Update all @getpara/* packages to the same 2.x.x version"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (results.length === 0) {
|
|
79
|
+
const version = normalizeVersion(paraPackages[0].version);
|
|
80
|
+
const message = paraPackages.length === 1 ? `Single Para package: ${paraPackages[0].name}@${version}` : `All ${paraPackages.length} Para packages use version ${version}`;
|
|
81
|
+
results.push({
|
|
82
|
+
checkId: this.metadata.id,
|
|
83
|
+
passed: true,
|
|
84
|
+
severity: this.metadata.severity,
|
|
85
|
+
message
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return results;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
export {
|
|
92
|
+
versionConsistencyCheck
|
|
93
|
+
};
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAwDA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAyDzC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import pc from "picocolors";
|
|
3
|
+
import { createContext } from "./core/context.js";
|
|
4
|
+
import { runChecks } from "./core/runner.js";
|
|
5
|
+
import { printHeader, printDetection, printResults } from "./core/reporter.js";
|
|
6
|
+
import { registerAllChecks } from "./checks/index.js";
|
|
7
|
+
function parseArgs(args) {
|
|
8
|
+
let projectRoot = process.cwd();
|
|
9
|
+
let help = false;
|
|
10
|
+
let version = false;
|
|
11
|
+
for (const arg of args) {
|
|
12
|
+
if (arg === "--help" || arg === "-h") {
|
|
13
|
+
help = true;
|
|
14
|
+
} else if (arg === "--version" || arg === "-v") {
|
|
15
|
+
version = true;
|
|
16
|
+
} else if (!arg.startsWith("-")) {
|
|
17
|
+
projectRoot = arg.startsWith("/") ? arg : `${process.cwd()}/${arg}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return { projectRoot, help, version };
|
|
21
|
+
}
|
|
22
|
+
function printHelp() {
|
|
23
|
+
console.log(`
|
|
24
|
+
${pc.bold("Paramedic")} - Para SDK Diagnostic Tool
|
|
25
|
+
|
|
26
|
+
${pc.bold("Usage:")}
|
|
27
|
+
npx @getpara/paramedic [path]
|
|
28
|
+
|
|
29
|
+
${pc.bold("Options:")}
|
|
30
|
+
-h, --help Show this help message
|
|
31
|
+
-v, --version Show version number
|
|
32
|
+
|
|
33
|
+
${pc.bold("Examples:")}
|
|
34
|
+
npx @getpara/paramedic # Scan current directory
|
|
35
|
+
npx @getpara/paramedic ./my-app # Scan specific directory
|
|
36
|
+
|
|
37
|
+
${pc.bold("Checks performed:")}
|
|
38
|
+
\u2022 API key configuration
|
|
39
|
+
\u2022 CSS styles import
|
|
40
|
+
\u2022 ParaProvider setup
|
|
41
|
+
\u2022 QueryClientProvider wrapping
|
|
42
|
+
\u2022 Package version consistency
|
|
43
|
+
\u2022 Chain dependencies (EVM, Solana, Cosmos)
|
|
44
|
+
\u2022 "use client" directive (Next.js)
|
|
45
|
+
\u2022 Environment variable prefix
|
|
46
|
+
`);
|
|
47
|
+
}
|
|
48
|
+
async function cli() {
|
|
49
|
+
const args = process.argv.slice(2);
|
|
50
|
+
const { projectRoot, help, version } = parseArgs(args);
|
|
51
|
+
if (version) {
|
|
52
|
+
console.log("@getpara/paramedic v2.7.0");
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
if (help) {
|
|
56
|
+
printHelp();
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
printHeader();
|
|
60
|
+
registerAllChecks();
|
|
61
|
+
const s = p.spinner();
|
|
62
|
+
s.start("Analyzing project...");
|
|
63
|
+
let context;
|
|
64
|
+
try {
|
|
65
|
+
context = await createContext(projectRoot);
|
|
66
|
+
s.stop("Analysis complete");
|
|
67
|
+
} catch (error) {
|
|
68
|
+
s.stop("Analysis failed");
|
|
69
|
+
console.log(pc.red("Failed to analyze project:"));
|
|
70
|
+
console.log(pc.dim(error instanceof Error ? error.message : String(error)));
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
printDetection(context);
|
|
74
|
+
if (context.sdkType === "none") {
|
|
75
|
+
console.log(pc.yellow("No Para SDK detected in this project."));
|
|
76
|
+
console.log(pc.dim("Make sure @getpara/react-sdk or @getpara/react-sdk-lite is installed."));
|
|
77
|
+
process.exit(0);
|
|
78
|
+
}
|
|
79
|
+
s.start("Running diagnostic checks...");
|
|
80
|
+
let runResult;
|
|
81
|
+
try {
|
|
82
|
+
runResult = await runChecks(context);
|
|
83
|
+
s.stop("Checks complete");
|
|
84
|
+
} catch (error) {
|
|
85
|
+
s.stop("Checks failed");
|
|
86
|
+
console.log(pc.red("Failed to run checks:"));
|
|
87
|
+
console.log(pc.dim(error instanceof Error ? error.message : String(error)));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
printResults(runResult);
|
|
91
|
+
const exitCode = runResult.failed > 0 ? 1 : 0;
|
|
92
|
+
process.exit(exitCode);
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
cli
|
|
96
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CheckResult, DiagnosticContext, CheckSeverity, CheckCategory } from '../types.js';
|
|
2
|
+
export interface CheckMetadata {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
category: CheckCategory;
|
|
7
|
+
severity: CheckSeverity;
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface Check {
|
|
11
|
+
metadata: CheckMetadata;
|
|
12
|
+
shouldRun: (context: DiagnosticContext) => boolean;
|
|
13
|
+
run: (context: DiagnosticContext) => Promise<CheckResult[]>;
|
|
14
|
+
}
|
|
15
|
+
export interface CheckConfig {
|
|
16
|
+
metadata: CheckMetadata;
|
|
17
|
+
shouldRun?: (context: DiagnosticContext) => boolean;
|
|
18
|
+
run: (context: DiagnosticContext) => Promise<CheckResult[]>;
|
|
19
|
+
}
|
|
20
|
+
export declare function defineCheck(config: CheckConfig): Check;
|
|
21
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/core/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhG,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,SAAS,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC;IACnD,GAAG,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAC7D;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC;IACpD,GAAG,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAC7D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAMtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOrD,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkDnF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import ignoreModule from "ignore";
|
|
3
|
+
import { detectFramework } from "../detectors/framework.js";
|
|
4
|
+
import { detectSDKType } from "../detectors/sdk.js";
|
|
5
|
+
import { detectPackageManager } from "../detectors/package-manager.js";
|
|
6
|
+
import { readPackageJson } from "../utils/package-json.js";
|
|
7
|
+
import { findProjectFiles, readGitignore } from "../utils/file-system.js";
|
|
8
|
+
async function createContext(projectRoot) {
|
|
9
|
+
const packageJson = await readPackageJson(projectRoot);
|
|
10
|
+
const ig = ignoreModule.default();
|
|
11
|
+
const gitignoreContent = await readGitignore(projectRoot);
|
|
12
|
+
if (gitignoreContent) {
|
|
13
|
+
ig.add(gitignoreContent);
|
|
14
|
+
}
|
|
15
|
+
ig.add([
|
|
16
|
+
"node_modules",
|
|
17
|
+
".git",
|
|
18
|
+
"dist",
|
|
19
|
+
"build",
|
|
20
|
+
".next",
|
|
21
|
+
".cache",
|
|
22
|
+
".turbo",
|
|
23
|
+
"coverage",
|
|
24
|
+
".output",
|
|
25
|
+
"out",
|
|
26
|
+
".nuxt",
|
|
27
|
+
".svelte-kit",
|
|
28
|
+
".vercel",
|
|
29
|
+
".netlify"
|
|
30
|
+
]);
|
|
31
|
+
const shouldIgnoreFile = (file) => {
|
|
32
|
+
const relativePath = path.relative(projectRoot, file);
|
|
33
|
+
if (!relativePath || relativePath.startsWith("..")) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return ig.ignores(relativePath);
|
|
37
|
+
};
|
|
38
|
+
const files = await findProjectFiles(projectRoot, shouldIgnoreFile);
|
|
39
|
+
const framework = await detectFramework(projectRoot, packageJson);
|
|
40
|
+
const { sdkType, sdkVersion } = detectSDKType(packageJson);
|
|
41
|
+
const packageManager = await detectPackageManager(projectRoot);
|
|
42
|
+
return {
|
|
43
|
+
projectRoot,
|
|
44
|
+
packageManager,
|
|
45
|
+
framework,
|
|
46
|
+
sdkType,
|
|
47
|
+
sdkVersion,
|
|
48
|
+
files,
|
|
49
|
+
packageJson,
|
|
50
|
+
shouldIgnoreFile,
|
|
51
|
+
cache: /* @__PURE__ */ new Map()
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
createContext
|
|
56
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Check } from './check.js';
|
|
2
|
+
import type { CheckCategory, CheckSeverity } from '../types.js';
|
|
3
|
+
declare class CheckRegistry {
|
|
4
|
+
private checks;
|
|
5
|
+
register(check: Check): void;
|
|
6
|
+
unregister(checkId: string): void;
|
|
7
|
+
get(checkId: string): Check | undefined;
|
|
8
|
+
getAll(): Check[];
|
|
9
|
+
getEnabled(): Check[];
|
|
10
|
+
filterBy(filters: {
|
|
11
|
+
categories?: CheckCategory[];
|
|
12
|
+
severity?: CheckSeverity[];
|
|
13
|
+
}): Check[];
|
|
14
|
+
clear(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare const registry: CheckRegistry;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhE,cAAM,aAAa;IACjB,OAAO,CAAC,MAAM,CAA4B;IAE1C,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAO5B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIjC,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIvC,MAAM,IAAI,KAAK,EAAE;IAIjB,UAAU,IAAI,KAAK,EAAE;IAIrB,QAAQ,CAAC,OAAO,EAAE;QAAE,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAA;KAAE,GAAG,KAAK,EAAE;IAcxF,KAAK,IAAI,IAAI;CAGd;AAED,eAAO,MAAM,QAAQ,eAAsB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
class CheckRegistry {
|
|
2
|
+
checks = /* @__PURE__ */ new Map();
|
|
3
|
+
register(check) {
|
|
4
|
+
if (this.checks.has(check.metadata.id)) {
|
|
5
|
+
throw new Error(`Check "${check.metadata.id}" is already registered`);
|
|
6
|
+
}
|
|
7
|
+
this.checks.set(check.metadata.id, check);
|
|
8
|
+
}
|
|
9
|
+
unregister(checkId) {
|
|
10
|
+
this.checks.delete(checkId);
|
|
11
|
+
}
|
|
12
|
+
get(checkId) {
|
|
13
|
+
return this.checks.get(checkId);
|
|
14
|
+
}
|
|
15
|
+
getAll() {
|
|
16
|
+
return Array.from(this.checks.values());
|
|
17
|
+
}
|
|
18
|
+
getEnabled() {
|
|
19
|
+
return this.getAll().filter((c) => c.metadata.enabled);
|
|
20
|
+
}
|
|
21
|
+
filterBy(filters) {
|
|
22
|
+
let checks = this.getEnabled();
|
|
23
|
+
if (filters.categories?.length) {
|
|
24
|
+
checks = checks.filter((c) => filters.categories.includes(c.metadata.category));
|
|
25
|
+
}
|
|
26
|
+
if (filters.severity?.length) {
|
|
27
|
+
checks = checks.filter((c) => filters.severity.includes(c.metadata.severity));
|
|
28
|
+
}
|
|
29
|
+
return checks;
|
|
30
|
+
}
|
|
31
|
+
clear() {
|
|
32
|
+
this.checks.clear();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const registry = new CheckRegistry();
|
|
36
|
+
export {
|
|
37
|
+
registry
|
|
38
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DiagnosticContext, RunResult } from '../types.js';
|
|
2
|
+
export declare function printHeader(): void;
|
|
3
|
+
export declare function printDetection(context: DiagnosticContext): void;
|
|
4
|
+
export declare function printResults(runResult: RunResult): void;
|
|
5
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/core/reporter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,iBAAiB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAS7E,wBAAgB,WAAW,IAAI,IAAI,CAKlC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAM/D;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CA+CvD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
const symbols = {
|
|
3
|
+
success: "\u2713",
|
|
4
|
+
error: "\u2717",
|
|
5
|
+
warning: "\u26A0",
|
|
6
|
+
info: "\u2139"
|
|
7
|
+
};
|
|
8
|
+
function printHeader() {
|
|
9
|
+
console.log();
|
|
10
|
+
console.log(pc.bgCyan(pc.black(" \u{1F3E5} Paramedic ")));
|
|
11
|
+
console.log(pc.dim("Para SDK Diagnostic Tool"));
|
|
12
|
+
console.log();
|
|
13
|
+
}
|
|
14
|
+
function printDetection(context) {
|
|
15
|
+
console.log(pc.dim("Project Info:"));
|
|
16
|
+
console.log(` Framework: ${pc.cyan(context.framework)}`);
|
|
17
|
+
console.log(` SDK: ${pc.cyan(context.sdkType)}${context.sdkVersion ? pc.dim(` (${context.sdkVersion})`) : ""}`);
|
|
18
|
+
console.log(` Package Manager: ${pc.cyan(context.packageManager)}`);
|
|
19
|
+
console.log();
|
|
20
|
+
}
|
|
21
|
+
function printResults(runResult) {
|
|
22
|
+
console.log(pc.bold("Diagnostic Results"));
|
|
23
|
+
console.log(pc.dim("\u2500".repeat(50)));
|
|
24
|
+
console.log();
|
|
25
|
+
const errors = runResult.results.filter((r) => !r.passed && r.severity === "error");
|
|
26
|
+
const warnings = runResult.results.filter((r) => !r.passed && r.severity === "warning");
|
|
27
|
+
const info = runResult.results.filter((r) => !r.passed && r.severity === "info");
|
|
28
|
+
const passed = runResult.results.filter((r) => r.passed);
|
|
29
|
+
if (errors.length > 0) {
|
|
30
|
+
console.log(pc.red(pc.bold(`${symbols.error} Errors (${errors.length})`)));
|
|
31
|
+
errors.forEach((r) => printResult(r));
|
|
32
|
+
console.log();
|
|
33
|
+
}
|
|
34
|
+
if (warnings.length > 0) {
|
|
35
|
+
console.log(pc.yellow(pc.bold(`${symbols.warning} Warnings (${warnings.length})`)));
|
|
36
|
+
warnings.forEach((r) => printResult(r));
|
|
37
|
+
console.log();
|
|
38
|
+
}
|
|
39
|
+
if (info.length > 0) {
|
|
40
|
+
console.log(pc.blue(pc.bold(`${symbols.info} Info (${info.length})`)));
|
|
41
|
+
info.forEach((r) => printResult(r));
|
|
42
|
+
console.log();
|
|
43
|
+
}
|
|
44
|
+
if (passed.length > 0) {
|
|
45
|
+
console.log(pc.green(pc.bold(`${symbols.success} Passed (${passed.length})`)));
|
|
46
|
+
passed.forEach((r) => {
|
|
47
|
+
console.log(` ${pc.green(symbols.success)} ${pc.dim(r.message)}`);
|
|
48
|
+
});
|
|
49
|
+
console.log();
|
|
50
|
+
}
|
|
51
|
+
console.log(pc.dim("\u2500".repeat(50)));
|
|
52
|
+
console.log();
|
|
53
|
+
console.log(pc.bold("Summary:"));
|
|
54
|
+
console.log(` ${pc.green(symbols.success)} ${runResult.passed} passed`);
|
|
55
|
+
if (runResult.failed > 0) {
|
|
56
|
+
console.log(` ${pc.red(symbols.error)} ${runResult.failed} errors`);
|
|
57
|
+
}
|
|
58
|
+
if (runResult.warnings > 0) {
|
|
59
|
+
console.log(` ${pc.yellow(symbols.warning)} ${runResult.warnings} warnings`);
|
|
60
|
+
}
|
|
61
|
+
console.log();
|
|
62
|
+
}
|
|
63
|
+
function printResult(result) {
|
|
64
|
+
const symbol = result.severity === "error" ? pc.red(symbols.error) : result.severity === "warning" ? pc.yellow(symbols.warning) : pc.blue(symbols.info);
|
|
65
|
+
console.log(` ${symbol} ${result.message}`);
|
|
66
|
+
if (result.details) {
|
|
67
|
+
console.log(` ${pc.dim(result.details)}`);
|
|
68
|
+
}
|
|
69
|
+
if (result.location) {
|
|
70
|
+
const loc = result.location;
|
|
71
|
+
const locStr = loc.line ? `${loc.file}:${loc.line}${loc.column ? `:${loc.column}` : ""}` : loc.file;
|
|
72
|
+
console.log(` ${pc.dim("at")} ${pc.cyan(locStr)}`);
|
|
73
|
+
}
|
|
74
|
+
if (result.recommendation) {
|
|
75
|
+
console.log(` ${pc.cyan("\u2192")} ${result.recommendation}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
printDetection,
|
|
80
|
+
printHeader,
|
|
81
|
+
printResults
|
|
82
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAe,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG3F,wBAAsB,SAAS,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,CAsC1G"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { registry } from "./registry.js";
|
|
2
|
+
async function runChecks(context, options = {}) {
|
|
3
|
+
const checks = registry.filterBy({
|
|
4
|
+
categories: options.categories,
|
|
5
|
+
severity: options.severity
|
|
6
|
+
});
|
|
7
|
+
const results = [];
|
|
8
|
+
for (const check of checks) {
|
|
9
|
+
if (!check.shouldRun(context)) {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const checkResults = await check.run(context);
|
|
14
|
+
results.push(...checkResults);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
results.push({
|
|
17
|
+
checkId: check.metadata.id,
|
|
18
|
+
passed: false,
|
|
19
|
+
severity: "error",
|
|
20
|
+
message: `Check "${check.metadata.name}" threw an error`,
|
|
21
|
+
details: error instanceof Error ? error.message : String(error)
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const passed = results.filter((r) => r.passed).length;
|
|
26
|
+
const failed = results.filter((r) => !r.passed && r.severity === "error").length;
|
|
27
|
+
const warnings = results.filter((r) => !r.passed && r.severity === "warning").length;
|
|
28
|
+
return {
|
|
29
|
+
results,
|
|
30
|
+
passed,
|
|
31
|
+
failed,
|
|
32
|
+
warnings,
|
|
33
|
+
total: results.length
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
runChecks
|
|
38
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Framework, PackageJsonData } from '../types.js';
|
|
2
|
+
export declare function detectFramework(projectRoot: string, packageJson: PackageJsonData | null): Promise<Framework>;
|
|
3
|
+
export declare function getEnvVarPrefix(framework: Framework): string;
|
|
4
|
+
export declare function getEnvAccessPattern(framework: Framework): string;
|
|
5
|
+
//# sourceMappingURL=framework.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework.d.ts","sourceRoot":"","sources":["../../src/detectors/framework.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9D,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CA0ClH;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAc5D;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAahE"}
|