@neat.is/core 0.6.0 → 0.6.1
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/{chunk-5PVQJLPR.js → chunk-3YUNROLT.js} +2 -2
- package/dist/{chunk-CS4GHQO3.js → chunk-7C6ZULNU.js} +114 -8
- package/dist/chunk-7C6ZULNU.js.map +1 -0
- package/dist/cli.cjs +113 -7
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/index.cjs +113 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/neatd.cjs +113 -7
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +2 -2
- package/dist/server.cjs +113 -7
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-CS4GHQO3.js.map +0 -1
- /package/dist/{chunk-5PVQJLPR.js.map → chunk-3YUNROLT.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
routeSpanToProject,
|
|
3
3
|
startDaemon
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3YUNROLT.js";
|
|
5
5
|
import {
|
|
6
6
|
ProjectNameCollisionError,
|
|
7
7
|
addProject,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
thresholdForEdgeType,
|
|
38
38
|
touchLastSeen,
|
|
39
39
|
writeAtomically
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-7C6ZULNU.js";
|
|
41
41
|
import {
|
|
42
42
|
startOtelGrpcReceiver
|
|
43
43
|
} from "./chunk-MVINCLQM.js";
|
package/dist/neatd.cjs
CHANGED
|
@@ -5305,6 +5305,7 @@ init_cjs_shims();
|
|
|
5305
5305
|
var import_node_path22 = __toESM(require("path"), 1);
|
|
5306
5306
|
var import_tree_sitter2 = __toESM(require("tree-sitter"), 1);
|
|
5307
5307
|
var import_tree_sitter_javascript2 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5308
|
+
var import_tree_sitter_python2 = __toESM(require("tree-sitter-python"), 1);
|
|
5308
5309
|
var import_types11 = require("@neat.is/types");
|
|
5309
5310
|
var PARSE_CHUNK2 = 16384;
|
|
5310
5311
|
function parseSource2(parser, source) {
|
|
@@ -5317,6 +5318,11 @@ function makeJsParser2() {
|
|
|
5317
5318
|
p.setLanguage(import_tree_sitter_javascript2.default);
|
|
5318
5319
|
return p;
|
|
5319
5320
|
}
|
|
5321
|
+
function makePyParser2() {
|
|
5322
|
+
const p = new import_tree_sitter2.default();
|
|
5323
|
+
p.setLanguage(import_tree_sitter_python2.default);
|
|
5324
|
+
return p;
|
|
5325
|
+
}
|
|
5320
5326
|
var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
5321
5327
|
"get",
|
|
5322
5328
|
"post",
|
|
@@ -5329,6 +5335,7 @@ var ROUTER_METHODS = /* @__PURE__ */ new Set([
|
|
|
5329
5335
|
]);
|
|
5330
5336
|
var NEXT_APP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
5331
5337
|
var JS_ROUTE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
|
|
5338
|
+
var FASTAPI_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete", "options", "head", "trace"]);
|
|
5332
5339
|
function canonicalizeTemplate(raw) {
|
|
5333
5340
|
let p = raw.split("?")[0].split("#")[0];
|
|
5334
5341
|
if (!p.startsWith("/")) p = "/" + p;
|
|
@@ -5556,8 +5563,102 @@ function nextRoutesFromFile(source, relFile, parser) {
|
|
|
5556
5563
|
}
|
|
5557
5564
|
return [];
|
|
5558
5565
|
}
|
|
5566
|
+
function pyStaticStringText(node) {
|
|
5567
|
+
if (node.type !== "string") return null;
|
|
5568
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
5569
|
+
const child = node.namedChild(i);
|
|
5570
|
+
if (child?.type === "interpolation") return null;
|
|
5571
|
+
if (child?.type === "string_content") return child.text;
|
|
5572
|
+
}
|
|
5573
|
+
return "";
|
|
5574
|
+
}
|
|
5575
|
+
function keywordArrayStrings(argsNode, key) {
|
|
5576
|
+
for (let i = 0; i < argsNode.namedChildCount; i++) {
|
|
5577
|
+
const arg = argsNode.namedChild(i);
|
|
5578
|
+
if (arg?.type !== "keyword_argument") continue;
|
|
5579
|
+
if (arg.childForFieldName("name")?.text !== key) continue;
|
|
5580
|
+
const val = arg.childForFieldName("value");
|
|
5581
|
+
if (!val || val.type !== "list") return [];
|
|
5582
|
+
const out = [];
|
|
5583
|
+
for (let j = 0; j < val.namedChildCount; j++) {
|
|
5584
|
+
const el = val.namedChild(j);
|
|
5585
|
+
if (el?.type === "string") {
|
|
5586
|
+
const s = pyStaticStringText(el);
|
|
5587
|
+
if (s) out.push(s);
|
|
5588
|
+
}
|
|
5589
|
+
}
|
|
5590
|
+
return out;
|
|
5591
|
+
}
|
|
5592
|
+
return [];
|
|
5593
|
+
}
|
|
5594
|
+
function collectApiRouterPrefixes(root) {
|
|
5595
|
+
const prefixes = /* @__PURE__ */ new Map();
|
|
5596
|
+
walk(root, (node) => {
|
|
5597
|
+
if (node.type !== "assignment") return;
|
|
5598
|
+
const right = node.childForFieldName("right");
|
|
5599
|
+
if (!right || right.type !== "call") return;
|
|
5600
|
+
const fn = right.childForFieldName("function");
|
|
5601
|
+
if (!fn) return;
|
|
5602
|
+
const ctor = fn.type === "attribute" ? fn.childForFieldName("attribute")?.text : fn.text;
|
|
5603
|
+
if (ctor !== "APIRouter") return;
|
|
5604
|
+
const left = node.childForFieldName("left");
|
|
5605
|
+
if (!left || left.type !== "identifier") return;
|
|
5606
|
+
const args = right.childForFieldName("arguments");
|
|
5607
|
+
if (!args) return;
|
|
5608
|
+
for (let i = 0; i < args.namedChildCount; i++) {
|
|
5609
|
+
const arg = args.namedChild(i);
|
|
5610
|
+
if (arg?.type !== "keyword_argument") continue;
|
|
5611
|
+
if (arg.childForFieldName("name")?.text !== "prefix") continue;
|
|
5612
|
+
const val = arg.childForFieldName("value");
|
|
5613
|
+
const p = val ? pyStaticStringText(val) : null;
|
|
5614
|
+
if (p !== null) prefixes.set(left.text, p);
|
|
5615
|
+
}
|
|
5616
|
+
});
|
|
5617
|
+
return prefixes;
|
|
5618
|
+
}
|
|
5619
|
+
function fastapiRoutesFromSource(source, parser) {
|
|
5620
|
+
const tree = parseSource2(parser, source);
|
|
5621
|
+
const prefixes = collectApiRouterPrefixes(tree.rootNode);
|
|
5622
|
+
const out = [];
|
|
5623
|
+
walk(tree.rootNode, (node) => {
|
|
5624
|
+
if (node.type !== "decorator") return;
|
|
5625
|
+
const call = node.namedChild(0);
|
|
5626
|
+
if (!call || call.type !== "call") return;
|
|
5627
|
+
const fn = call.childForFieldName("function");
|
|
5628
|
+
if (!fn || fn.type !== "attribute") return;
|
|
5629
|
+
const method = fn.childForFieldName("attribute")?.text?.toLowerCase();
|
|
5630
|
+
if (!method) return;
|
|
5631
|
+
const isVerb = FASTAPI_METHODS.has(method);
|
|
5632
|
+
if (!isVerb && method !== "api_route") return;
|
|
5633
|
+
const args = call.childForFieldName("arguments");
|
|
5634
|
+
const first = args?.namedChild(0);
|
|
5635
|
+
if (!first || first.type !== "string") return;
|
|
5636
|
+
const rawPath = pyStaticStringText(first);
|
|
5637
|
+
if (rawPath === null || !rawPath.startsWith("/")) return;
|
|
5638
|
+
const obj = fn.childForFieldName("object")?.text;
|
|
5639
|
+
const prefix = obj ? prefixes.get(obj) ?? "" : "";
|
|
5640
|
+
const pathTemplate = canonicalizeTemplate(prefix + rawPath);
|
|
5641
|
+
const line = node.startPosition.row + 1;
|
|
5642
|
+
if (isVerb) {
|
|
5643
|
+
out.push({ method: method.toUpperCase(), pathTemplate, line, framework: "fastapi" });
|
|
5644
|
+
return;
|
|
5645
|
+
}
|
|
5646
|
+
const methods = keywordArrayStrings(args, "methods");
|
|
5647
|
+
const list = methods.length > 0 ? methods : ["ALL"];
|
|
5648
|
+
for (const m of list) {
|
|
5649
|
+
out.push({
|
|
5650
|
+
method: m === "ALL" ? "ALL" : m.toUpperCase(),
|
|
5651
|
+
pathTemplate,
|
|
5652
|
+
line,
|
|
5653
|
+
framework: "fastapi"
|
|
5654
|
+
});
|
|
5655
|
+
}
|
|
5656
|
+
});
|
|
5657
|
+
return out;
|
|
5658
|
+
}
|
|
5559
5659
|
async function addRoutes(graph, services) {
|
|
5560
5660
|
const jsParser = makeJsParser2();
|
|
5661
|
+
const pyParser = makePyParser2();
|
|
5561
5662
|
let nodesAdded = 0;
|
|
5562
5663
|
let edgesAdded = 0;
|
|
5563
5664
|
for (const service of services) {
|
|
@@ -5569,15 +5670,20 @@ async function addRoutes(graph, services) {
|
|
|
5569
5670
|
const hasFastify = deps["fastify"] !== void 0;
|
|
5570
5671
|
const hasHono = deps["hono"] !== void 0;
|
|
5571
5672
|
const hasNext = deps["next"] !== void 0;
|
|
5572
|
-
|
|
5673
|
+
const hasFastapi = deps["fastapi"] !== void 0;
|
|
5674
|
+
if (!hasExpress && !hasFastify && !hasHono && !hasNext && !hasFastapi) continue;
|
|
5573
5675
|
const files = await loadSourceFiles(service.dir);
|
|
5574
5676
|
for (const file of files) {
|
|
5575
5677
|
if (isTestPath(file.path)) continue;
|
|
5576
|
-
|
|
5678
|
+
const ext = import_node_path22.default.extname(file.path);
|
|
5679
|
+
const isPy = ext === ".py";
|
|
5680
|
+
if (!JS_ROUTE_EXTENSIONS.has(ext) && !isPy) continue;
|
|
5577
5681
|
const relFile = toPosix2(import_node_path22.default.relative(service.dir, file.path));
|
|
5578
5682
|
let routes;
|
|
5579
5683
|
try {
|
|
5580
|
-
if (
|
|
5684
|
+
if (isPy) {
|
|
5685
|
+
routes = hasFastapi ? fastapiRoutesFromSource(file.content, pyParser) : [];
|
|
5686
|
+
} else if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {
|
|
5581
5687
|
routes = nextRoutesFromFile(file.content, relFile, jsParser);
|
|
5582
5688
|
} else if (hasExpress || hasFastify || hasHono) {
|
|
5583
5689
|
routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono);
|
|
@@ -5761,7 +5867,7 @@ init_cjs_shims();
|
|
|
5761
5867
|
var import_node_path24 = __toESM(require("path"), 1);
|
|
5762
5868
|
var import_tree_sitter3 = __toESM(require("tree-sitter"), 1);
|
|
5763
5869
|
var import_tree_sitter_javascript3 = __toESM(require("tree-sitter-javascript"), 1);
|
|
5764
|
-
var
|
|
5870
|
+
var import_tree_sitter_python3 = __toESM(require("tree-sitter-python"), 1);
|
|
5765
5871
|
var import_types13 = require("@neat.is/types");
|
|
5766
5872
|
var STRING_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set(["string_fragment", "string_content"]);
|
|
5767
5873
|
var JSX_EXTERNAL_LINK_TAGS = /* @__PURE__ */ new Set(["a", "Link", "NavLink", "ExternalLink", "Anchor"]);
|
|
@@ -5816,14 +5922,14 @@ function makeJsParser3() {
|
|
|
5816
5922
|
p.setLanguage(import_tree_sitter_javascript3.default);
|
|
5817
5923
|
return p;
|
|
5818
5924
|
}
|
|
5819
|
-
function
|
|
5925
|
+
function makePyParser3() {
|
|
5820
5926
|
const p = new import_tree_sitter3.default();
|
|
5821
|
-
p.setLanguage(
|
|
5927
|
+
p.setLanguage(import_tree_sitter_python3.default);
|
|
5822
5928
|
return p;
|
|
5823
5929
|
}
|
|
5824
5930
|
async function addHttpCallEdges(graph, services) {
|
|
5825
5931
|
const jsParser = makeJsParser3();
|
|
5826
|
-
const pyParser =
|
|
5932
|
+
const pyParser = makePyParser3();
|
|
5827
5933
|
const { knownHosts, hostToNodeId } = buildServiceHostIndex(services);
|
|
5828
5934
|
let nodesAdded = 0;
|
|
5829
5935
|
let edgesAdded = 0;
|