@agent-scope/manifest 1.19.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 +349 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -1
- package/dist/index.d.ts +87 -1
- package/dist/index.js +350 -14
- 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) {
|
|
@@ -489,6 +589,62 @@ function nodeReturnsJsx(node) {
|
|
|
489
589
|
visit(node);
|
|
490
590
|
return found;
|
|
491
591
|
}
|
|
592
|
+
function matchGlob(pattern, value) {
|
|
593
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
594
|
+
const regexStr = escaped.replace(/\*\*/g, "\xA7GLOBSTAR\xA7").replace(/\*/g, "[^/]*").replace(/§GLOBSTAR§/g, ".*");
|
|
595
|
+
const regex = new RegExp(`^${regexStr}$`, "i");
|
|
596
|
+
return regex.test(value);
|
|
597
|
+
}
|
|
598
|
+
function extractTsDocTags(declNode) {
|
|
599
|
+
let collection;
|
|
600
|
+
let internal = false;
|
|
601
|
+
const keywords = [];
|
|
602
|
+
const nodeWithDocs = declNode;
|
|
603
|
+
if (typeof nodeWithDocs.getJsDocs !== "function") {
|
|
604
|
+
return { collection, internal, keywords };
|
|
605
|
+
}
|
|
606
|
+
const jsDocs = nodeWithDocs.getJsDocs();
|
|
607
|
+
for (const jsDoc of jsDocs) {
|
|
608
|
+
for (const tag of jsDoc.getTags()) {
|
|
609
|
+
const tagName = tag.getTagName();
|
|
610
|
+
if (tagName === "collection") {
|
|
611
|
+
const comment = tag.getComment();
|
|
612
|
+
if (comment && typeof comment === "string") {
|
|
613
|
+
collection = comment.trim();
|
|
614
|
+
}
|
|
615
|
+
} else if (tagName === "internal") {
|
|
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
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return { collection, internal, keywords };
|
|
629
|
+
}
|
|
630
|
+
function readCollectionFromScopeFile(scopeFilePath, project) {
|
|
631
|
+
let sf = project.getSourceFile(scopeFilePath);
|
|
632
|
+
if (!sf) {
|
|
633
|
+
sf = project.addSourceFileAtPath(scopeFilePath);
|
|
634
|
+
}
|
|
635
|
+
for (const varStmt of sf.getVariableStatements()) {
|
|
636
|
+
if (!varStmt.isExported()) continue;
|
|
637
|
+
for (const varDecl of varStmt.getDeclarations()) {
|
|
638
|
+
if (varDecl.getName() !== "collection") continue;
|
|
639
|
+
const initializer = varDecl.getInitializer();
|
|
640
|
+
if (!initializer) continue;
|
|
641
|
+
if (tsMorph.Node.isStringLiteral(initializer)) {
|
|
642
|
+
return initializer.getLiteralValue();
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return void 0;
|
|
647
|
+
}
|
|
492
648
|
function processSourceFile(sourceFile, rootDir, project) {
|
|
493
649
|
const results = [];
|
|
494
650
|
const filePath = path.relative(rootDir, sourceFile.getFilePath());
|
|
@@ -549,7 +705,10 @@ function processSourceFile(sourceFile, rootDir, project) {
|
|
|
549
705
|
detectedHooks: detectHooks(fn),
|
|
550
706
|
requiredContexts: detectRequiredContexts(fn, sourceFile, project),
|
|
551
707
|
sideEffects: detectSideEffects(fn),
|
|
552
|
-
scopeFile: null
|
|
708
|
+
scopeFile: null,
|
|
709
|
+
// collection, internal, and keywords will be filled in after all components are collected
|
|
710
|
+
internal: false,
|
|
711
|
+
keywords: []
|
|
553
712
|
}
|
|
554
713
|
});
|
|
555
714
|
}
|
|
@@ -587,7 +746,16 @@ function processSourceFile(sourceFile, rootDir, project) {
|
|
|
587
746
|
}
|
|
588
747
|
const propsTypeName = inferPropsTypeName(params);
|
|
589
748
|
const defaults = extractDefaultsFromDestructuring(params);
|
|
590
|
-
|
|
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
|
+
}
|
|
591
759
|
const composes = collectJsxCompositions(bodyNode);
|
|
592
760
|
const startLine = varDecl.getStartLineNumber();
|
|
593
761
|
const endLine = varDecl.getEndLineNumber();
|
|
@@ -614,7 +782,9 @@ function processSourceFile(sourceFile, rootDir, project) {
|
|
|
614
782
|
detectedHooks: detectHooks(bodyNode),
|
|
615
783
|
requiredContexts: detectRequiredContexts(bodyNode, sourceFile, project),
|
|
616
784
|
sideEffects: detectSideEffects(bodyNode),
|
|
617
|
-
scopeFile: null
|
|
785
|
+
scopeFile: null,
|
|
786
|
+
internal: false,
|
|
787
|
+
keywords: []
|
|
618
788
|
}
|
|
619
789
|
});
|
|
620
790
|
}
|
|
@@ -663,19 +833,22 @@ function processSourceFile(sourceFile, rootDir, project) {
|
|
|
663
833
|
detectedHooks: [],
|
|
664
834
|
requiredContexts: [],
|
|
665
835
|
sideEffects: detectSideEffects(cls),
|
|
666
|
-
scopeFile: null
|
|
836
|
+
scopeFile: null,
|
|
837
|
+
internal: false,
|
|
838
|
+
keywords: []
|
|
667
839
|
}
|
|
668
840
|
});
|
|
669
841
|
}
|
|
670
842
|
return results;
|
|
671
843
|
}
|
|
672
844
|
function generateManifest(config) {
|
|
845
|
+
const normalizedRootDir = fs.realpathSync(config.rootDir);
|
|
673
846
|
const {
|
|
674
|
-
rootDir,
|
|
675
847
|
include = ["src/**/*.tsx", "src/**/*.ts"],
|
|
676
848
|
exclude = ["**/node_modules/**", "**/*.test.*", "**/*.spec.*", "**/dist/**", "**/*.d.ts"],
|
|
677
|
-
tsConfigFilePath = path.join(
|
|
849
|
+
tsConfigFilePath = path.join(normalizedRootDir, "tsconfig.json")
|
|
678
850
|
} = config;
|
|
851
|
+
const rootDir = normalizedRootDir;
|
|
679
852
|
const project = new tsMorph.Project({
|
|
680
853
|
tsConfigFilePath,
|
|
681
854
|
skipAddingFilesFromTsConfig: true
|
|
@@ -731,11 +904,78 @@ function generateManifest(config) {
|
|
|
731
904
|
desc.scopeFile = scopeMeta;
|
|
732
905
|
}
|
|
733
906
|
}
|
|
907
|
+
const configCollections = config.collections ?? [];
|
|
908
|
+
const internalPatterns = config.internalPatterns ?? [];
|
|
909
|
+
for (const [compName, desc] of Object.entries(allComponents)) {
|
|
910
|
+
const absFilePath = desc.filePath.startsWith("/") ? desc.filePath : path.join(rootDir, desc.filePath);
|
|
911
|
+
const sf = project.getSourceFile(absFilePath);
|
|
912
|
+
let tsdocCollection;
|
|
913
|
+
let tsdocInternal = false;
|
|
914
|
+
let tsdocKeywords = [];
|
|
915
|
+
if (sf) {
|
|
916
|
+
const fn = sf.getFunction(compName);
|
|
917
|
+
if (fn) {
|
|
918
|
+
const tags = extractTsDocTags(fn);
|
|
919
|
+
tsdocCollection = tags.collection;
|
|
920
|
+
tsdocInternal = tags.internal;
|
|
921
|
+
tsdocKeywords = tags.keywords;
|
|
922
|
+
}
|
|
923
|
+
if (tsdocCollection === void 0 && !tsdocInternal && tsdocKeywords.length === 0) {
|
|
924
|
+
const varDecl = sf.getVariableDeclaration(compName);
|
|
925
|
+
if (varDecl) {
|
|
926
|
+
const varStmt = varDecl.getVariableStatement();
|
|
927
|
+
if (varStmt) {
|
|
928
|
+
const tags = extractTsDocTags(varStmt);
|
|
929
|
+
tsdocCollection = tags.collection;
|
|
930
|
+
tsdocInternal = tags.internal;
|
|
931
|
+
tsdocKeywords = tags.keywords;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
if (tsdocCollection === void 0 && !tsdocInternal && tsdocKeywords.length === 0) {
|
|
936
|
+
const cls = sf.getClass(compName);
|
|
937
|
+
if (cls) {
|
|
938
|
+
const tags = extractTsDocTags(cls);
|
|
939
|
+
tsdocCollection = tags.collection;
|
|
940
|
+
tsdocInternal = tags.internal;
|
|
941
|
+
tsdocKeywords = tags.keywords;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
let scopeFileCollection;
|
|
946
|
+
if (desc.scopeFile) {
|
|
947
|
+
scopeFileCollection = readCollectionFromScopeFile(desc.scopeFile.filePath, project);
|
|
948
|
+
}
|
|
949
|
+
let configCollection;
|
|
950
|
+
for (const colConfig of configCollections) {
|
|
951
|
+
if (colConfig.patterns.some((p) => matchGlob(p, desc.filePath))) {
|
|
952
|
+
configCollection = colConfig.name;
|
|
953
|
+
break;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
let configInternal = false;
|
|
957
|
+
if (internalPatterns.length > 0) {
|
|
958
|
+
configInternal = internalPatterns.some(
|
|
959
|
+
(p) => matchGlob(p, desc.filePath) || matchGlob(p, desc.displayName)
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
const iconPats = config.iconPatterns ?? [];
|
|
963
|
+
const isIcon = iconPats.length > 0 && iconPats.some((p) => matchGlob(p, desc.filePath) || matchGlob(p, desc.displayName));
|
|
964
|
+
const resolvedCollection = tsdocCollection ?? scopeFileCollection ?? configCollection;
|
|
965
|
+
if (resolvedCollection !== void 0) {
|
|
966
|
+
desc.collection = resolvedCollection;
|
|
967
|
+
}
|
|
968
|
+
desc.internal = tsdocInternal || configInternal || isIcon;
|
|
969
|
+
if (tsdocKeywords.length > 0) {
|
|
970
|
+
desc.keywords = tsdocKeywords;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
734
973
|
return {
|
|
735
974
|
version: "0.1",
|
|
736
975
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
737
976
|
components: allComponents,
|
|
738
|
-
tree
|
|
977
|
+
tree,
|
|
978
|
+
collections: configCollections
|
|
739
979
|
};
|
|
740
980
|
}
|
|
741
981
|
var SCOPE_EXTENSIONS = [".scope.tsx", ".scope.ts", ".scope.jsx", ".scope.js"];
|
|
@@ -745,7 +985,103 @@ function detectScopeFile(componentFilePath, rootDir) {
|
|
|
745
985
|
for (const ext of SCOPE_EXTENSIONS) {
|
|
746
986
|
const candidate = `${stem}${ext}`;
|
|
747
987
|
if (fs.existsSync(candidate)) {
|
|
748
|
-
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);
|
|
749
1085
|
}
|
|
750
1086
|
}
|
|
751
1087
|
return null;
|