@agent-scope/manifest 1.20.0 → 1.20.2
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/index.cjs +245 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +246 -19
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync } from 'fs';
|
|
1
|
+
import { realpathSync, existsSync, readFileSync } from 'fs';
|
|
2
2
|
import { join, relative } from 'path';
|
|
3
3
|
import { Project, Node } from 'ts-morph';
|
|
4
4
|
|
|
@@ -333,7 +333,7 @@ function expandUnionValues(type) {
|
|
|
333
333
|
}
|
|
334
334
|
return values.length > 0 ? values : void 0;
|
|
335
335
|
}
|
|
336
|
-
function buildPropDescriptor(type, required, defaultValue) {
|
|
336
|
+
function buildPropDescriptor(type, required, defaultValue, source, sourceGroup) {
|
|
337
337
|
const kind = resolvePropKind(type);
|
|
338
338
|
const desc = {
|
|
339
339
|
type: kind,
|
|
@@ -348,6 +348,12 @@ function buildPropDescriptor(type, required, defaultValue) {
|
|
|
348
348
|
desc.default = defaultValue;
|
|
349
349
|
desc.required = false;
|
|
350
350
|
}
|
|
351
|
+
if (source !== void 0) {
|
|
352
|
+
desc.source = source;
|
|
353
|
+
}
|
|
354
|
+
if (sourceGroup !== void 0) {
|
|
355
|
+
desc.sourceGroup = sourceGroup;
|
|
356
|
+
}
|
|
351
357
|
return desc;
|
|
352
358
|
}
|
|
353
359
|
function extractPropsFromType(typeName, sourceFile, defaultValues = {}) {
|
|
@@ -359,25 +365,47 @@ function extractPropsFromType(typeName, sourceFile, defaultValues = {}) {
|
|
|
359
365
|
if (name.startsWith("[")) continue;
|
|
360
366
|
const type = prop.getType();
|
|
361
367
|
const required = !prop.hasQuestionToken();
|
|
362
|
-
props[name] = buildPropDescriptor(type, required, defaultValues[name]);
|
|
368
|
+
props[name] = buildPropDescriptor(type, required, defaultValues[name], "own");
|
|
363
369
|
}
|
|
364
370
|
return props;
|
|
365
371
|
}
|
|
366
372
|
const typeAlias = sourceFile.getTypeAlias(typeName);
|
|
367
373
|
if (typeAlias) {
|
|
368
374
|
const aliasType = typeAlias.getType();
|
|
369
|
-
if (aliasType.isObject()) {
|
|
375
|
+
if (aliasType.isObject() || aliasType.isIntersection()) {
|
|
370
376
|
for (const prop of aliasType.getProperties()) {
|
|
371
377
|
const name = prop.getName();
|
|
372
378
|
if (name.startsWith("[")) continue;
|
|
373
379
|
const decls = prop.getDeclarations();
|
|
374
|
-
|
|
380
|
+
let required = decls.length === 0 || !prop.getDeclarations().some((d) => Node.isPropertySignature(d) && d.hasQuestionToken());
|
|
375
381
|
const valType = prop.getTypeAtLocation(sourceFile);
|
|
376
|
-
|
|
382
|
+
if (required && typeIncludesUndefined(valType)) {
|
|
383
|
+
required = false;
|
|
384
|
+
}
|
|
385
|
+
const { source, sourceGroup } = classifyPropSource(prop);
|
|
386
|
+
props[name] = buildPropDescriptor(
|
|
387
|
+
valType,
|
|
388
|
+
required,
|
|
389
|
+
defaultValues[name],
|
|
390
|
+
source,
|
|
391
|
+
sourceGroup
|
|
392
|
+
);
|
|
377
393
|
}
|
|
378
394
|
}
|
|
379
395
|
return props;
|
|
380
396
|
}
|
|
397
|
+
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
398
|
+
const match = importDecl.getNamedImports().find((ni) => {
|
|
399
|
+
const localName = ni.getAliasNode()?.getText() ?? ni.getName();
|
|
400
|
+
return localName === typeName;
|
|
401
|
+
});
|
|
402
|
+
if (!match) continue;
|
|
403
|
+
const importedFile = importDecl.getModuleSpecifierSourceFile();
|
|
404
|
+
if (importedFile) {
|
|
405
|
+
const originalName = match.getName();
|
|
406
|
+
return extractPropsFromType(originalName, importedFile, defaultValues);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
381
409
|
return props;
|
|
382
410
|
}
|
|
383
411
|
function inferPropsTypeName(params) {
|
|
@@ -474,6 +502,78 @@ function extractNameFromWrappedCall(node) {
|
|
|
474
502
|
}
|
|
475
503
|
return void 0;
|
|
476
504
|
}
|
|
505
|
+
function extractForwardRefPropsTypeNode(node) {
|
|
506
|
+
if (!Node.isCallExpression(node)) return void 0;
|
|
507
|
+
const expr = node.getExpression();
|
|
508
|
+
const name = expr.getText();
|
|
509
|
+
if (name === "React.forwardRef" || name === "forwardRef") {
|
|
510
|
+
const typeArgs = node.getTypeArguments();
|
|
511
|
+
if (typeArgs.length >= 2 && typeArgs[1]) {
|
|
512
|
+
return typeArgs[1];
|
|
513
|
+
}
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
const args = node.getArguments();
|
|
517
|
+
if (args[0] && Node.isCallExpression(args[0])) {
|
|
518
|
+
return extractForwardRefPropsTypeNode(args[0]);
|
|
519
|
+
}
|
|
520
|
+
return void 0;
|
|
521
|
+
}
|
|
522
|
+
function typeIncludesUndefined(type) {
|
|
523
|
+
if (type.isUndefined()) return true;
|
|
524
|
+
if (type.isUnion()) {
|
|
525
|
+
return type.getUnionTypes().some((t) => t.isUndefined());
|
|
526
|
+
}
|
|
527
|
+
return false;
|
|
528
|
+
}
|
|
529
|
+
var REACT_INTERFACES = /* @__PURE__ */ new Set([
|
|
530
|
+
"Attributes",
|
|
531
|
+
"RefAttributes",
|
|
532
|
+
"ClassAttributes",
|
|
533
|
+
"DOMAttributes"
|
|
534
|
+
]);
|
|
535
|
+
function classifyPropSource(prop) {
|
|
536
|
+
const decls = prop.getDeclarations();
|
|
537
|
+
if (decls.length === 0) return { source: "inherited" };
|
|
538
|
+
const allInNodeModules = decls.every(
|
|
539
|
+
(d) => d.getSourceFile().getFilePath().includes("/node_modules/")
|
|
540
|
+
);
|
|
541
|
+
if (!allInNodeModules) return { source: "own" };
|
|
542
|
+
for (const d of decls) {
|
|
543
|
+
const parent = d.getParent();
|
|
544
|
+
if (!Node.isInterfaceDeclaration(parent)) continue;
|
|
545
|
+
const ifaceName = parent.getName();
|
|
546
|
+
if (ifaceName === "AriaAttributes") return { source: "inherited", sourceGroup: "aria" };
|
|
547
|
+
if (ifaceName.endsWith("HTMLAttributes")) return { source: "inherited", sourceGroup: "html" };
|
|
548
|
+
if (REACT_INTERFACES.has(ifaceName)) return { source: "inherited", sourceGroup: "react" };
|
|
549
|
+
}
|
|
550
|
+
const filePath = decls[0]?.getSourceFile().getFilePath() ?? "";
|
|
551
|
+
const pkgMatch = filePath.match(/node_modules\/((?:@[^/]+\/)?[^/]+)/);
|
|
552
|
+
if (pkgMatch?.[1]) {
|
|
553
|
+
const pkg = pkgMatch[1];
|
|
554
|
+
if (pkg === "@types/react" || pkg === "react")
|
|
555
|
+
return { source: "inherited", sourceGroup: "react" };
|
|
556
|
+
return { source: "inherited", sourceGroup: pkg };
|
|
557
|
+
}
|
|
558
|
+
return { source: "inherited" };
|
|
559
|
+
}
|
|
560
|
+
function extractPropsFromResolvedType(resolvedType, sourceFile, defaultValues = {}) {
|
|
561
|
+
const props = {};
|
|
562
|
+
if (!resolvedType.isObject() && !resolvedType.isIntersection()) return props;
|
|
563
|
+
for (const prop of resolvedType.getProperties()) {
|
|
564
|
+
const name = prop.getName();
|
|
565
|
+
if (name.startsWith("[")) continue;
|
|
566
|
+
const decls = prop.getDeclarations();
|
|
567
|
+
let required = decls.length === 0 || !decls.some((d) => Node.isPropertySignature(d) && d.hasQuestionToken());
|
|
568
|
+
const valType = prop.getTypeAtLocation(sourceFile);
|
|
569
|
+
if (required && typeIncludesUndefined(valType)) {
|
|
570
|
+
required = false;
|
|
571
|
+
}
|
|
572
|
+
const { source, sourceGroup } = classifyPropSource(prop);
|
|
573
|
+
props[name] = buildPropDescriptor(valType, required, defaultValues[name], source, sourceGroup);
|
|
574
|
+
}
|
|
575
|
+
return props;
|
|
576
|
+
}
|
|
477
577
|
function nodeReturnsJsx(node) {
|
|
478
578
|
let found = false;
|
|
479
579
|
function visit(n) {
|
|
@@ -496,9 +596,10 @@ function matchGlob(pattern, value) {
|
|
|
496
596
|
function extractTsDocTags(declNode) {
|
|
497
597
|
let collection;
|
|
498
598
|
let internal = false;
|
|
599
|
+
const keywords = [];
|
|
499
600
|
const nodeWithDocs = declNode;
|
|
500
601
|
if (typeof nodeWithDocs.getJsDocs !== "function") {
|
|
501
|
-
return { collection, internal };
|
|
602
|
+
return { collection, internal, keywords };
|
|
502
603
|
}
|
|
503
604
|
const jsDocs = nodeWithDocs.getJsDocs();
|
|
504
605
|
for (const jsDoc of jsDocs) {
|
|
@@ -511,10 +612,18 @@ function extractTsDocTags(declNode) {
|
|
|
511
612
|
}
|
|
512
613
|
} else if (tagName === "internal") {
|
|
513
614
|
internal = true;
|
|
615
|
+
} else if (tagName === "keywords") {
|
|
616
|
+
const comment = tag.getComment();
|
|
617
|
+
if (comment && typeof comment === "string") {
|
|
618
|
+
for (const kw of comment.split(",")) {
|
|
619
|
+
const trimmed = kw.trim();
|
|
620
|
+
if (trimmed) keywords.push(trimmed);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
514
623
|
}
|
|
515
624
|
}
|
|
516
625
|
}
|
|
517
|
-
return { collection, internal };
|
|
626
|
+
return { collection, internal, keywords };
|
|
518
627
|
}
|
|
519
628
|
function readCollectionFromScopeFile(scopeFilePath, project) {
|
|
520
629
|
let sf = project.getSourceFile(scopeFilePath);
|
|
@@ -595,8 +704,9 @@ function processSourceFile(sourceFile, rootDir, project) {
|
|
|
595
704
|
requiredContexts: detectRequiredContexts(fn, sourceFile, project),
|
|
596
705
|
sideEffects: detectSideEffects(fn),
|
|
597
706
|
scopeFile: null,
|
|
598
|
-
// collection and
|
|
599
|
-
internal: false
|
|
707
|
+
// collection, internal, and keywords will be filled in after all components are collected
|
|
708
|
+
internal: false,
|
|
709
|
+
keywords: []
|
|
600
710
|
}
|
|
601
711
|
});
|
|
602
712
|
}
|
|
@@ -634,7 +744,16 @@ function processSourceFile(sourceFile, rootDir, project) {
|
|
|
634
744
|
}
|
|
635
745
|
const propsTypeName = inferPropsTypeName(params);
|
|
636
746
|
const defaults = extractDefaultsFromDestructuring(params);
|
|
637
|
-
|
|
747
|
+
let props = {};
|
|
748
|
+
if (propsTypeName) {
|
|
749
|
+
props = extractPropsFromType(propsTypeName, sourceFile, defaults);
|
|
750
|
+
}
|
|
751
|
+
if (Object.keys(props).length === 0 && wrappers.forwardedRef) {
|
|
752
|
+
const propsTypeNode = extractForwardRefPropsTypeNode(initializer);
|
|
753
|
+
if (propsTypeNode) {
|
|
754
|
+
props = extractPropsFromResolvedType(propsTypeNode.getType(), sourceFile, defaults);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
638
757
|
const composes = collectJsxCompositions(bodyNode);
|
|
639
758
|
const startLine = varDecl.getStartLineNumber();
|
|
640
759
|
const endLine = varDecl.getEndLineNumber();
|
|
@@ -662,7 +781,8 @@ function processSourceFile(sourceFile, rootDir, project) {
|
|
|
662
781
|
requiredContexts: detectRequiredContexts(bodyNode, sourceFile, project),
|
|
663
782
|
sideEffects: detectSideEffects(bodyNode),
|
|
664
783
|
scopeFile: null,
|
|
665
|
-
internal: false
|
|
784
|
+
internal: false,
|
|
785
|
+
keywords: []
|
|
666
786
|
}
|
|
667
787
|
});
|
|
668
788
|
}
|
|
@@ -712,19 +832,21 @@ function processSourceFile(sourceFile, rootDir, project) {
|
|
|
712
832
|
requiredContexts: [],
|
|
713
833
|
sideEffects: detectSideEffects(cls),
|
|
714
834
|
scopeFile: null,
|
|
715
|
-
internal: false
|
|
835
|
+
internal: false,
|
|
836
|
+
keywords: []
|
|
716
837
|
}
|
|
717
838
|
});
|
|
718
839
|
}
|
|
719
840
|
return results;
|
|
720
841
|
}
|
|
721
842
|
function generateManifest(config) {
|
|
843
|
+
const normalizedRootDir = realpathSync(config.rootDir);
|
|
722
844
|
const {
|
|
723
|
-
rootDir,
|
|
724
845
|
include = ["src/**/*.tsx", "src/**/*.ts"],
|
|
725
846
|
exclude = ["**/node_modules/**", "**/*.test.*", "**/*.spec.*", "**/dist/**", "**/*.d.ts"],
|
|
726
|
-
tsConfigFilePath = join(
|
|
847
|
+
tsConfigFilePath = join(normalizedRootDir, "tsconfig.json")
|
|
727
848
|
} = config;
|
|
849
|
+
const rootDir = normalizedRootDir;
|
|
728
850
|
const project = new Project({
|
|
729
851
|
tsConfigFilePath,
|
|
730
852
|
skipAddingFilesFromTsConfig: true
|
|
@@ -787,14 +909,16 @@ function generateManifest(config) {
|
|
|
787
909
|
const sf = project.getSourceFile(absFilePath);
|
|
788
910
|
let tsdocCollection;
|
|
789
911
|
let tsdocInternal = false;
|
|
912
|
+
let tsdocKeywords = [];
|
|
790
913
|
if (sf) {
|
|
791
914
|
const fn = sf.getFunction(compName);
|
|
792
915
|
if (fn) {
|
|
793
916
|
const tags = extractTsDocTags(fn);
|
|
794
917
|
tsdocCollection = tags.collection;
|
|
795
918
|
tsdocInternal = tags.internal;
|
|
919
|
+
tsdocKeywords = tags.keywords;
|
|
796
920
|
}
|
|
797
|
-
if (tsdocCollection === void 0 && !tsdocInternal) {
|
|
921
|
+
if (tsdocCollection === void 0 && !tsdocInternal && tsdocKeywords.length === 0) {
|
|
798
922
|
const varDecl = sf.getVariableDeclaration(compName);
|
|
799
923
|
if (varDecl) {
|
|
800
924
|
const varStmt = varDecl.getVariableStatement();
|
|
@@ -802,15 +926,17 @@ function generateManifest(config) {
|
|
|
802
926
|
const tags = extractTsDocTags(varStmt);
|
|
803
927
|
tsdocCollection = tags.collection;
|
|
804
928
|
tsdocInternal = tags.internal;
|
|
929
|
+
tsdocKeywords = tags.keywords;
|
|
805
930
|
}
|
|
806
931
|
}
|
|
807
932
|
}
|
|
808
|
-
if (tsdocCollection === void 0 && !tsdocInternal) {
|
|
933
|
+
if (tsdocCollection === void 0 && !tsdocInternal && tsdocKeywords.length === 0) {
|
|
809
934
|
const cls = sf.getClass(compName);
|
|
810
935
|
if (cls) {
|
|
811
936
|
const tags = extractTsDocTags(cls);
|
|
812
937
|
tsdocCollection = tags.collection;
|
|
813
938
|
tsdocInternal = tags.internal;
|
|
939
|
+
tsdocKeywords = tags.keywords;
|
|
814
940
|
}
|
|
815
941
|
}
|
|
816
942
|
}
|
|
@@ -831,11 +957,16 @@ function generateManifest(config) {
|
|
|
831
957
|
(p) => matchGlob(p, desc.filePath) || matchGlob(p, desc.displayName)
|
|
832
958
|
);
|
|
833
959
|
}
|
|
960
|
+
const iconPats = config.iconPatterns ?? [];
|
|
961
|
+
const isIcon = iconPats.length > 0 && iconPats.some((p) => matchGlob(p, desc.filePath) || matchGlob(p, desc.displayName));
|
|
834
962
|
const resolvedCollection = tsdocCollection ?? scopeFileCollection ?? configCollection;
|
|
835
963
|
if (resolvedCollection !== void 0) {
|
|
836
964
|
desc.collection = resolvedCollection;
|
|
837
965
|
}
|
|
838
|
-
desc.internal = tsdocInternal || configInternal;
|
|
966
|
+
desc.internal = tsdocInternal || configInternal || isIcon;
|
|
967
|
+
if (tsdocKeywords.length > 0) {
|
|
968
|
+
desc.keywords = tsdocKeywords;
|
|
969
|
+
}
|
|
839
970
|
}
|
|
840
971
|
return {
|
|
841
972
|
version: "0.1",
|
|
@@ -852,7 +983,103 @@ function detectScopeFile(componentFilePath, rootDir) {
|
|
|
852
983
|
for (const ext of SCOPE_EXTENSIONS) {
|
|
853
984
|
const candidate = `${stem}${ext}`;
|
|
854
985
|
if (existsSync(candidate)) {
|
|
855
|
-
return
|
|
986
|
+
return readScopeFileMeta(candidate);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
function readScopeFileMeta(filePath) {
|
|
992
|
+
const source = readFileSync(filePath, "utf-8");
|
|
993
|
+
const scenarioNames = extractScenarioNames(source);
|
|
994
|
+
const hasWrapper = /\bexport\s+(?:const|function)\s+wrapper\b/.test(source) || /\bwrapper\s*:/.test(source);
|
|
995
|
+
return { filePath, scenarioNames, hasWrapper };
|
|
996
|
+
}
|
|
997
|
+
function extractScenarioNames(source) {
|
|
998
|
+
const objectSource = extractScenarioObjectLiteral(source, /\bexport\s+const\s+scenarios\s*=\s*\{/) ?? extractScenarioObjectLiteral(source, /\bscenarios\s*:\s*\{/);
|
|
999
|
+
if (objectSource === null) return [];
|
|
1000
|
+
const names = /* @__PURE__ */ new Set();
|
|
1001
|
+
let depth = 0;
|
|
1002
|
+
let quote = null;
|
|
1003
|
+
let escaped = false;
|
|
1004
|
+
let token = "";
|
|
1005
|
+
const flushTokenAsKey = () => {
|
|
1006
|
+
const name = token.trim().replace(/^['"]|['"]$/g, "");
|
|
1007
|
+
if (depth === 0 && name && name !== "scenarios" && name !== "wrapper") {
|
|
1008
|
+
names.add(name);
|
|
1009
|
+
}
|
|
1010
|
+
token = "";
|
|
1011
|
+
};
|
|
1012
|
+
for (let i = 0; i < objectSource.length; i += 1) {
|
|
1013
|
+
const char = objectSource[i];
|
|
1014
|
+
if (quote !== null) {
|
|
1015
|
+
token += char;
|
|
1016
|
+
if (escaped) {
|
|
1017
|
+
escaped = false;
|
|
1018
|
+
} else if (char === "\\") {
|
|
1019
|
+
escaped = true;
|
|
1020
|
+
} else if (char === quote) {
|
|
1021
|
+
quote = null;
|
|
1022
|
+
}
|
|
1023
|
+
continue;
|
|
1024
|
+
}
|
|
1025
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
1026
|
+
quote = char;
|
|
1027
|
+
token += char;
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
if (char === "{") {
|
|
1031
|
+
depth += 1;
|
|
1032
|
+
token = "";
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
if (char === "}") {
|
|
1036
|
+
depth = Math.max(0, depth - 1);
|
|
1037
|
+
token = "";
|
|
1038
|
+
continue;
|
|
1039
|
+
}
|
|
1040
|
+
if (depth === 0 && char === ":") {
|
|
1041
|
+
flushTokenAsKey();
|
|
1042
|
+
continue;
|
|
1043
|
+
}
|
|
1044
|
+
if (depth === 0 && char === ",") {
|
|
1045
|
+
token = "";
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
token += char;
|
|
1049
|
+
}
|
|
1050
|
+
return [...names];
|
|
1051
|
+
}
|
|
1052
|
+
function extractScenarioObjectLiteral(source, pattern) {
|
|
1053
|
+
const match = pattern.exec(source);
|
|
1054
|
+
if (!match) return null;
|
|
1055
|
+
const openBraceIndex = source.indexOf("{", match.index);
|
|
1056
|
+
if (openBraceIndex < 0) return null;
|
|
1057
|
+
let depth = 0;
|
|
1058
|
+
let quote = null;
|
|
1059
|
+
let escaped = false;
|
|
1060
|
+
for (let i = openBraceIndex; i < source.length; i += 1) {
|
|
1061
|
+
const char = source[i];
|
|
1062
|
+
if (quote !== null) {
|
|
1063
|
+
if (escaped) {
|
|
1064
|
+
escaped = false;
|
|
1065
|
+
} else if (char === "\\") {
|
|
1066
|
+
escaped = true;
|
|
1067
|
+
} else if (char === quote) {
|
|
1068
|
+
quote = null;
|
|
1069
|
+
}
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
1073
|
+
quote = char;
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
if (char === "{") {
|
|
1077
|
+
depth += 1;
|
|
1078
|
+
continue;
|
|
1079
|
+
}
|
|
1080
|
+
if (char === "}") {
|
|
1081
|
+
depth -= 1;
|
|
1082
|
+
if (depth === 0) return source.slice(openBraceIndex + 1, i);
|
|
856
1083
|
}
|
|
857
1084
|
}
|
|
858
1085
|
return null;
|