@c4a/extract-ts 0.6.3 → 0.6.4
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 +28 -0
- package/README.zh-CN.md +32 -0
- package/index.js +318 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -11,6 +11,34 @@ packages.
|
|
|
11
11
|
|
|
12
12
|
**Depends on:** `@c4a/extract`, `web-tree-sitter`
|
|
13
13
|
|
|
14
|
+
## React Router structural facts
|
|
15
|
+
|
|
16
|
+
Projects that use `extractCustom()` can reuse `extractReactRouterRoutes()` to
|
|
17
|
+
index JSX `<Route>` declarations and route-object arrays. It reports paths,
|
|
18
|
+
components, redirects, conditions, import sources, notes, and source locations
|
|
19
|
+
without classifying product meaning:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { extractReactRouterRoutes } from "@c4a/extract-ts";
|
|
23
|
+
|
|
24
|
+
const routes = extractReactRouterRoutes(source, "src/router.tsx", {
|
|
25
|
+
routeIdPrefix: "web",
|
|
26
|
+
mountPath: "/web",
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## TypeScript module export facts
|
|
31
|
+
|
|
32
|
+
`extractTypeScriptModuleExports()` reads one TypeScript or TSX module and
|
|
33
|
+
returns deterministic named exports, wildcard export targets, and all
|
|
34
|
+
re-export targets. It does not resolve files or infer product meaning:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { extractTypeScriptModuleExports } from "@c4a/extract-ts";
|
|
38
|
+
|
|
39
|
+
const exports = extractTypeScriptModuleExports(source, "src/index.ts");
|
|
40
|
+
```
|
|
41
|
+
|
|
14
42
|
## Current Extraction Coverage
|
|
15
43
|
|
|
16
44
|
### Entry Detection
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# @c4a/extract-ts
|
|
2
|
+
|
|
3
|
+
Context 的 TypeScript/TSX 结构提取包。它实现 `@c4a/extract` 的插件协议,
|
|
4
|
+
也是 SDK `extractTs({ source, collection: "codegraph" })` 阶段使用的默认
|
|
5
|
+
提取器。
|
|
6
|
+
|
|
7
|
+
除 TypeScript 符号、导出和 AST 关系外,包还提供可独立使用的 React Router
|
|
8
|
+
结构提取:
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { extractReactRouterRoutes } from "@c4a/extract-ts";
|
|
12
|
+
|
|
13
|
+
const routes = extractReactRouterRoutes(source, "src/router.tsx", {
|
|
14
|
+
routeIdPrefix: "web",
|
|
15
|
+
mountPath: "/web",
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
该函数读取 JSX `<Route>` 和 route object 数组,返回路径、组件、重定向、
|
|
20
|
+
条件、导入来源、注释及源码位置,不判断业务含义。项目可以在
|
|
21
|
+
`extractCustom()` 中将这些结构事实映射为自己的候选。
|
|
22
|
+
|
|
23
|
+
包还提供单文件导出面读取:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { extractTypeScriptModuleExports } from "@c4a/extract-ts";
|
|
27
|
+
|
|
28
|
+
const exports = extractTypeScriptModuleExports(source, "src/index.ts");
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
返回结果包含具名导出、通配导出目标和全部 re-export 目标。函数不解析文件、
|
|
32
|
+
不追踪依赖,也不判断业务含义,适合由定制提取流程继续映射为领域事实。
|
package/index.js
CHANGED
|
@@ -13296,6 +13296,324 @@ class TypeScriptPlugin {
|
|
|
13296
13296
|
return result;
|
|
13297
13297
|
}
|
|
13298
13298
|
}
|
|
13299
|
+
// src/reactRouter.ts
|
|
13300
|
+
import * as ts from "typescript";
|
|
13301
|
+
function compact(value) {
|
|
13302
|
+
return value.replace(/\s+/gu, " ").trim();
|
|
13303
|
+
}
|
|
13304
|
+
function scalarValue(node2) {
|
|
13305
|
+
if (!node2)
|
|
13306
|
+
return;
|
|
13307
|
+
if (ts.isStringLiteralLike(node2) || ts.isNoSubstitutionTemplateLiteral(node2))
|
|
13308
|
+
return node2.text;
|
|
13309
|
+
if (ts.isNumericLiteral(node2))
|
|
13310
|
+
return Number(node2.text);
|
|
13311
|
+
if (node2.kind === ts.SyntaxKind.TrueKeyword)
|
|
13312
|
+
return true;
|
|
13313
|
+
if (node2.kind === ts.SyntaxKind.FalseKeyword)
|
|
13314
|
+
return false;
|
|
13315
|
+
return;
|
|
13316
|
+
}
|
|
13317
|
+
function findDynamicImport(node2) {
|
|
13318
|
+
let result;
|
|
13319
|
+
const visit = (child) => {
|
|
13320
|
+
if (result)
|
|
13321
|
+
return;
|
|
13322
|
+
if (ts.isCallExpression(child) && child.expression.kind === ts.SyntaxKind.ImportKeyword && child.arguments[0] && ts.isStringLiteralLike(child.arguments[0])) {
|
|
13323
|
+
result = child.arguments[0].text;
|
|
13324
|
+
return;
|
|
13325
|
+
}
|
|
13326
|
+
ts.forEachChild(child, visit);
|
|
13327
|
+
};
|
|
13328
|
+
visit(node2);
|
|
13329
|
+
return result;
|
|
13330
|
+
}
|
|
13331
|
+
function parseSource(source, filePath) {
|
|
13332
|
+
const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
13333
|
+
const imports = new Map;
|
|
13334
|
+
const constants2 = new Map;
|
|
13335
|
+
for (const statement of sourceFile.statements) {
|
|
13336
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
13337
|
+
const moduleSource = statement.moduleSpecifier.text;
|
|
13338
|
+
const clause = statement.importClause;
|
|
13339
|
+
if (clause?.name)
|
|
13340
|
+
imports.set(clause.name.text, moduleSource);
|
|
13341
|
+
const bindings = clause?.namedBindings;
|
|
13342
|
+
if (bindings && ts.isNamedImports(bindings)) {
|
|
13343
|
+
for (const element of bindings.elements)
|
|
13344
|
+
imports.set(element.name.text, moduleSource);
|
|
13345
|
+
}
|
|
13346
|
+
if (bindings && ts.isNamespaceImport(bindings))
|
|
13347
|
+
imports.set(bindings.name.text, moduleSource);
|
|
13348
|
+
}
|
|
13349
|
+
if (!ts.isVariableStatement(statement))
|
|
13350
|
+
continue;
|
|
13351
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
13352
|
+
if (!ts.isIdentifier(declaration.name) || !declaration.initializer)
|
|
13353
|
+
continue;
|
|
13354
|
+
const scalar = scalarValue(declaration.initializer);
|
|
13355
|
+
if (scalar !== undefined)
|
|
13356
|
+
constants2.set(declaration.name.text, scalar);
|
|
13357
|
+
const dynamicImport = findDynamicImport(declaration.initializer);
|
|
13358
|
+
if (dynamicImport)
|
|
13359
|
+
imports.set(declaration.name.text, dynamicImport);
|
|
13360
|
+
}
|
|
13361
|
+
}
|
|
13362
|
+
return { sourceFile, imports, constants: constants2 };
|
|
13363
|
+
}
|
|
13364
|
+
function locationFor(filePath, sourceFile, node2) {
|
|
13365
|
+
const start = sourceFile.getLineAndCharacterOfPosition(node2.getStart(sourceFile));
|
|
13366
|
+
const end = sourceFile.getLineAndCharacterOfPosition(node2.getEnd());
|
|
13367
|
+
return { path: filePath, startLine: start.line + 1, startColumn: start.character + 1, endLine: end.line + 1, endColumn: end.character + 1 };
|
|
13368
|
+
}
|
|
13369
|
+
function joinRoutePath(parent, child, index) {
|
|
13370
|
+
if (index || !child || child === "/")
|
|
13371
|
+
return parent || "/";
|
|
13372
|
+
if (child.startsWith("/"))
|
|
13373
|
+
return child.replace(/\/{2,}/gu, "/");
|
|
13374
|
+
return `${parent.replace(/\/$/u, "")}/${child.replace(/^\//u, "")}`.replace(/\/{2,}/gu, "/");
|
|
13375
|
+
}
|
|
13376
|
+
function routeConditions(node2, sourceFile) {
|
|
13377
|
+
const conditions = [];
|
|
13378
|
+
let current = node2;
|
|
13379
|
+
while (current?.parent) {
|
|
13380
|
+
const parent = current.parent;
|
|
13381
|
+
if (ts.isConditionalExpression(parent)) {
|
|
13382
|
+
const condition = compact(parent.condition.getText(sourceFile));
|
|
13383
|
+
conditions.push(current === parent.whenTrue ? condition : `!(${condition})`);
|
|
13384
|
+
} else if (ts.isBinaryExpression(parent) && parent.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken && current === parent.right) {
|
|
13385
|
+
conditions.push(compact(parent.left.getText(sourceFile)));
|
|
13386
|
+
}
|
|
13387
|
+
if (ts.isFunctionLike(parent))
|
|
13388
|
+
break;
|
|
13389
|
+
current = parent;
|
|
13390
|
+
}
|
|
13391
|
+
return [...new Set(conditions.reverse())];
|
|
13392
|
+
}
|
|
13393
|
+
function jsxAttributes(node2) {
|
|
13394
|
+
const result = new Map;
|
|
13395
|
+
for (const property of node2.attributes.properties)
|
|
13396
|
+
if (ts.isJsxAttribute(property))
|
|
13397
|
+
result.set(property.name.getText(), property);
|
|
13398
|
+
return result;
|
|
13399
|
+
}
|
|
13400
|
+
function jsxExpression(attribute) {
|
|
13401
|
+
const initializer = attribute?.initializer;
|
|
13402
|
+
return initializer && ts.isJsxExpression(initializer) ? initializer.expression : undefined;
|
|
13403
|
+
}
|
|
13404
|
+
function jsxScalar(attribute, constants2) {
|
|
13405
|
+
if (!attribute)
|
|
13406
|
+
return;
|
|
13407
|
+
if (!attribute.initializer)
|
|
13408
|
+
return true;
|
|
13409
|
+
if (ts.isStringLiteral(attribute.initializer))
|
|
13410
|
+
return attribute.initializer.text;
|
|
13411
|
+
const expression = jsxExpression(attribute);
|
|
13412
|
+
return scalarValue(expression) ?? (expression && ts.isIdentifier(expression) ? constants2.get(expression.text) : undefined);
|
|
13413
|
+
}
|
|
13414
|
+
function descendantTags(node2) {
|
|
13415
|
+
const tags = new Set;
|
|
13416
|
+
const visit = (child) => {
|
|
13417
|
+
if (ts.isJsxElement(child) || ts.isJsxSelfClosingElement(child)) {
|
|
13418
|
+
const opening = ts.isJsxElement(child) ? child.openingElement : child;
|
|
13419
|
+
const tag = opening.tagName.getText();
|
|
13420
|
+
if (child !== node2 && tag === "Route")
|
|
13421
|
+
return;
|
|
13422
|
+
if (!["Route", "Routes", "Suspense", "Fragment", "React.Fragment", "Navigate"].includes(tag))
|
|
13423
|
+
tags.add(tag);
|
|
13424
|
+
}
|
|
13425
|
+
ts.forEachChild(child, visit);
|
|
13426
|
+
};
|
|
13427
|
+
visit(node2);
|
|
13428
|
+
return [...tags];
|
|
13429
|
+
}
|
|
13430
|
+
function navigateTarget(node2, sourceFile) {
|
|
13431
|
+
let target;
|
|
13432
|
+
const visit = (child) => {
|
|
13433
|
+
if (target)
|
|
13434
|
+
return;
|
|
13435
|
+
if (ts.isJsxElement(child) || ts.isJsxSelfClosingElement(child)) {
|
|
13436
|
+
const opening = ts.isJsxElement(child) ? child.openingElement : child;
|
|
13437
|
+
if (child !== node2 && opening.tagName.getText() === "Route")
|
|
13438
|
+
return;
|
|
13439
|
+
if (opening.tagName.getText() === "Navigate") {
|
|
13440
|
+
const attribute = jsxAttributes(opening).get("to");
|
|
13441
|
+
const scalar = jsxScalar(attribute, new Map);
|
|
13442
|
+
if (typeof scalar === "string")
|
|
13443
|
+
target = scalar;
|
|
13444
|
+
const expression = jsxExpression(attribute);
|
|
13445
|
+
if (!target && expression) {
|
|
13446
|
+
const text = expression.getText(sourceFile);
|
|
13447
|
+
target = text.match(/pathname\s*:\s*['"]([^'"]+)['"]/u)?.[1] ?? compact(text);
|
|
13448
|
+
}
|
|
13449
|
+
}
|
|
13450
|
+
}
|
|
13451
|
+
ts.forEachChild(child, visit);
|
|
13452
|
+
};
|
|
13453
|
+
visit(node2);
|
|
13454
|
+
return target;
|
|
13455
|
+
}
|
|
13456
|
+
function leadingNote(node2, sourceFile) {
|
|
13457
|
+
const prefix = sourceFile.text.slice(Math.max(0, node2.getFullStart() - 600), node2.getStart(sourceFile));
|
|
13458
|
+
const comments = [...prefix.matchAll(/\/\*+([\s\S]*?)\*\/|\/\/([^\n]*)/gu)];
|
|
13459
|
+
const value = comments.at(-1)?.[1] ?? comments.at(-1)?.[2];
|
|
13460
|
+
return value ? compact(value.replace(/^\s*\*\s?/gmu, "")) : undefined;
|
|
13461
|
+
}
|
|
13462
|
+
function componentSource(component, imports) {
|
|
13463
|
+
const identifier = component?.match(/[A-Za-z_$][\w$]*/u)?.[0];
|
|
13464
|
+
return identifier ? imports.get(identifier) : undefined;
|
|
13465
|
+
}
|
|
13466
|
+
function objectProperty(object2, name) {
|
|
13467
|
+
for (const property of object2.properties) {
|
|
13468
|
+
if (!ts.isPropertyAssignment(property) && !ts.isShorthandPropertyAssignment(property))
|
|
13469
|
+
continue;
|
|
13470
|
+
const key = property.name && (ts.isIdentifier(property.name) || ts.isStringLiteralLike(property.name)) ? property.name.text : undefined;
|
|
13471
|
+
if (key !== name)
|
|
13472
|
+
continue;
|
|
13473
|
+
return ts.isPropertyAssignment(property) ? property.initializer : property.name;
|
|
13474
|
+
}
|
|
13475
|
+
return;
|
|
13476
|
+
}
|
|
13477
|
+
function extractReactRouterRoutes(source, filePath, options = {}) {
|
|
13478
|
+
const parsed = parseSource(source, filePath);
|
|
13479
|
+
const routeIdPrefix = options.routeIdPrefix ?? filePath;
|
|
13480
|
+
const mountPath = options.mountPath ?? "/";
|
|
13481
|
+
const ignoredCandidates = new Set(options.ignoredComponentCandidates ?? []);
|
|
13482
|
+
const routes = [];
|
|
13483
|
+
const relativePath = (fullPath) => {
|
|
13484
|
+
if (mountPath === "/")
|
|
13485
|
+
return fullPath;
|
|
13486
|
+
if (fullPath === mountPath)
|
|
13487
|
+
return "/";
|
|
13488
|
+
return fullPath.startsWith(`${mountPath.replace(/\/$/u, "")}/`) ? fullPath.slice(mountPath.length) : fullPath;
|
|
13489
|
+
};
|
|
13490
|
+
const pushRoute = (input) => {
|
|
13491
|
+
const fullPath = joinRoutePath(input.parentPath, input.path, input.index);
|
|
13492
|
+
const candidates = input.candidates ?? (input.component ? [input.component] : []);
|
|
13493
|
+
const location = locationFor(filePath, parsed.sourceFile, input.node);
|
|
13494
|
+
const sourceModule = componentSource(input.component ?? candidates[0], parsed.imports);
|
|
13495
|
+
const note = leadingNote(input.node, parsed.sourceFile);
|
|
13496
|
+
routes.push({
|
|
13497
|
+
id: `${routeIdPrefix}:${fullPath}:${location.startLine}`,
|
|
13498
|
+
kind: input.redirectTo ? "redirect" : input.component || candidates.length > 0 ? "page" : "group",
|
|
13499
|
+
relativePath: relativePath(fullPath),
|
|
13500
|
+
fullPath,
|
|
13501
|
+
index: input.index,
|
|
13502
|
+
...input.component ? { component: input.component } : candidates[0] ? { component: candidates[0] } : {},
|
|
13503
|
+
...sourceModule ? { componentSource: sourceModule } : {},
|
|
13504
|
+
componentCandidates: candidates,
|
|
13505
|
+
...input.redirectTo ? { redirectTo: input.redirectTo } : {},
|
|
13506
|
+
conditions: routeConditions(input.node, parsed.sourceFile),
|
|
13507
|
+
...note ? { note } : {},
|
|
13508
|
+
location
|
|
13509
|
+
});
|
|
13510
|
+
if (input.children)
|
|
13511
|
+
visitRouteObjects(input.children, fullPath);
|
|
13512
|
+
};
|
|
13513
|
+
const visitRouteObjects = (array, parentPath) => {
|
|
13514
|
+
for (const element of array.elements) {
|
|
13515
|
+
if (!ts.isObjectLiteralExpression(element))
|
|
13516
|
+
continue;
|
|
13517
|
+
const index = scalarValue(objectProperty(element, "index")) === true;
|
|
13518
|
+
const pathValue = scalarValue(objectProperty(element, "path"));
|
|
13519
|
+
const componentNode = objectProperty(element, "Component") ?? objectProperty(element, "element") ?? objectProperty(element, "lazy");
|
|
13520
|
+
const component = componentNode ? compact(componentNode.getText(parsed.sourceFile)) : undefined;
|
|
13521
|
+
const redirectNode = objectProperty(element, "redirectTo") ?? objectProperty(element, "to");
|
|
13522
|
+
const redirect = scalarValue(redirectNode);
|
|
13523
|
+
const children = objectProperty(element, "children");
|
|
13524
|
+
pushRoute({
|
|
13525
|
+
node: element,
|
|
13526
|
+
parentPath,
|
|
13527
|
+
path: typeof pathValue === "string" ? pathValue : "",
|
|
13528
|
+
index,
|
|
13529
|
+
...component ? { component } : {},
|
|
13530
|
+
...typeof redirect === "string" ? { redirectTo: redirect } : {},
|
|
13531
|
+
...children && ts.isArrayLiteralExpression(children) ? { children } : {}
|
|
13532
|
+
});
|
|
13533
|
+
}
|
|
13534
|
+
};
|
|
13535
|
+
const visit = (node2, parentPath) => {
|
|
13536
|
+
if (ts.isJsxElement(node2) || ts.isJsxSelfClosingElement(node2)) {
|
|
13537
|
+
const opening = ts.isJsxElement(node2) ? node2.openingElement : node2;
|
|
13538
|
+
if (opening.tagName.getText() === "Route") {
|
|
13539
|
+
const attributes = jsxAttributes(opening);
|
|
13540
|
+
const index = jsxScalar(attributes.get("index"), parsed.constants) === true;
|
|
13541
|
+
const pathValue = jsxScalar(attributes.get("path"), parsed.constants);
|
|
13542
|
+
const componentNode = jsxExpression(attributes.get("Component"));
|
|
13543
|
+
const elementNode = jsxExpression(attributes.get("element"));
|
|
13544
|
+
const component = componentNode ? compact(componentNode.getText(parsed.sourceFile)) : undefined;
|
|
13545
|
+
const candidateNode = elementNode ?? componentNode ?? node2;
|
|
13546
|
+
const candidates = (component ? [component] : descendantTags(candidateNode)).filter((candidate) => !ignoredCandidates.has(candidate));
|
|
13547
|
+
const fullPath = joinRoutePath(parentPath, typeof pathValue === "string" ? pathValue : "", index);
|
|
13548
|
+
const redirectTo = navigateTarget(candidateNode, parsed.sourceFile);
|
|
13549
|
+
pushRoute({ node: node2, parentPath, path: typeof pathValue === "string" ? pathValue : "", index, ...component ? { component } : {}, candidates, ...redirectTo ? { redirectTo } : {} });
|
|
13550
|
+
if (ts.isJsxElement(node2))
|
|
13551
|
+
for (const child of node2.children)
|
|
13552
|
+
visit(child, fullPath);
|
|
13553
|
+
return;
|
|
13554
|
+
}
|
|
13555
|
+
}
|
|
13556
|
+
if (ts.isCallExpression(node2)) {
|
|
13557
|
+
const callee = node2.expression.getText(parsed.sourceFile);
|
|
13558
|
+
if ((callee === "createBrowserRouter" || callee === "createHashRouter" || callee === "useRoutes") && node2.arguments[0] && ts.isArrayLiteralExpression(node2.arguments[0])) {
|
|
13559
|
+
visitRouteObjects(node2.arguments[0], mountPath);
|
|
13560
|
+
}
|
|
13561
|
+
}
|
|
13562
|
+
ts.forEachChild(node2, (child) => visit(child, parentPath));
|
|
13563
|
+
};
|
|
13564
|
+
visit(parsed.sourceFile, mountPath);
|
|
13565
|
+
return routes.sort((left, right) => left.fullPath.localeCompare(right.fullPath) || left.location.startLine - right.location.startLine || left.location.startColumn - right.location.startColumn);
|
|
13566
|
+
}
|
|
13567
|
+
// src/moduleExports.ts
|
|
13568
|
+
import * as ts2 from "typescript";
|
|
13569
|
+
function exportedDeclarationName(statement) {
|
|
13570
|
+
const exported = ts2.canHaveModifiers(statement) && ts2.getModifiers(statement)?.some((modifier) => modifier.kind === ts2.SyntaxKind.ExportKeyword);
|
|
13571
|
+
if (!exported)
|
|
13572
|
+
return;
|
|
13573
|
+
if ((ts2.isFunctionDeclaration(statement) || ts2.isClassDeclaration(statement) || ts2.isInterfaceDeclaration(statement) || ts2.isTypeAliasDeclaration(statement) || ts2.isEnumDeclaration(statement)) && statement.name) {
|
|
13574
|
+
return statement.name.text;
|
|
13575
|
+
}
|
|
13576
|
+
return;
|
|
13577
|
+
}
|
|
13578
|
+
function extractTypeScriptModuleExports(source, filePath = "module.ts") {
|
|
13579
|
+
const sourceFile = ts2.createSourceFile(filePath, source, ts2.ScriptTarget.Latest, true, filePath.endsWith("x") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS);
|
|
13580
|
+
const named = new Set;
|
|
13581
|
+
const wildcard = new Set;
|
|
13582
|
+
const targets = new Set;
|
|
13583
|
+
for (const statement of sourceFile.statements) {
|
|
13584
|
+
if (ts2.isExportDeclaration(statement)) {
|
|
13585
|
+
const target = statement.moduleSpecifier && ts2.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : undefined;
|
|
13586
|
+
if (target)
|
|
13587
|
+
targets.add(target);
|
|
13588
|
+
if (!statement.exportClause) {
|
|
13589
|
+
if (target)
|
|
13590
|
+
wildcard.add(target);
|
|
13591
|
+
} else if (ts2.isNamedExports(statement.exportClause)) {
|
|
13592
|
+
for (const element of statement.exportClause.elements)
|
|
13593
|
+
named.add(element.name.text);
|
|
13594
|
+
} else if (ts2.isNamespaceExport(statement.exportClause)) {
|
|
13595
|
+
named.add(statement.exportClause.name.text);
|
|
13596
|
+
}
|
|
13597
|
+
continue;
|
|
13598
|
+
}
|
|
13599
|
+
const declarationName = exportedDeclarationName(statement);
|
|
13600
|
+
if (declarationName)
|
|
13601
|
+
named.add(declarationName);
|
|
13602
|
+
if (ts2.isVariableStatement(statement) && ts2.getModifiers(statement)?.some((modifier) => modifier.kind === ts2.SyntaxKind.ExportKeyword)) {
|
|
13603
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
13604
|
+
if (ts2.isIdentifier(declaration.name))
|
|
13605
|
+
named.add(declaration.name.text);
|
|
13606
|
+
}
|
|
13607
|
+
}
|
|
13608
|
+
}
|
|
13609
|
+
return {
|
|
13610
|
+
named: [...named].sort(),
|
|
13611
|
+
wildcard: [...wildcard].sort(),
|
|
13612
|
+
targets: [...targets].sort()
|
|
13613
|
+
};
|
|
13614
|
+
}
|
|
13299
13615
|
export {
|
|
13616
|
+
extractTypeScriptModuleExports,
|
|
13617
|
+
extractReactRouterRoutes,
|
|
13300
13618
|
TypeScriptPlugin
|
|
13301
13619
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c4a/extract-ts",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "TypeScript extraction plugin for C4A ExtractionResult v2",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"node": ">=20"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
+
"typescript": "^5.5.4",
|
|
16
17
|
"web-tree-sitter": "^0.20.8"
|
|
17
18
|
},
|
|
18
19
|
"main": "./index.js"
|