feat(custom-widgets): complete JSX v2
This commit is contained in:
263 files changed
+65503
-17816
No files matched your search
@@ -0,0 +1,20 @@
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
import { customJsxComponentRegistry } from "../src/core/component-registry";
|
||||
|
||||
const output = customJsxComponentRegistry.map(
|
||||
({ name, package: packageName, category, safety, reason, documentationUrl }) => ({
|
||||
name,
|
||||
package: packageName,
|
||||
category,
|
||||
safety,
|
||||
reason,
|
||||
documentationUrl,
|
||||
}),
|
||||
);
|
||||
|
||||
await writeFile(
|
||||
resolve(import.meta.dirname, "../../../apps/docs/src/generated/custom-jsx-components.json"),
|
||||
`${JSON.stringify(output, null, 2)}\n`,
|
||||
);
|
||||
@@ -0,0 +1,72 @@
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
import * as Charts from "@mantine/charts";
|
||||
import * as Core from "@mantine/core";
|
||||
import * as Dates from "@mantine/dates";
|
||||
import ts from "typescript";
|
||||
|
||||
import { discoveredMantineComponents } from "../src/core/component-discovery";
|
||||
import { deniedCustomJsxComponentNames } from "../src/core/component-registry-denied";
|
||||
import { isBlockedCustomJsxProp } from "../src/jsx/policy";
|
||||
|
||||
void [Core, Dates, Charts];
|
||||
|
||||
const packageRoot = resolve(import.meta.dirname, "..");
|
||||
const configPath = resolve(packageRoot, "tsconfig.json");
|
||||
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
||||
if (configFile.error) throw new Error(ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n"));
|
||||
const config = ts.parseJsonConfigFileContent(configFile.config, ts.sys, packageRoot);
|
||||
const program = ts.createProgram({ rootNames: [...config.fileNames, import.meta.filename], options: config.options });
|
||||
const checker = program.getTypeChecker();
|
||||
const source = program.getSourceFile(import.meta.filename);
|
||||
if (!source) throw new Error("Unable to inspect the component metadata generator");
|
||||
|
||||
const moduleSymbols = new Map<string, ts.Symbol>();
|
||||
for (const declaration of source.statements) {
|
||||
if (!ts.isImportDeclaration(declaration) || !ts.isStringLiteral(declaration.moduleSpecifier)) continue;
|
||||
const moduleName = declaration.moduleSpecifier.text;
|
||||
if (!moduleName.startsWith("@mantine/")) continue;
|
||||
const symbol = checker.getSymbolAtLocation(declaration.moduleSpecifier);
|
||||
if (symbol) moduleSymbols.set(moduleName, symbol);
|
||||
}
|
||||
|
||||
function isCallableType(type: ts.Type): boolean {
|
||||
if (type.getCallSignatures().length > 0) return true;
|
||||
return type.isUnionOrIntersection() && type.types.some(isCallableType);
|
||||
}
|
||||
const metadata: Record<string, string[]> = {};
|
||||
for (const component of discoveredMantineComponents) {
|
||||
if (deniedCustomJsxComponentNames.has(component.name)) continue;
|
||||
const moduleSymbol = moduleSymbols.get(component.package);
|
||||
const rootName = component.name.split(".")[0];
|
||||
let symbol =
|
||||
moduleSymbol && checker.getExportsOfModule(moduleSymbol).find((candidate) => candidate.name === rootName);
|
||||
let location = symbol?.valueDeclaration ?? symbol?.declarations?.[0] ?? source;
|
||||
let type = symbol && checker.getTypeOfSymbolAtLocation(symbol, location);
|
||||
for (const segment of component.name.split(".").slice(1)) {
|
||||
symbol = type?.getProperty(segment);
|
||||
if (!symbol) break;
|
||||
location = symbol.valueDeclaration ?? symbol.declarations?.[0] ?? location;
|
||||
type = checker.getTypeOfSymbolAtLocation(symbol, location);
|
||||
}
|
||||
const signature = type?.getCallSignatures()[0] ?? type?.getConstructSignatures()[0];
|
||||
const parameter = signature?.parameters[0];
|
||||
const props = parameter
|
||||
? checker.getPropertiesOfType(checker.getTypeOfSymbolAtLocation(parameter, parameter.valueDeclaration ?? location))
|
||||
: [];
|
||||
metadata[component.name] = props
|
||||
.filter((prop) => {
|
||||
const declaration = prop.valueDeclaration ?? prop.declarations?.[0] ?? location;
|
||||
return (
|
||||
!isBlockedCustomJsxProp(prop.name) && !isCallableType(checker.getTypeOfSymbolAtLocation(prop, declaration))
|
||||
);
|
||||
})
|
||||
.map((prop) => prop.name)
|
||||
.toSorted();
|
||||
}
|
||||
|
||||
await writeFile(
|
||||
resolve(packageRoot, "src/core/component-props.generated.json"),
|
||||
`${JSON.stringify(metadata, null, 2)}\n`,
|
||||
);
|
||||
Reference in new issue
Block a user