@rankingcoach/vanguard 1.3.0 → 1.4.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/icons/Icon-tools-active-1.svg +3 -0
- package/dist/icons/Icon-tools-active.svg +3 -0
- package/dist/index-AMPMMidnightParser.js +1 -1
- package/dist/index-AMPMParser.js +1 -1
- package/dist/index-Accordion2.js +1 -1
- package/dist/index-AccordionDetails.js +1 -1
- package/dist/index-AccordionSummary.js +1 -1
- package/dist/index-AppBar2.js +1 -1
- package/dist/index-Autocomplete2.js +1 -1
- package/dist/index-Backdrop.js +1 -1
- package/dist/index-BasePopper.js +1 -1
- package/dist/index-Box.js +1 -1
- package/dist/index-Button2.js +1 -1
- package/dist/index-ButtonBase.js +1 -1
- package/dist/index-CSSTransition.js +1 -1
- package/dist/index-Calendar.js +20 -20
- package/dist/index-CalendarPicker.js +1 -1
- package/dist/index-Chip.js +1 -1
- package/dist/index-ClickAwayListener.js +1 -1
- package/dist/index-ClockPicker.js +1 -1
- package/dist/index-Collapse2.js +1 -1
- package/dist/index-ControlledValuePlugin.js +1 -1
- package/dist/index-CreditCard.js +1 -1
- package/dist/index-DateInput.js +1 -1
- package/dist/index-DateParser.js +1 -1
- package/dist/index-DatePicker2.js +1 -1
- package/dist/index-DateRange2.js +7 -7
- package/dist/index-DateRangePicker2.js +1 -1
- package/dist/index-DayCell.js +7 -7
- package/dist/index-DayOfYearParser.js +1 -1
- package/dist/index-DayParser.js +1 -1
- package/dist/index-DayPeriodParser.js +1 -1
- package/dist/index-DefaultPropsProvider.js +1 -1
- package/dist/index-DefaultPropsProvider2.js +1 -1
- package/dist/index-DefaultValuePlugin.js +1 -1
- package/dist/index-DefinedRange.js +1 -1
- package/dist/index-DesktopDatePicker.js +1 -1
- package/dist/index-Dialog.js +1 -1
- package/dist/index-DialogActions.js +1 -1
- package/dist/index-DialogContent.js +1 -1
- package/dist/index-Drawer2.js +1 -1
- package/dist/index-EraParser.js +1 -1
- package/dist/index-ExtendedYearParser.js +1 -1
- package/dist/index-Fade.js +1 -1
- package/dist/index-FilledInput.js +1 -1
- package/dist/index-FocusTrap.js +1 -1
- package/dist/index-FormControl2.js +1 -1
- package/dist/index-FormHelperText.js +1 -1
- package/dist/index-FormLabel.js +1 -1
- package/dist/index-FractionOfSecondParser.js +1 -1
- package/dist/index-GlobalStyles.js +1 -1
- package/dist/index-GlobalStyles2.js +1 -1
- package/dist/index-GlobalStyles3.js +1 -1
- package/dist/index-Grid.js +1 -1
- package/dist/index-Grow.js +1 -1
- package/dist/index-Hour0To11Parser.js +1 -1
- package/dist/index-Hour0to23Parser.js +1 -1
- package/dist/index-Hour1To24Parser.js +1 -1
- package/dist/index-Hour1to12Parser.js +1 -1
- package/dist/index-HyperlinkPlugin.js +1 -1
- package/dist/index-ISODayParser.js +1 -1
- package/dist/index-ISOTimezoneParser.js +1 -1
- package/dist/index-ISOTimezoneWithZParser.js +1 -1
- package/dist/index-ISOWeekParser.js +1 -1
- package/dist/index-ISOWeekYearParser.js +1 -1
- package/dist/index-Icon-tools-active-1.svg.js +4 -0
- package/dist/index-Icon-tools-active.svg.js +4 -0
- package/dist/index-IconButton2.js +1 -1
- package/dist/index-Input2.js +1 -1
- package/dist/index-InputAdornment.js +1 -1
- package/dist/index-InputBase.js +48 -43
- package/dist/index-InputBase2.js +1 -1
- package/dist/index-InputLabel.js +1 -1
- package/dist/index-InputRangeField.js +1 -1
- package/dist/index-KeywordNode.js +1 -1
- package/dist/index-KeywordPlugin.js +1 -1
- package/dist/index-LinearProgress.js +1 -1
- package/dist/index-List2.js +1 -1
- package/dist/index-ListSubheader.js +1 -1
- package/dist/index-LocalDayParser.js +1 -1
- package/dist/index-LocalWeekParser.js +1 -1
- package/dist/index-LocalWeekYearParser.js +1 -1
- package/dist/index-LocalizationProvider.js +1 -1
- package/dist/index-LoginButton.js +1 -1
- package/dist/index-Menu.js +1 -1
- package/dist/index-MenuItem.js +1 -1
- package/dist/index-MenuList.js +1 -1
- package/dist/index-MinuteParser.js +1 -1
- package/dist/index-MobileDatePicker.js +1 -1
- package/dist/index-Modal2.js +1 -1
- package/dist/index-Month.js +10 -10
- package/dist/index-MonthParser.js +1 -1
- package/dist/index-MonthPicker.js +1 -1
- package/dist/index-NativeSelectInput.js +1 -1
- package/dist/index-NotchedOutline.js +1 -1
- package/dist/index-OnChangeContentPlugin.js +1 -1
- package/dist/index-OnFocusOnBlurPlugin.js +1 -1
- package/dist/index-OutlinedInput.js +1 -1
- package/dist/index-Paper.js +1 -1
- package/dist/index-Parser2.js +314 -255
- package/dist/index-Parser3.js +129 -2
- package/dist/index-PickersDay.js +1 -1
- package/dist/index-Popover2.js +1 -1
- package/dist/index-Popper.js +1 -1
- package/dist/index-Portal.js +1 -1
- package/dist/index-PropTypes.js +1 -1
- package/dist/index-QuarterParser.js +1 -1
- package/dist/index-Ripple.js +1 -1
- package/dist/index-RtlProvider.js +1 -1
- package/dist/index-ScrollbarSize.js +1 -1
- package/dist/index-SecondParser.js +1 -1
- package/dist/index-Select2.js +1 -1
- package/dist/index-SelectInput2.js +1 -1
- package/dist/index-Skeleton2.js +1 -1
- package/dist/index-Slide.js +1 -1
- package/dist/index-Slider2.js +1 -1
- package/dist/index-SliderValueLabel.js +1 -1
- package/dist/index-Snackbar2.js +1 -1
- package/dist/index-SnackbarContent.js +1 -1
- package/dist/index-StandAloneLocalDayParser.js +1 -1
- package/dist/index-StandAloneMonthParser.js +1 -1
- package/dist/index-StandAloneQuarterParser.js +1 -1
- package/dist/index-StyledEngineProvider.js +1 -1
- package/dist/index-StyledSVG2.js +1 -1
- package/dist/index-SvgIcon.js +1 -1
- package/dist/index-Tab2.js +1 -1
- package/dist/index-TabScrollButton.js +1 -1
- package/dist/index-Tabs2.js +1 -1
- package/dist/index-Text.js +18 -18
- package/dist/index-TextField.js +1 -1
- package/dist/index-TextHighlighted.js +23 -19
- package/dist/index-TextareaAutosize.js +1 -1
- package/dist/index-TimestampMillisecondsParser.js +1 -1
- package/dist/index-TimestampSecondsParser.js +1 -1
- package/dist/index-ToggleButton2.js +1 -1
- package/dist/index-ToggleButtonGroup2.js +1 -1
- package/dist/index-Tokenizer.js +411 -334
- package/dist/index-Tokenizer2.js +139 -2
- package/dist/index-Toolbar2.js +1 -1
- package/dist/index-Tooltip.js +1 -1
- package/dist/index-TouchRipple.js +1 -1
- package/dist/index-Transition.js +1 -1
- package/dist/index-TransitionGroup.js +1 -1
- package/dist/index-Typography.js +1 -1
- package/dist/index-YearParser.js +1 -1
- package/dist/index-YearPicker.js +1 -1
- package/dist/index-_virtual12.js +1 -1
- package/dist/index-_virtual15.js +2 -5
- package/dist/index-_virtual16.js +5 -3
- package/dist/index-_virtual17.js +5 -2
- package/dist/index-_virtual18.js +2 -7
- package/dist/index-_virtual19.js +4 -4
- package/dist/index-_virtual21.js +2 -2
- package/dist/index-_virtual22.js +2 -2
- package/dist/index-_virtual23.js +2 -3
- package/dist/index-_virtual24.js +2 -2
- package/dist/index-_virtual25.js +2 -2
- package/dist/index-_virtual26.js +2 -2
- package/dist/index-_virtual27.js +2 -2
- package/dist/index-_virtual28.js +2 -2
- package/dist/index-_virtual30.js +2 -2
- package/dist/index-_virtual31.js +2 -2
- package/dist/index-_virtual32.js +3 -2
- package/dist/index-_virtual34.js +2 -2
- package/dist/index-_virtual35.js +2 -4
- package/dist/index-_virtual36.js +1 -1
- package/dist/index-_virtual37.js +1 -1
- package/dist/index-_virtual38.js +1 -1
- package/dist/index-_virtual39.js +1 -1
- package/dist/index-_virtual40.js +1 -1
- package/dist/index-_virtual41.js +4 -2
- package/dist/index-_virtual42.js +2 -4
- package/dist/index-_virtual43.js +1 -1
- package/dist/index-_virtual44.js +1 -1
- package/dist/index-_virtual45.js +1 -1
- package/dist/index-_virtual46.js +1 -1
- package/dist/index-_virtual47.js +1 -1
- package/dist/index-_virtual48.js +1 -1
- package/dist/index-_virtual49.js +1 -1
- package/dist/index-_virtual50.js +1 -1
- package/dist/index-_virtual51.js +1 -1
- package/dist/index-_virtual52.js +1 -1
- package/dist/index-_virtual53.js +1 -1
- package/dist/index-_virtual54.js +1 -1
- package/dist/index-_virtual55.js +1 -1
- package/dist/index-_virtual56.js +1 -1
- package/dist/index-_virtual57.js +1 -1
- package/dist/index-_virtual58.js +4 -2
- package/dist/index-_virtual60.js +2 -4
- package/dist/index-_virtual61.js +1 -1
- package/dist/index-_virtual62.js +4 -2
- package/dist/index-_virtual63.js +2 -2
- package/dist/index-_virtual66.js +2 -2
- package/dist/index-_virtual67.js +2 -4
- package/dist/index-_virtual68.js +4 -2
- package/dist/index-_virtual74.js +1 -1
- package/dist/index-_virtual76.js +2 -2
- package/dist/index-_virtual77.js +4 -2
- package/dist/index-_virtual78.js +1 -1
- package/dist/index-_virtual79.js +1 -1
- package/dist/index-_virtual80.js +1 -1
- package/dist/index-_virtual81.js +1 -1
- package/dist/index-_virtual82.js +1 -1
- package/dist/index-_virtual83.js +1 -1
- package/dist/index-_virtual84.js +1 -1
- package/dist/index-_virtual85.js +2 -4
- package/dist/index-_virtual86.js +2 -2
- package/dist/index-applyInternationalSeparatorStyle.js +1 -1
- package/dist/index-attributes-to-props.js +1 -1
- package/dist/index-cjs.js +19 -75
- package/dist/index-colorManipulator3.js +2 -2
- package/dist/index-constants.js +38 -8
- package/dist/index-constants2.js +8 -38
- package/dist/index-createExtensionPattern.js +1 -1
- package/dist/index-createStyled2.js +6 -6
- package/dist/index-decode-data-html.js +5 -11
- package/dist/index-decode-data-xml.js +5 -11
- package/dist/index-decode.js +263 -216
- package/dist/index-decode_codepoint.js +43 -53
- package/dist/index-defaultRanges.js +10 -10
- package/dist/index-dist5.js +1 -1
- package/dist/index-elementAcceptingRef.js +1 -1
- package/dist/index-elementTypeAcceptingRef.js +1 -1
- package/dist/index-emotion-cache.browser.esm.js +2 -2
- package/dist/index-escape.js +43 -48
- package/dist/index-esm2.js +108 -129
- package/dist/index-esm3.js +12 -301
- package/dist/index-esm4.js +135 -17
- package/dist/index-esm5.js +303 -0
- package/dist/index-esm6.js +21 -0
- package/dist/index-esm7.js +102 -0
- package/dist/index-exenv.js +1 -1
- package/dist/index-extractCountryCallingCode.js +1 -1
- package/dist/index-extractPhoneContext.js +1 -1
- package/dist/index-foreignNames.js +101 -108
- package/dist/index-helpers3.js +1 -1
- package/dist/index-http.store.js +1 -1
- package/dist/index-isViablePhoneNumber.js +1 -1
- package/dist/index-keycode.js +1 -1
- package/dist/index-lib.js +2 -2
- package/dist/index-lib2.js +424 -111
- package/dist/index-lib3.js +14 -433
- package/dist/index-lib4.js +120 -14
- package/dist/index-lib5.js +10 -69
- package/dist/index-mpd-parser.es.js +1 -1
- package/dist/index-node.js +1 -1
- package/dist/index-node2.js +1 -1
- package/dist/index-parse2.js +1 -1
- package/dist/index-parse3.js +122 -20
- package/dist/index-refType.js +1 -1
- package/dist/index-responsivePropType.js +1 -1
- package/dist/index-sanitize-html.js +91 -48
- package/dist/index-stripIddPrefix.js +1 -1
- package/dist/index-style-to-object.js +1 -1
- package/dist/index-text-animate-words-style.js +12 -12
- package/dist/index-tiny-emitter.js +1 -1
- package/dist/index-use-dynamic-import.js +2 -0
- package/dist/index-useHyperlinkEditor.js +1 -1
- package/dist/index-useLexicalToolbar.js +1 -1
- package/dist/index-useRteAiAssistant-selection.js +5 -5
- package/dist/index-useThemeWithoutDefault3.js +1 -1
- package/dist/index-utilities.js +1 -1
- package/dist/index-utilities2.js +1 -1
- package/dist/index-utils2.js +1 -1
- package/dist/index-utils6.js +7 -7
- package/dist/index.js +428 -426
- package/dist/types/core/RichTextEditor/stories/RichTextEditorStory.story.d.ts +2 -0
- package/dist/types/core/RichTextEditor/stories/RichTextEditorWithXSSAttackStory.story.d.ts +2 -0
- package/dist/types/core/RichTextEditor/stories/_RichTextEditor.default.d.ts +4 -0
- package/dist/types/core/RichTextEditor/stories/bootstrap/richtexteditor.test.slice.d.ts +1 -0
- package/dist/types/core/TextHighlighted/stories/TextHighlightedStory.story.d.ts +2 -0
- package/dist/types/core/TextHighlighted/stories/TextHighlightedStory2.story.d.ts +2 -0
- package/dist/types/core/TextHighlighted/stories/TextHighlightedWithEmphasisStory.story.d.ts +2 -0
- package/dist/types/core/TextHighlighted/stories/TextHighlightedWithXSSAttackStory.story.d.ts +2 -0
- package/dist/types/core/TextHighlighted/stories/_TextHighlighted.default.d.ts +7 -0
- package/dist/types/core/_internal/InputBase/stories/HighlightLengthExceededTest.story.d.ts +2 -0
- package/dist/types/core/_internal/InputBase/stories/HighlightUrlTest.story.d.ts +2 -0
- package/dist/types/core/_internal/InputBase/stories/HighlightWordsTest.story.d.ts +2 -0
- package/dist/types/helpers/sanitize-html.d.ts +18 -3
- package/dist/types/index.d.ts +2 -0
- package/dist/vanguard-asset-analysis.json +1 -1
- package/dist-wordpress/Icon-tools-active-1-B-9tOuX0.mjs +4 -0
- package/dist-wordpress/Icon-tools-active-t9IjG2pg.mjs +4 -0
- package/dist-wordpress/index.js +23653 -22245
- package/package.json +5 -2
- package/scripts/check-meta-coverage.js +117 -0
- package/scripts/generate-exports-props.js +855 -0
- package/dist/index-Parser5.js +0 -131
- package/dist/index-Tokenizer3.js +0 -141
- package/dist/index-_virtual87.js +0 -4
- package/dist/index-_virtual88.js +0 -4
- package/dist/index-_virtual89.js +0 -4
- package/dist/index-_virtual90.js +0 -4
- package/dist/index-_virtual91.js +0 -4
- package/dist/index-at-rule.js +0 -22
- package/dist/index-cjs2.js +0 -23
- package/dist/index-comment.js +0 -16
- package/dist/index-container.js +0 -223
- package/dist/index-css-syntax-error.js +0 -56
- package/dist/index-declaration.js +0 -19
- package/dist/index-decode-data-html2.js +0 -4
- package/dist/index-decode-data-xml2.js +0 -4
- package/dist/index-decode2.js +0 -4
- package/dist/index-decode_codepoint2.js +0 -4
- package/dist/index-document3.js +0 -23
- package/dist/index-encode-html.js +0 -15
- package/dist/index-encode-html2.js +0 -4
- package/dist/index-encode.js +0 -49
- package/dist/index-encode2.js +0 -4
- package/dist/index-escape-string-regexp.js +0 -11
- package/dist/index-escape2.js +0 -4
- package/dist/index-feeds.js +0 -92
- package/dist/index-feeds2.js +0 -4
- package/dist/index-foreignNames2.js +0 -4
- package/dist/index-fromJSON.js +0 -46
- package/dist/index-helpers4.js +0 -54
- package/dist/index-helpers5.js +0 -4
- package/dist/index-input3.js +0 -139
- package/dist/index-is-plain-object.js +0 -17
- package/dist/index-is-plain-object2.js +0 -4
- package/dist/index-lazy-result.js +0 -343
- package/dist/index-legacy.js +0 -75
- package/dist/index-legacy2.js +0 -4
- package/dist/index-lib6.js +0 -13
- package/dist/index-lib7.js +0 -43
- package/dist/index-lib8.js +0 -147
- package/dist/index-lib9.js +0 -90
- package/dist/index-list3.js +0 -25
- package/dist/index-manipulation.js +0 -61
- package/dist/index-manipulation2.js +0 -4
- package/dist/index-map-generator.js +0 -171
- package/dist/index-no-work-result.js +0 -94
- package/dist/index-node4.js +0 -259
- package/dist/index-non-secure.js +0 -20
- package/dist/index-parse-srcset.js +0 -71
- package/dist/index-parse-srcset2.js +0 -4
- package/dist/index-parse4.js +0 -127
- package/dist/index-parser4.js +0 -322
- package/dist/index-picocolors.browser.js +0 -13
- package/dist/index-picocolors.browser2.js +0 -4
- package/dist/index-postcss.js +0 -46
- package/dist/index-previous-map.js +0 -92
- package/dist/index-processor.js +0 -43
- package/dist/index-querying.js +0 -63
- package/dist/index-querying2.js +0 -4
- package/dist/index-result.js +0 -30
- package/dist/index-root.js +0 -38
- package/dist/index-rule.js +0 -24
- package/dist/index-sanitize-html2.js +0 -672
- package/dist/index-stringifier.js +0 -196
- package/dist/index-stringify.js +0 -14
- package/dist/index-stringify2.js +0 -36
- package/dist/index-stringify3.js +0 -4
- package/dist/index-symbols.js +0 -8
- package/dist/index-symbols2.js +0 -4
- package/dist/index-tokenize.js +0 -114
- package/dist/index-traversal.js +0 -48
- package/dist/index-traversal2.js +0 -4
- package/dist/index-warn-once.js +0 -12
- package/dist/index-warning2.js +0 -25
- /package/dist/{index-Parser6.js → index-Parser4.js} +0 -0
|
@@ -0,0 +1,855 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Generate TypeScript type information for all exported components, hooks, and helpers.
|
|
4
|
+
*
|
|
5
|
+
* This script:
|
|
6
|
+
* 1. Parses src/index.ts to identify all value exports (skips types/interfaces)
|
|
7
|
+
* 2. Loads metadata from src/exports-meta/*.json for enrichment
|
|
8
|
+
* 3. Uses TypeScript Compiler API to extract type information
|
|
9
|
+
* 4. Generates JSON files with props, types, and metadata for MCP context
|
|
10
|
+
*
|
|
11
|
+
* Output: src/exports-props/*.json
|
|
12
|
+
*
|
|
13
|
+
* Usage: node scripts/generate-exports-props.js
|
|
14
|
+
*/
|
|
15
|
+
const ts = require('typescript');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
20
|
+
const INDEX = path.join(ROOT, 'src', 'index.ts');
|
|
21
|
+
const META_DIR = path.join(ROOT, 'src', 'exports-meta');
|
|
22
|
+
// output folder moved under `src` so MCP package can import generated files
|
|
23
|
+
const OUT_DIR = path.join(ROOT, 'src', 'exports-props');
|
|
24
|
+
|
|
25
|
+
function ensureOutDir() {
|
|
26
|
+
if (!fs.existsSync(OUT_DIR)) fs.mkdirSync(OUT_DIR, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function log(...args) {
|
|
30
|
+
console.log('[generate-exports-props]', ...args);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parse index.ts to extract all value (non-type) exports.
|
|
35
|
+
* Uses regex-based approach similar to check-meta-coverage.js for consistency.
|
|
36
|
+
*/
|
|
37
|
+
function parseValueExportsFromIndex(indexPath) {
|
|
38
|
+
const content = fs.readFileSync(indexPath, 'utf8');
|
|
39
|
+
const lines = content.split('\n');
|
|
40
|
+
const exports = new Set();
|
|
41
|
+
|
|
42
|
+
// Regex to match "export { A, B, C } from ..." or "export { A } from ..."
|
|
43
|
+
const namedExportRegex = /export\s+\{\s*([^}]+)\s*\}\s+from/g;
|
|
44
|
+
// Regex to match "export const x = ..." or "export function x() ..." or "export class x ..."
|
|
45
|
+
const inlineExportRegex = /export\s+(const|function|class|let|var)\s+([a-zA-Z0-9_$]+)/g;
|
|
46
|
+
|
|
47
|
+
lines.forEach((line) => {
|
|
48
|
+
// Skip type exports
|
|
49
|
+
if (line.trim().startsWith('export type')) return;
|
|
50
|
+
if (line.trim().startsWith('export interface')) return;
|
|
51
|
+
|
|
52
|
+
// Handle named exports: export { A, B } from '...'
|
|
53
|
+
let match;
|
|
54
|
+
while ((match = namedExportRegex.exec(line)) !== null) {
|
|
55
|
+
const items = match[1].split(',').map((i) => i.trim().split(/\s+as\s+/)[0]);
|
|
56
|
+
items.forEach((item) => {
|
|
57
|
+
if (item && item !== 'type') {
|
|
58
|
+
exports.add(item);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
namedExportRegex.lastIndex = 0; // Reset for next line
|
|
63
|
+
|
|
64
|
+
// Handle inline exports: export const X = ...
|
|
65
|
+
while ((match = inlineExportRegex.exec(line)) !== null) {
|
|
66
|
+
exports.add(match[2]);
|
|
67
|
+
}
|
|
68
|
+
inlineExportRegex.lastIndex = 0;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return Array.from(exports);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Load metadata files to classify exports and get additional context.
|
|
76
|
+
*/
|
|
77
|
+
function loadMetadata() {
|
|
78
|
+
const metadata = new Map();
|
|
79
|
+
if (!fs.existsSync(META_DIR)) {
|
|
80
|
+
log('WARNING: Meta directory does not exist:', META_DIR);
|
|
81
|
+
return metadata;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const metaFiles = fs.readdirSync(META_DIR).filter((f) => f.endsWith('.json'));
|
|
85
|
+
log('Loading', metaFiles.length, 'metadata files from', META_DIR);
|
|
86
|
+
|
|
87
|
+
for (const file of metaFiles) {
|
|
88
|
+
const name = path.basename(file, '.json');
|
|
89
|
+
const filePath = path.join(META_DIR, file);
|
|
90
|
+
try {
|
|
91
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
92
|
+
metadata.set(name, data);
|
|
93
|
+
} catch (e) {
|
|
94
|
+
log('WARNING: Failed to parse metadata file', file, ':', e.message);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return metadata;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function createProgram() {
|
|
102
|
+
// Load project tsconfig so we analyze the whole project and can resolve types across files
|
|
103
|
+
try {
|
|
104
|
+
const configPath = ts.findConfigFile(ROOT, ts.sys.fileExists, 'tsconfig.json');
|
|
105
|
+
if (configPath) {
|
|
106
|
+
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
107
|
+
const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configPath));
|
|
108
|
+
const rootNames = parsed.fileNames;
|
|
109
|
+
const options = parsed.options;
|
|
110
|
+
return ts.createProgram(rootNames, options);
|
|
111
|
+
}
|
|
112
|
+
} catch (e) {
|
|
113
|
+
console.warn('Could not load tsconfig, falling back to single-file program', e && e.message);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const options = {
|
|
117
|
+
target: ts.ScriptTarget.ESNext,
|
|
118
|
+
module: ts.ModuleKind.ESNext,
|
|
119
|
+
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
|
120
|
+
jsx: ts.JsxEmit.React,
|
|
121
|
+
allowJs: true,
|
|
122
|
+
skipLibCheck: true,
|
|
123
|
+
};
|
|
124
|
+
return ts.createProgram([INDEX], options);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function resolveModule(specifier, containingFile, options) {
|
|
128
|
+
const resolved = ts.resolveModuleName(specifier, containingFile, options, ts.sys);
|
|
129
|
+
return resolved.resolvedModule && resolved.resolvedModule.resolvedFileName;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function isSimpleConstant(decl) {
|
|
133
|
+
// treat as simple constant if it's a variable declared with const and initializer is literal (string/number/boolean/null)
|
|
134
|
+
if (!decl) return false;
|
|
135
|
+
if (decl.kind === ts.SyntaxKind.VariableDeclaration) {
|
|
136
|
+
const parent = decl.parent && decl.parent.parent; // VariableDeclarationList -> VariableStatement
|
|
137
|
+
const declList = decl.parent;
|
|
138
|
+
if (declList && declList.flags & ts.NodeFlags.Const) {
|
|
139
|
+
const init = decl.initializer;
|
|
140
|
+
if (!init) return false;
|
|
141
|
+
return (
|
|
142
|
+
init.kind === ts.SyntaxKind.StringLiteral ||
|
|
143
|
+
init.kind === ts.SyntaxKind.NumericLiteral ||
|
|
144
|
+
init.kind === ts.SyntaxKind.TrueKeyword ||
|
|
145
|
+
init.kind === ts.SyntaxKind.FalseKeyword ||
|
|
146
|
+
init.kind === ts.SyntaxKind.NullKeyword
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function serializeType(checker, type) {
|
|
154
|
+
try {
|
|
155
|
+
return checker.typeToString(
|
|
156
|
+
type,
|
|
157
|
+
undefined,
|
|
158
|
+
ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseFullyQualifiedType,
|
|
159
|
+
);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
return String(type && type.symbol ? type.symbol.name : type);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function collectReferencedTypes(checker, type, out = {}, seen = new Set()) {
|
|
166
|
+
if (!type || seen.has(type.id)) return out;
|
|
167
|
+
seen.add(type.id);
|
|
168
|
+
|
|
169
|
+
// Helpers
|
|
170
|
+
function isIntrinsic(t) {
|
|
171
|
+
const F = ts.TypeFlags;
|
|
172
|
+
return !!(
|
|
173
|
+
t.flags &
|
|
174
|
+
(F.String |
|
|
175
|
+
F.StringLiteral |
|
|
176
|
+
F.Number |
|
|
177
|
+
F.NumberLiteral |
|
|
178
|
+
F.Boolean |
|
|
179
|
+
F.BooleanLiteral |
|
|
180
|
+
F.ESSymbol |
|
|
181
|
+
F.ESSymbolLike |
|
|
182
|
+
F.Null |
|
|
183
|
+
F.Undefined |
|
|
184
|
+
F.Void |
|
|
185
|
+
F.Any |
|
|
186
|
+
F.Unknown)
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
function isProjectSource(sf) {
|
|
190
|
+
if (!sf) return false;
|
|
191
|
+
if (sf.isDeclarationFile) return false; // skip lib and .d.ts files
|
|
192
|
+
const fn = sf.fileName;
|
|
193
|
+
if (!fn) return false;
|
|
194
|
+
if (fn.indexOf('node_modules') !== -1) return false;
|
|
195
|
+
// prefer files inside project root
|
|
196
|
+
return fn.startsWith(ROOT);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Skip primitives and builtins to avoid huge noise (String/Array prototype methods etc)
|
|
200
|
+
try {
|
|
201
|
+
if (isIntrinsic(type)) return out;
|
|
202
|
+
} catch (e) {}
|
|
203
|
+
|
|
204
|
+
// If this type is a named symbol, capture a minimal snippet + source only when it's from project files
|
|
205
|
+
const typeSymbol = type.symbol || type.aliasSymbol || null;
|
|
206
|
+
if (typeSymbol && typeSymbol.getName && typeSymbol.declarations && typeSymbol.declarations.length) {
|
|
207
|
+
const name = typeSymbol.getName();
|
|
208
|
+
if (!out[name]) {
|
|
209
|
+
try {
|
|
210
|
+
const decl = typeSymbol.declarations[0];
|
|
211
|
+
const sf = decl.getSourceFile && decl.getSourceFile();
|
|
212
|
+
if (isProjectSource(sf)) {
|
|
213
|
+
const src = path.relative(ROOT, sf.fileName);
|
|
214
|
+
// get a short snippet (avoid dumping entire lib files)
|
|
215
|
+
let text = '';
|
|
216
|
+
try {
|
|
217
|
+
text = sf.text.substring(decl.pos, decl.end).trim().replace(/\s+/g, ' ');
|
|
218
|
+
if (text.length > 600) text = text.slice(0, 600) + '...';
|
|
219
|
+
} catch (e) {
|
|
220
|
+
text = name;
|
|
221
|
+
}
|
|
222
|
+
out[name] = { source: src, snippet: text };
|
|
223
|
+
}
|
|
224
|
+
} catch (e) {
|
|
225
|
+
out[typeSymbol.getName()] = { source: 'unknown', snippet: typeSymbol.getName() };
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Recurse into alias/type arguments
|
|
231
|
+
if (type.aliasTypeArguments && type.aliasTypeArguments.length) {
|
|
232
|
+
for (const ta of type.aliasTypeArguments) collectReferencedTypes(checker, ta, out, seen);
|
|
233
|
+
}
|
|
234
|
+
if (type.typeArguments && type.typeArguments.length) {
|
|
235
|
+
for (const ta of type.typeArguments) collectReferencedTypes(checker, ta, out, seen);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// If object-like, iterate properties but avoid recursing into builtins or declaration file types
|
|
239
|
+
const props = type.getProperties ? type.getProperties() : [];
|
|
240
|
+
for (const p of props) {
|
|
241
|
+
try {
|
|
242
|
+
const decl = p.valueDeclaration || (p.declarations && p.declarations[0]);
|
|
243
|
+
const pType = checker.getTypeOfSymbolAtLocation(p, decl || decl);
|
|
244
|
+
// if property's type is intrinsic or from .d.ts skip
|
|
245
|
+
const pDecl =
|
|
246
|
+
(pType && (pType.symbol || pType.aliasSymbol) && pType.symbol.declarations && pType.symbol.declarations[0]) ||
|
|
247
|
+
null;
|
|
248
|
+
const pSF = pDecl && pDecl.getSourceFile && pDecl.getSourceFile();
|
|
249
|
+
if (pSF && !isProjectSource(pSF)) continue;
|
|
250
|
+
if (isIntrinsic(pType)) continue;
|
|
251
|
+
collectReferencedTypes(checker, pType, out, seen);
|
|
252
|
+
} catch (e) {
|
|
253
|
+
/* ignore */
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// signatures
|
|
258
|
+
if (type.getCallSignatures) {
|
|
259
|
+
for (const sig of type.getCallSignatures()) {
|
|
260
|
+
for (const param of sig.getParameters()) {
|
|
261
|
+
try {
|
|
262
|
+
const decl = param.valueDeclaration || (param.declarations && param.declarations[0]);
|
|
263
|
+
const pType = checker.getTypeOfSymbolAtLocation(param, decl || decl);
|
|
264
|
+
if (isIntrinsic(pType)) continue;
|
|
265
|
+
// skip params declared in .d.ts
|
|
266
|
+
const pDecl = (param && param.declarations && param.declarations[0]) || null;
|
|
267
|
+
const pSF = pDecl && pDecl.getSourceFile && pDecl.getSourceFile();
|
|
268
|
+
if (pSF && !isProjectSource(pSF)) continue;
|
|
269
|
+
collectReferencedTypes(checker, pType, out, seen);
|
|
270
|
+
} catch (e) {}
|
|
271
|
+
}
|
|
272
|
+
const ret = sig.getReturnType && sig.getReturnType();
|
|
273
|
+
if (ret && !isIntrinsic(ret)) {
|
|
274
|
+
const retDecl =
|
|
275
|
+
(ret &&
|
|
276
|
+
(ret.symbol || ret.aliasSymbol) &&
|
|
277
|
+
ret.symbol &&
|
|
278
|
+
ret.symbol.declarations &&
|
|
279
|
+
ret.symbol.declarations[0]) ||
|
|
280
|
+
null;
|
|
281
|
+
const rSF = retDecl && retDecl.getSourceFile && retDecl.getSourceFile();
|
|
282
|
+
if (!rSF || isProjectSource(rSF)) collectReferencedTypes(checker, ret, out, seen);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return out;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function findTypeAliasByName(program, checker, typeName, preferredDir) {
|
|
291
|
+
// Prefer same-directory declarations
|
|
292
|
+
const files = program.getSourceFiles();
|
|
293
|
+
let candidate = null;
|
|
294
|
+
for (const sf of files) {
|
|
295
|
+
if (sf.isDeclarationFile) continue;
|
|
296
|
+
if (preferredDir && !sf.fileName.startsWith(preferredDir)) continue;
|
|
297
|
+
for (const stmt of sf.statements) {
|
|
298
|
+
if (
|
|
299
|
+
(ts.isTypeAliasDeclaration(stmt) || ts.isInterfaceDeclaration(stmt)) &&
|
|
300
|
+
stmt.name &&
|
|
301
|
+
stmt.name.text === typeName
|
|
302
|
+
) {
|
|
303
|
+
try {
|
|
304
|
+
if (ts.isTypeAliasDeclaration(stmt) && stmt.type) {
|
|
305
|
+
return checker.getTypeFromTypeNode(stmt.type);
|
|
306
|
+
}
|
|
307
|
+
return checker.getTypeAtLocation(stmt);
|
|
308
|
+
} catch (e) {}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// if not found in preferred dir, remember one as fallback
|
|
312
|
+
for (const stmt of sf.statements) {
|
|
313
|
+
if (
|
|
314
|
+
(ts.isTypeAliasDeclaration(stmt) || ts.isInterfaceDeclaration(stmt)) &&
|
|
315
|
+
stmt.name &&
|
|
316
|
+
stmt.name.text === typeName
|
|
317
|
+
) {
|
|
318
|
+
try {
|
|
319
|
+
if (!candidate) candidate = checker.getTypeAtLocation(stmt);
|
|
320
|
+
} catch (e) {}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return candidate;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function findTypeDeclarationSnippet(program, checker, typeName, preferredDir) {
|
|
328
|
+
const files = program.getSourceFiles();
|
|
329
|
+
// Prefer same-directory declarations
|
|
330
|
+
for (const sf of files) {
|
|
331
|
+
if (sf.isDeclarationFile) continue;
|
|
332
|
+
if (preferredDir && !sf.fileName.startsWith(preferredDir)) continue;
|
|
333
|
+
for (const stmt of sf.statements) {
|
|
334
|
+
if (
|
|
335
|
+
(ts.isTypeAliasDeclaration(stmt) || ts.isInterfaceDeclaration(stmt) || ts.isEnumDeclaration(stmt)) &&
|
|
336
|
+
stmt.name &&
|
|
337
|
+
stmt.name.text === typeName
|
|
338
|
+
) {
|
|
339
|
+
try {
|
|
340
|
+
const src = path.relative(ROOT, sf.fileName);
|
|
341
|
+
let text = stmt.getText().replace(/\s+/g, ' ');
|
|
342
|
+
if (text.length > 600) text = text.slice(0, 600) + '...';
|
|
343
|
+
return { source: src, snippet: text };
|
|
344
|
+
} catch (e) {}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// fallback: loose search across project files
|
|
349
|
+
for (const sf of files) {
|
|
350
|
+
if (sf.isDeclarationFile) continue;
|
|
351
|
+
for (const stmt of sf.statements) {
|
|
352
|
+
if (
|
|
353
|
+
(ts.isTypeAliasDeclaration(stmt) || ts.isInterfaceDeclaration(stmt) || ts.isEnumDeclaration(stmt)) &&
|
|
354
|
+
stmt.name &&
|
|
355
|
+
stmt.name.text === typeName
|
|
356
|
+
) {
|
|
357
|
+
try {
|
|
358
|
+
const src = path.relative(ROOT, sf.fileName);
|
|
359
|
+
let text = stmt.getText().replace(/\s+/g, ' ');
|
|
360
|
+
if (text.length > 600) text = text.slice(0, 600) + '...';
|
|
361
|
+
return { source: src, snippet: text };
|
|
362
|
+
} catch (e) {}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function getPropsTypeForSymbol(checker, symbol, fromPath) {
|
|
370
|
+
if (!symbol) return null;
|
|
371
|
+
|
|
372
|
+
// If this is an alias (re-export), resolve to the original symbol so we can inspect the real declaration
|
|
373
|
+
try {
|
|
374
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
375
|
+
const aliased = checker.getAliasedSymbol(symbol);
|
|
376
|
+
if (aliased) symbol = aliased;
|
|
377
|
+
}
|
|
378
|
+
} catch (e) {
|
|
379
|
+
// ignore
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const decl = symbol.valueDeclaration || (symbol.declarations && symbol.declarations[0]);
|
|
383
|
+
if (!decl) return null;
|
|
384
|
+
|
|
385
|
+
// If this declaration is an export specifier from a barrel file, try to resolve the original module
|
|
386
|
+
if (
|
|
387
|
+
decl.kind === ts.SyntaxKind.ExportSpecifier ||
|
|
388
|
+
(decl.getSourceFile && decl.getSourceFile().fileName && decl.getSourceFile().fileName.endsWith('/index.ts'))
|
|
389
|
+
) {
|
|
390
|
+
try {
|
|
391
|
+
const sf = decl.getSourceFile();
|
|
392
|
+
// find export declarations that export this name and have a moduleSpecifier
|
|
393
|
+
const nameToFind = symbol.getName();
|
|
394
|
+
const exports = sf.statements.filter(
|
|
395
|
+
(s) => ts.isExportDeclaration(s) && s.moduleSpecifier && s.exportClause && ts.isNamedExports(s.exportClause),
|
|
396
|
+
);
|
|
397
|
+
for (const ed of exports) {
|
|
398
|
+
const named = ed.exportClause;
|
|
399
|
+
for (const el of named.elements) {
|
|
400
|
+
const exportedName = el.name && el.name.text;
|
|
401
|
+
const localName = el.propertyName ? el.propertyName.text : exportedName;
|
|
402
|
+
if (exportedName === nameToFind) {
|
|
403
|
+
const spec = ed.moduleSpecifier && ed.moduleSpecifier.text;
|
|
404
|
+
if (!spec) continue;
|
|
405
|
+
const resolved = resolveModule(spec, sf.fileName, program.getCompilerOptions());
|
|
406
|
+
if (!resolved) continue;
|
|
407
|
+
const targetSF = program.getSourceFile(resolved);
|
|
408
|
+
if (!targetSF) continue;
|
|
409
|
+
const moduleSymbol = checker.getSymbolAtLocation(targetSF);
|
|
410
|
+
if (!moduleSymbol) continue;
|
|
411
|
+
const exportsOfModule = checker.getExportsOfModule(moduleSymbol);
|
|
412
|
+
const sym = exportsOfModule.find(
|
|
413
|
+
(s) => s.getName() === (el.propertyName ? el.propertyName.text : exportedName),
|
|
414
|
+
);
|
|
415
|
+
if (sym) {
|
|
416
|
+
// recurse on resolved symbol
|
|
417
|
+
return getPropsTypeForSymbol(checker, sym, resolved);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Fallback: attempt to find implementation file with the same name in this folder (e.g., Text.tsx)
|
|
424
|
+
try {
|
|
425
|
+
const dir = path.dirname(sf.fileName);
|
|
426
|
+
const candidates = [`${nameToFind}.tsx`, `${nameToFind}.ts`, `${nameToFind}.jsx`, `${nameToFind}.js`];
|
|
427
|
+
for (const c of candidates) {
|
|
428
|
+
const p = path.join(dir, c);
|
|
429
|
+
const targetSF2 = program.getSourceFile(p);
|
|
430
|
+
if (!targetSF2) continue;
|
|
431
|
+
const moduleSymbol2 = checker.getSymbolAtLocation(targetSF2);
|
|
432
|
+
if (!moduleSymbol2) continue;
|
|
433
|
+
const exportsOfModule2 = checker.getExportsOfModule(moduleSymbol2);
|
|
434
|
+
const sym2 = exportsOfModule2.find((s) => s.getName() === nameToFind);
|
|
435
|
+
if (sym2) return getPropsTypeForSymbol(checker, sym2, p);
|
|
436
|
+
}
|
|
437
|
+
} catch (e) {
|
|
438
|
+
// ignore
|
|
439
|
+
}
|
|
440
|
+
} catch (e) {
|
|
441
|
+
// ignore resolution errors
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// If the declaration is a variable with an arrow/function initializer, inspect its parameters directly
|
|
446
|
+
if (decl.kind === ts.SyntaxKind.VariableDeclaration) {
|
|
447
|
+
const init = decl.initializer;
|
|
448
|
+
// handle direct function/arrow
|
|
449
|
+
if (init && (init.kind === ts.SyntaxKind.ArrowFunction || init.kind === ts.SyntaxKind.FunctionExpression)) {
|
|
450
|
+
const params = init.parameters || [];
|
|
451
|
+
if (params.length > 0) {
|
|
452
|
+
const firstParam = params[0];
|
|
453
|
+
if (firstParam.type) {
|
|
454
|
+
try {
|
|
455
|
+
return checker.getTypeFromTypeNode(firstParam.type);
|
|
456
|
+
} catch (e) {
|
|
457
|
+
// fall through to other heuristics
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// handle forwardRef/memo and HOC patterns: variable initializer is a CallExpression
|
|
464
|
+
if (init && ts.isCallExpression(init)) {
|
|
465
|
+
const expr = init.expression;
|
|
466
|
+
// common patterns: React.forwardRef(Component), memo(Component)
|
|
467
|
+
if (ts.isIdentifier(expr) || ts.isPropertyAccessExpression(expr)) {
|
|
468
|
+
const arg0 = init.arguments && init.arguments[0];
|
|
469
|
+
if (arg0 && (ts.isFunctionExpression(arg0) || ts.isArrowFunction(arg0))) {
|
|
470
|
+
const params = arg0.parameters || [];
|
|
471
|
+
if (params.length > 0) {
|
|
472
|
+
const firstParam = params[0];
|
|
473
|
+
if (firstParam.type) {
|
|
474
|
+
try {
|
|
475
|
+
return checker.getTypeFromTypeNode(firstParam.type);
|
|
476
|
+
} catch (e) {}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// if arg0 is an identifier, try to resolve its symbol
|
|
482
|
+
if (arg0 && ts.isIdentifier(arg0)) {
|
|
483
|
+
try {
|
|
484
|
+
const s = checker.getSymbolAtLocation(arg0);
|
|
485
|
+
if (s)
|
|
486
|
+
return getPropsTypeForSymbol(
|
|
487
|
+
checker,
|
|
488
|
+
s,
|
|
489
|
+
s.valueDeclaration && s.valueDeclaration.getSourceFile && s.valueDeclaration.getSourceFile().fileName,
|
|
490
|
+
);
|
|
491
|
+
} catch (e) {}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// If it's a function or has call signatures, use the first parameter type
|
|
498
|
+
const valueType = checker.getTypeOfSymbolAtLocation(symbol, decl);
|
|
499
|
+
const callSigs = valueType.getCallSignatures ? valueType.getCallSignatures() : [];
|
|
500
|
+
if (callSigs && callSigs.length) {
|
|
501
|
+
const sig = callSigs[0];
|
|
502
|
+
const params = sig.getParameters();
|
|
503
|
+
if (params.length > 0) {
|
|
504
|
+
try {
|
|
505
|
+
const first = params[0];
|
|
506
|
+
const pt = checker.getTypeOfSymbolAtLocation(
|
|
507
|
+
first,
|
|
508
|
+
first.valueDeclaration || (first.declarations && first.declarations[0]),
|
|
509
|
+
);
|
|
510
|
+
return pt;
|
|
511
|
+
} catch (e) {
|
|
512
|
+
// fallback
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// If it's a class, check constructor
|
|
518
|
+
if (decl.kind === ts.SyntaxKind.ClassDeclaration) {
|
|
519
|
+
const classType = checker.getTypeAtLocation(decl);
|
|
520
|
+
const constructs = classType.getConstructSignatures();
|
|
521
|
+
if (constructs && constructs.length) {
|
|
522
|
+
const sig = constructs[0];
|
|
523
|
+
const params = sig.getParameters();
|
|
524
|
+
if (params.length > 0) {
|
|
525
|
+
try {
|
|
526
|
+
const pt = checker.getTypeOfSymbolAtLocation(
|
|
527
|
+
params[0],
|
|
528
|
+
params[0].valueDeclaration || (params[0].declarations && params[0].declarations[0]),
|
|
529
|
+
);
|
|
530
|
+
return pt;
|
|
531
|
+
} catch (e) {}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Attempt to use alias type arguments (React.FC<P>)
|
|
537
|
+
if (valueType.aliasTypeArguments && valueType.aliasTypeArguments.length) {
|
|
538
|
+
return valueType.aliasTypeArguments[0];
|
|
539
|
+
}
|
|
540
|
+
if (valueType.typeArguments && valueType.typeArguments.length) {
|
|
541
|
+
return valueType.typeArguments[0];
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// if the valueType itself is object with a single property named 'props', use that
|
|
545
|
+
const propsProp = valueType.getProperty && valueType.getProperty('props');
|
|
546
|
+
if (propsProp) {
|
|
547
|
+
try {
|
|
548
|
+
return checker.getTypeOfSymbolAtLocation(
|
|
549
|
+
propsProp,
|
|
550
|
+
propsProp.valueDeclaration || (propsProp.declarations && propsProp.declarations[0]),
|
|
551
|
+
);
|
|
552
|
+
} catch (e) {}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// As a last resort, try to find a type alias/interface named `${Name}Props` or `Props` in workspace (prefer same dir)
|
|
556
|
+
try {
|
|
557
|
+
const name = symbol.getName();
|
|
558
|
+
const dirPref = decl && decl.getSourceFile && path.dirname(decl.getSourceFile().fileName);
|
|
559
|
+
const byName = findTypeAliasByName(program, checker, `${name}Props`, dirPref);
|
|
560
|
+
if (byName) return byName;
|
|
561
|
+
// generic 'Props' in same dir
|
|
562
|
+
const byProps = findTypeAliasByName(program, checker, 'Props', dirPref);
|
|
563
|
+
if (byProps) return byProps;
|
|
564
|
+
} catch (e) {}
|
|
565
|
+
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function main() {
|
|
570
|
+
log('Starting analysis of', INDEX);
|
|
571
|
+
|
|
572
|
+
// Step 1: Parse index.ts to get all value exports
|
|
573
|
+
const allExports = parseValueExportsFromIndex(INDEX);
|
|
574
|
+
log('Found', allExports.length, 'value exports in index.ts');
|
|
575
|
+
|
|
576
|
+
// Step 2: Load metadata to enrich context
|
|
577
|
+
const metadata = loadMetadata();
|
|
578
|
+
log('Loaded metadata for', metadata.size, 'items');
|
|
579
|
+
|
|
580
|
+
// Step 3: Create TypeScript program for type analysis
|
|
581
|
+
const program = createProgram();
|
|
582
|
+
const checker = program.getTypeChecker();
|
|
583
|
+
const sf = program.getSourceFile(INDEX);
|
|
584
|
+
if (!sf) {
|
|
585
|
+
console.error('Could not load', INDEX);
|
|
586
|
+
process.exit(1);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
ensureOutDir();
|
|
590
|
+
|
|
591
|
+
// Step 4: Build a map of export name -> symbol for type extraction
|
|
592
|
+
const symbolMap = new Map();
|
|
593
|
+
const moduleSymbol = checker.getSymbolAtLocation(sf);
|
|
594
|
+
if (moduleSymbol) {
|
|
595
|
+
const exports = checker.getExportsOfModule(moduleSymbol);
|
|
596
|
+
for (const sym of exports) {
|
|
597
|
+
symbolMap.set(sym.getName(), sym);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
log('Processing', allExports.length, 'exports...');
|
|
602
|
+
|
|
603
|
+
let processed = 0;
|
|
604
|
+
let skipped = 0;
|
|
605
|
+
|
|
606
|
+
for (const name of allExports) {
|
|
607
|
+
const symbol = symbolMap.get(name);
|
|
608
|
+
if (!symbol) {
|
|
609
|
+
log('WARNING: Could not find symbol for export:', name);
|
|
610
|
+
skipped++;
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Get the original declaration location
|
|
615
|
+
let from = INDEX;
|
|
616
|
+
try {
|
|
617
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
618
|
+
const aliased = checker.getAliasedSymbol(symbol);
|
|
619
|
+
if (aliased && aliased.declarations && aliased.declarations[0]) {
|
|
620
|
+
const decl = aliased.declarations[0];
|
|
621
|
+
const declSf = decl.getSourceFile && decl.getSourceFile();
|
|
622
|
+
if (declSf) from = declSf.fileName;
|
|
623
|
+
}
|
|
624
|
+
} else if (symbol.declarations && symbol.declarations[0]) {
|
|
625
|
+
const decl = symbol.declarations[0];
|
|
626
|
+
const declSf = decl.getSourceFile && decl.getSourceFile();
|
|
627
|
+
if (declSf) from = declSf.fileName;
|
|
628
|
+
}
|
|
629
|
+
} catch (e) {
|
|
630
|
+
// Keep default 'from' value
|
|
631
|
+
}
|
|
632
|
+
try {
|
|
633
|
+
// Skip type-only symbols (type/interface/enum)
|
|
634
|
+
const decl = symbol.declarations && symbol.declarations[0];
|
|
635
|
+
if (!decl) {
|
|
636
|
+
skipped++;
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
if (
|
|
640
|
+
decl.kind === ts.SyntaxKind.TypeAliasDeclaration ||
|
|
641
|
+
decl.kind === ts.SyntaxKind.InterfaceDeclaration ||
|
|
642
|
+
decl.kind === ts.SyntaxKind.EnumDeclaration
|
|
643
|
+
) {
|
|
644
|
+
skipped++;
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Skip simple constants
|
|
649
|
+
if (isSimpleConstant(decl)) {
|
|
650
|
+
skipped++;
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Determine kind
|
|
655
|
+
let kind = 'value';
|
|
656
|
+
if (decl.kind === ts.SyntaxKind.FunctionDeclaration) kind = 'function';
|
|
657
|
+
else if (decl.kind === ts.SyntaxKind.ClassDeclaration) kind = 'class';
|
|
658
|
+
else if (decl.kind === ts.SyntaxKind.VariableDeclaration) kind = 'variable';
|
|
659
|
+
|
|
660
|
+
let propsType = getPropsTypeForSymbol(checker, symbol, from);
|
|
661
|
+
|
|
662
|
+
// Special-case: directly read `Props` from `src/core/Text/Text.types.tsx` for the `Text` component
|
|
663
|
+
try {
|
|
664
|
+
if (name === 'Text' && (!propsType || serializeType(checker, propsType) === 'any')) {
|
|
665
|
+
const candidates = [
|
|
666
|
+
path.join(ROOT, 'src', 'core', 'Text', 'Text.types.tsx'),
|
|
667
|
+
path.join(ROOT, 'src', 'core', 'Text', 'Text.types.ts'),
|
|
668
|
+
path.join(ROOT, 'src', 'core', 'Text', 'Text.types.jsx'),
|
|
669
|
+
path.join(ROOT, 'src', 'core', 'Text', 'Text.types.js'),
|
|
670
|
+
];
|
|
671
|
+
for (const p of candidates) {
|
|
672
|
+
const sfTypes = program.getSourceFile(p);
|
|
673
|
+
if (!sfTypes) continue;
|
|
674
|
+
for (const stmt of sfTypes.statements) {
|
|
675
|
+
if (ts.isTypeAliasDeclaration(stmt) && stmt.name && stmt.name.text === 'Props') {
|
|
676
|
+
try {
|
|
677
|
+
const t = checker.getTypeFromTypeNode(stmt.type);
|
|
678
|
+
if (t) {
|
|
679
|
+
propsType = t;
|
|
680
|
+
break;
|
|
681
|
+
}
|
|
682
|
+
} catch {
|
|
683
|
+
// Ignore errors
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
if (propsType) break;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
} catch {
|
|
691
|
+
// Ignore Text special-case errors
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// If we couldn't infer props or it resolved to `any`, try to find an exported props type in the same module
|
|
695
|
+
try {
|
|
696
|
+
const serialized = propsType ? serializeType(checker, propsType) : null;
|
|
697
|
+
if ((!propsType || serialized === 'any' || serialized === 'unknown') && from) {
|
|
698
|
+
const targetSF = program.getSourceFile(from);
|
|
699
|
+
if (targetSF) {
|
|
700
|
+
const targetModuleSymbol = checker.getSymbolAtLocation(targetSF);
|
|
701
|
+
if (targetModuleSymbol) {
|
|
702
|
+
const exportsOfModule = checker.getExportsOfModule(targetModuleSymbol);
|
|
703
|
+
const candidateNames = [`${name}Props`, 'Props', `${name}Props`];
|
|
704
|
+
for (const cn of candidateNames) {
|
|
705
|
+
const tsym = exportsOfModule.find((s) => s.getName() === cn);
|
|
706
|
+
if (tsym) {
|
|
707
|
+
try {
|
|
708
|
+
let ttype = null;
|
|
709
|
+
try {
|
|
710
|
+
// resolve re-exports/aliases
|
|
711
|
+
if (tsym.flags & ts.SymbolFlags.Alias) {
|
|
712
|
+
try {
|
|
713
|
+
const aliased = checker.getAliasedSymbol(tsym);
|
|
714
|
+
if (aliased) tsym = aliased;
|
|
715
|
+
} catch (e) {}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
const decl0 = tsym.declarations && tsym.declarations[0];
|
|
719
|
+
// If it's a type alias with an explicit type node, use that to get a concrete type
|
|
720
|
+
if (
|
|
721
|
+
decl0 &&
|
|
722
|
+
(decl0.kind === ts.SyntaxKind.TypeAliasDeclaration ||
|
|
723
|
+
decl0.kind === ts.SyntaxKind.InterfaceDeclaration)
|
|
724
|
+
) {
|
|
725
|
+
try {
|
|
726
|
+
if (decl0.kind === ts.SyntaxKind.TypeAliasDeclaration && decl0.type) {
|
|
727
|
+
ttype = checker.getTypeFromTypeNode(decl0.type);
|
|
728
|
+
} else {
|
|
729
|
+
ttype = checker.getTypeAtLocation(decl0);
|
|
730
|
+
}
|
|
731
|
+
} catch (e) {
|
|
732
|
+
ttype = null;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// fallback to getDeclaredTypeOfSymbol or getTypeOfSymbolAtLocation
|
|
737
|
+
if (!ttype) {
|
|
738
|
+
try {
|
|
739
|
+
if (tsym.flags & ts.SymbolFlags.TypeAlias) {
|
|
740
|
+
ttype = checker.getDeclaredTypeOfSymbol(tsym);
|
|
741
|
+
} else {
|
|
742
|
+
ttype = checker.getTypeOfSymbolAtLocation(tsym, tsym.valueDeclaration || decl0);
|
|
743
|
+
}
|
|
744
|
+
} catch (e) {
|
|
745
|
+
ttype = null;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
} catch {
|
|
749
|
+
ttype = null;
|
|
750
|
+
}
|
|
751
|
+
if (ttype) {
|
|
752
|
+
propsType = ttype;
|
|
753
|
+
break;
|
|
754
|
+
}
|
|
755
|
+
} catch {
|
|
756
|
+
// Ignore type resolution errors
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
} catch (e) {}
|
|
764
|
+
|
|
765
|
+
const props = propsType ? serializeType(checker, propsType) : null;
|
|
766
|
+
|
|
767
|
+
// Build expanded props as a map of propName -> { type: string, optional: boolean }
|
|
768
|
+
let expandedProps = null;
|
|
769
|
+
// collect type names referenced via import("...") so we can ensure they appear in referencedTypes
|
|
770
|
+
const importedTypeNames = new Set();
|
|
771
|
+
try {
|
|
772
|
+
if (propsType) {
|
|
773
|
+
const propsObj = {};
|
|
774
|
+
const propsSyms = propsType.getProperties ? propsType.getProperties() : [];
|
|
775
|
+
const importRegex = /import\(["'][^"']+["']\)\.([A-Za-z0-9_$]+)/g;
|
|
776
|
+
for (const ps of propsSyms) {
|
|
777
|
+
try {
|
|
778
|
+
const decl0 = ps.valueDeclaration || (ps.declarations && ps.declarations[0]);
|
|
779
|
+
const ptype = checker.getTypeOfSymbolAtLocation(ps, decl0 || decl);
|
|
780
|
+
let ptypeStr = serializeType(checker, ptype);
|
|
781
|
+
// detect and collect imported type names (import("...").Name)
|
|
782
|
+
let m;
|
|
783
|
+
while ((m = importRegex.exec(ptypeStr))) {
|
|
784
|
+
importedTypeNames.add(m[1]);
|
|
785
|
+
}
|
|
786
|
+
// shorten import("...").Name -> Name for readability
|
|
787
|
+
const ptypeStrShort = ptypeStr.replace(importRegex, '$1');
|
|
788
|
+
const optional = decl0 && !!decl0.questionToken;
|
|
789
|
+
propsObj[ps.getName()] = { type: ptypeStrShort, optional };
|
|
790
|
+
} catch (e) {
|
|
791
|
+
propsObj[ps.getName()] = { type: 'unknown', optional: false };
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
expandedProps = propsObj;
|
|
795
|
+
}
|
|
796
|
+
} catch (e) {
|
|
797
|
+
expandedProps = null;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const referenced = propsType ? collectReferencedTypes(checker, propsType) : {};
|
|
801
|
+
|
|
802
|
+
// Ensure any types referenced via import("...").Name in expandedProps are present in referencedTypes
|
|
803
|
+
try {
|
|
804
|
+
const dirPref = decl && decl.getSourceFile && decl.getSourceFile().fileName;
|
|
805
|
+
for (const tn of importedTypeNames) {
|
|
806
|
+
if (!referenced[tn]) {
|
|
807
|
+
const snippet = findTypeDeclarationSnippet(program, checker, tn, dirPref);
|
|
808
|
+
if (snippet) referenced[tn] = snippet;
|
|
809
|
+
else referenced[tn] = { source: 'unknown', snippet: tn };
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
} catch (e) {}
|
|
813
|
+
|
|
814
|
+
// Get metadata if available
|
|
815
|
+
const meta = metadata.get(name);
|
|
816
|
+
|
|
817
|
+
// Build output with metadata enrichment
|
|
818
|
+
const out = {
|
|
819
|
+
name,
|
|
820
|
+
from: path.relative(ROOT, from),
|
|
821
|
+
kind,
|
|
822
|
+
props: props,
|
|
823
|
+
referencedTypes: referenced,
|
|
824
|
+
expandedProps: expandedProps,
|
|
825
|
+
// Include metadata for MCP context
|
|
826
|
+
...(meta && {
|
|
827
|
+
metadata: {
|
|
828
|
+
kind: meta.kind,
|
|
829
|
+
category: meta.category,
|
|
830
|
+
summary: meta.summary,
|
|
831
|
+
description: meta.description,
|
|
832
|
+
tags: meta.tags,
|
|
833
|
+
keywords: meta.keywords,
|
|
834
|
+
relatedComponents: meta.relatedComponents,
|
|
835
|
+
},
|
|
836
|
+
}),
|
|
837
|
+
};
|
|
838
|
+
|
|
839
|
+
fs.writeFileSync(path.join(OUT_DIR, `${name}.json`), JSON.stringify(out, null, 2), 'utf8');
|
|
840
|
+
processed++;
|
|
841
|
+
} catch (error) {
|
|
842
|
+
console.error('Error processing', name, ':', error.message);
|
|
843
|
+
skipped++;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
log('✅ Processing complete!');
|
|
848
|
+
log(' - Processed:', processed);
|
|
849
|
+
log(' - Skipped:', skipped);
|
|
850
|
+
log(' - Output directory:', OUT_DIR);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
if (require.main === module) main();
|
|
854
|
+
|
|
855
|
+
module.exports = { main };
|