Files
jhonny-editor/bm/premiere-pro-mcp-main/scripts/generate-uxp-js-api-inventory.mjs
T
João Henrique b541f502ba feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto
- Configurado MCP server para Premiere Pro
- Adicionado documentação e skills
- Configurado Gitignore para o projeto
2026-09-08 09:59:31 -04:00

169 lines
8.0 KiB
JavaScript
Executable File

import { createHash } from "node:crypto";
import { readFile, writeFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import ts from "typescript";
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const packagePath = resolve(root, "node_modules/@adobe/cc-ext-uxp-types/package.json");
const declarationsPath = process.env.UXP_JS_DECLARATIONS_PATH
? resolve(process.env.UXP_JS_DECLARATIONS_PATH)
: resolve(root, "node_modules/@adobe/cc-ext-uxp-types/uxp/index.d.ts");
const coveragePath = resolve(root, "src/resources/uxp-js-coverage.json");
const outputPath = resolve(root, "src/resources/uxp-js-api-inventory.json");
const check = process.argv.includes("--check");
const validateOnly = process.argv.includes("--validate-only");
const [packageText, declarationsText, coverageText] = await Promise.all([
readFile(packagePath, "utf8"),
readFile(declarationsPath, "utf8"),
readFile(coveragePath, "utf8"),
]);
const packageMetadata = JSON.parse(packageText);
const coverage = JSON.parse(coverageText);
const mappedSymbols = new Set(coverage.entries.flatMap((entry) => entry.uxpApi));
const source = ts.createSourceFile(declarationsPath, declarationsText, ts.ScriptTarget.Latest, true);
if (source.parseDiagnostics.length > 0) {
const details = source.parseDiagnostics
.map((diagnostic) => ts.flattenDiagnosticMessageText(diagnostic.messageText, " "))
.join("; ");
throw new Error(`TypeScript declaration parse failed: ${details}`);
}
const normalizedDeclarations = declarationsText.replaceAll("\r\n", "\n");
const declarationsSha256 = createHash("sha256").update(normalizedDeclarations).digest("hex");
const symbols = [];
const compareText = (left, right) => left < right ? -1 : left > right ? 1 : 0;
const cleanName = (node) => node.getText(source).replaceAll('"', "").replaceAll("'", "");
const joinName = (owner, name) => owner ? `${owner}.${name}` : name;
function add(symbol, kind) {
symbols.push({ symbol, kind });
}
function memberName(member) {
if (ts.isConstructorDeclaration(member) || ts.isConstructSignatureDeclaration(member)) return "[[construct]]";
if (ts.isCallSignatureDeclaration(member)) return "[[call]]";
if (ts.isIndexSignatureDeclaration(member)) return "[[index]]";
if (!member.name) throw new Error(`Unsupported anonymous UXP member: ${ts.SyntaxKind[member.kind]}`);
return cleanName(member.name);
}
function memberKind(member) {
if (ts.isConstructorDeclaration(member) || ts.isConstructSignatureDeclaration(member)) return "constructor";
if (ts.isMethodDeclaration(member) || ts.isMethodSignature(member)) return "method";
if (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) return "property";
if (ts.isGetAccessorDeclaration(member)) return "getter";
if (ts.isSetAccessorDeclaration(member)) return "setter";
if (ts.isCallSignatureDeclaration(member)) return "call";
if (ts.isIndexSignatureDeclaration(member)) return "index";
throw new Error(`Unsupported UXP type member: ${ts.SyntaxKind[member.kind]}`);
}
function collectMembers(owner, members) {
for (const member of members) add(joinName(owner, memberName(member)), memberKind(member));
}
function collectTypeNode(owner, node) {
if (ts.isTypeLiteralNode(node)) {
collectMembers(owner, node.members);
} else if (ts.isIntersectionTypeNode(node) || ts.isUnionTypeNode(node)) {
for (const type of node.types) collectTypeNode(owner, type);
} else if (ts.isParenthesizedTypeNode(node)) {
collectTypeNode(owner, node.type);
}
}
function collectStatements(statements, owner = "globalThis") {
for (const statement of statements) {
if (ts.isModuleDeclaration(statement)) {
const moduleOwner = joinName(owner === "globalThis" ? "" : owner, cleanName(statement.name));
add(moduleOwner, "module");
collectModuleBody(statement.body, moduleOwner);
} else if (ts.isClassDeclaration(statement) || ts.isInterfaceDeclaration(statement)) {
if (!statement.name) throw new Error(`Anonymous UXP declaration: ${ts.SyntaxKind[statement.kind]}`);
const symbol = joinName(owner, statement.name.text);
add(symbol, ts.isClassDeclaration(statement) ? "class" : "interface");
collectMembers(symbol, statement.members);
} else if (ts.isTypeAliasDeclaration(statement)) {
const symbol = joinName(owner, statement.name.text);
add(symbol, "type");
collectTypeNode(symbol, statement.type);
} else if (ts.isEnumDeclaration(statement)) {
const symbol = joinName(owner, statement.name.text);
add(symbol, "enum");
for (const member of statement.members) add(joinName(symbol, cleanName(member.name)), "enumMember");
} else if (ts.isFunctionDeclaration(statement)) {
if (!statement.name) throw new Error("Anonymous UXP function declaration");
add(joinName(owner, statement.name.text), "function");
} else if (ts.isVariableStatement(statement)) {
for (const declaration of statement.declarationList.declarations) {
if (!ts.isIdentifier(declaration.name)) throw new Error("Unsupported destructured UXP variable declaration");
add(joinName(owner, declaration.name.text), "variable");
}
} else if (ts.isExportAssignment(statement) || ts.isExportDeclaration(statement) || ts.isImportDeclaration(statement)) {
// Module wiring does not add a callable or inspectable API symbol.
} else {
throw new Error(`Unsupported top-level UXP declaration: ${ts.SyntaxKind[statement.kind]}`);
}
}
}
function collectModuleBody(body, owner) {
if (!body) throw new Error(`UXP module ${owner} has no body`);
if (ts.isModuleDeclaration(body)) {
const nestedOwner = joinName(owner, cleanName(body.name));
add(nestedOwner, "module");
collectModuleBody(body.body, nestedOwner);
} else if (ts.isModuleBlock(body)) {
collectStatements(body.statements, owner);
} else {
throw new Error(`Unsupported UXP module body: ${ts.SyntaxKind[body.kind]}`);
}
}
collectStatements(source.statements);
const uniqueSymbols = [...new Map(symbols.map((entry) => [entry.symbol, entry])).values()]
.sort((left, right) => compareText(left.symbol, right.symbol));
const declaredSymbols = new Set(uniqueSymbols.map((entry) => entry.symbol));
const entries = uniqueSymbols.map((entry) => ({
...entry,
coverage: mappedSymbols.has(entry.symbol) ? "mapped" : "unmapped",
}));
const mapped = entries.filter((entry) => entry.coverage === "mapped").length;
const manifestOnly = [...mappedSymbols].filter((symbol) => !declaredSymbols.has(symbol)).sort(compareText);
const inventory = {
schemaVersion: 1,
source: {
package: "@adobe/cc-ext-uxp-types",
version: packageMetadata.version,
declarations: "node_modules/@adobe/cc-ext-uxp-types/uxp/index.d.ts",
declarationsSha256,
coverageManifest: "src/resources/uxp-js-coverage.json",
},
semantics: {
mapped: "The exact declaration symbol is referenced by panel coverage; this alone is not licensed-host verification.",
unmapped: "No panel coverage entry references the exact declaration symbol; this is a review queue, not a requirement for a standalone MCP tool.",
},
stats: { total: entries.length, mapped, unmapped: entries.length - mapped, manifestOnly: manifestOnly.length },
manifestOnly,
entries,
};
const rendered = `${JSON.stringify(inventory, null, 2)}\n`;
if (validateOnly) {
console.log(`Validated ${entries.length} UXP JavaScript API symbols from ${packageMetadata.version}.`);
} else if (check) {
let current = "";
try { current = await readFile(outputPath, "utf8"); } catch {}
if (current.replaceAll("\r\n", "\n") !== rendered) {
console.error("UXP JavaScript API inventory is stale. Run npm run uxp:js-api-inventory.");
process.exitCode = 1;
} else {
console.log(`UXP JavaScript API inventory is current: ${entries.length} symbols from ${packageMetadata.version}.`);
}
} else {
await writeFile(outputPath, rendered);
console.log(`Wrote ${entries.length} UXP JavaScript API symbols (${mapped} mapped, ${entries.length - mapped} unmapped).`);
}