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