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
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { createHash } from "node:crypto";
|
||||
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/premierepro/package.json");
|
||||
const declarationsPath = process.env.PREMIERE_API_DECLARATIONS_PATH
|
||||
? resolve(process.env.PREMIERE_API_DECLARATIONS_PATH)
|
||||
: resolve(root, "node_modules/@adobe/premierepro/src/premierepro.d.ts");
|
||||
const coveragePath = resolve(root, "src/resources/adobe-uxp-coverage.json");
|
||||
const outputPath = resolve(root, "src/resources/adobe-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 coveredApis = new Set(coverage.entries.flatMap((entry) => entry.adobeApi));
|
||||
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 compareText = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
||||
const normalizedDeclarations = declarationsText.replaceAll("\r\n", "\n");
|
||||
const declarationsSha256 = createHash("sha256").update(normalizedDeclarations).digest("hex");
|
||||
const canonicalOwners = new Map();
|
||||
const rootDeclaration = source.statements.find((statement) => (
|
||||
ts.isTypeAliasDeclaration(statement) && statement.name.text === "premierepro"
|
||||
));
|
||||
if (!rootDeclaration || !ts.isTypeLiteralNode(rootDeclaration.type)) {
|
||||
throw new Error("Adobe declarations must expose a premierepro root type literal.");
|
||||
}
|
||||
for (const member of rootDeclaration.type.members) {
|
||||
if (!ts.isPropertySignature(member) || !member.name || !member.type || !ts.isTypeReferenceNode(member.type)) continue;
|
||||
canonicalOwners.set(member.type.typeName.getText(source), member.name.getText(source).replaceAll('"', ""));
|
||||
}
|
||||
|
||||
function memberName(member) {
|
||||
if (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 type member: ${ts.SyntaxKind[member.kind]}`);
|
||||
if (ts.isIdentifier(member.name) || ts.isStringLiteral(member.name) || ts.isNumericLiteral(member.name)) {
|
||||
return member.name.text;
|
||||
}
|
||||
return member.name.getText(source);
|
||||
}
|
||||
|
||||
function memberKind(member) {
|
||||
if (ts.isMethodSignature(member)) return "method";
|
||||
if (ts.isPropertySignature(member)) return "property";
|
||||
if (ts.isConstructSignatureDeclaration(member)) return "constructor";
|
||||
if (ts.isCallSignatureDeclaration(member)) return "call";
|
||||
if (ts.isIndexSignatureDeclaration(member)) return "index";
|
||||
throw new Error(`Unsupported type member: ${ts.SyntaxKind[member.kind]}`);
|
||||
}
|
||||
|
||||
const symbols = [];
|
||||
function addMember(owner, name, kind) {
|
||||
const canonicalOwner = canonicalOwners.get(owner) ?? owner;
|
||||
const symbol = `${canonicalOwner}.${name}`;
|
||||
const declarationSymbol = `${owner}.${name}`;
|
||||
symbols.push({ symbol, kind, ...(symbol === declarationSymbol ? {} : { declarationSymbol }) });
|
||||
}
|
||||
|
||||
function collectTypeMembers(owner, node) {
|
||||
if (ts.isTypeLiteralNode(node)) {
|
||||
for (const member of node.members) {
|
||||
addMember(owner, memberName(member), memberKind(member));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ts.isIntersectionTypeNode(node) || ts.isUnionTypeNode(node)) {
|
||||
for (const type of node.types) collectTypeMembers(owner, type);
|
||||
return;
|
||||
}
|
||||
if (ts.isParenthesizedTypeNode(node)) collectTypeMembers(owner, node.type);
|
||||
else throw new Error(`Unsupported type expression for ${owner}: ${ts.SyntaxKind[node.kind]}`);
|
||||
}
|
||||
|
||||
function collectModule(owner, moduleDeclaration) {
|
||||
symbols.push({ symbol: owner, kind: "namespace" });
|
||||
if (!moduleDeclaration.body) throw new Error(`Namespace ${owner} has no body.`);
|
||||
if (ts.isModuleDeclaration(moduleDeclaration.body)) {
|
||||
collectModule(`${owner}.${moduleDeclaration.body.name.getText(source).replaceAll('"', "")}`, moduleDeclaration.body);
|
||||
return;
|
||||
}
|
||||
if (!ts.isModuleBlock(moduleDeclaration.body)) {
|
||||
throw new Error(`Unsupported namespace body for ${owner}: ${ts.SyntaxKind[moduleDeclaration.body.kind]}`);
|
||||
}
|
||||
for (const child of moduleDeclaration.body.statements) {
|
||||
if (ts.isEnumDeclaration(child)) {
|
||||
const enumName = `${owner}.${child.name.text}`;
|
||||
symbols.push({ symbol: enumName, kind: "enum" });
|
||||
for (const member of child.members) {
|
||||
symbols.push({ symbol: `${enumName}.${member.name.getText(source).replaceAll('"', "")}`, kind: "enumMember" });
|
||||
}
|
||||
} else if (ts.isModuleDeclaration(child)) {
|
||||
collectModule(`${owner}.${child.name.getText(source).replaceAll('"', "")}`, child);
|
||||
} else {
|
||||
throw new Error(`Unsupported declaration in namespace ${owner}: ${ts.SyntaxKind[child.kind]}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const statement of source.statements) {
|
||||
if (ts.isTypeAliasDeclaration(statement)) {
|
||||
const owner = statement.name.text;
|
||||
symbols.push({ symbol: owner, kind: "type" });
|
||||
collectTypeMembers(owner, statement.type);
|
||||
} else if (ts.isModuleDeclaration(statement)) {
|
||||
collectModule(statement.name.getText(source).replaceAll('"', ""), statement);
|
||||
} else if (ts.isExportAssignment(statement) && statement.expression.getText(source) === "premierepro") {
|
||||
// The package's `export = premierepro` binds the root declaration object.
|
||||
} else {
|
||||
throw new Error(`Unsupported top-level Adobe declaration: ${ts.SyntaxKind[statement.kind]}`);
|
||||
}
|
||||
}
|
||||
|
||||
const uniqueSymbols = [...new Map(symbols.map((entry) => [entry.symbol, entry])).values()]
|
||||
.sort((left, right) => compareText(left.symbol, right.symbol));
|
||||
const entries = uniqueSymbols.map((entry) => ({
|
||||
...entry,
|
||||
coverage: coveredApis.has(entry.symbol) ? "mapped" : "unmapped",
|
||||
}));
|
||||
const mapped = entries.filter((entry) => entry.coverage === "mapped").length;
|
||||
const declaredSymbols = new Set(entries.map((entry) => entry.symbol));
|
||||
const manifestOnly = [...coveredApis].filter((symbol) => !declaredSymbols.has(symbol)).sort(compareText);
|
||||
const inventory = {
|
||||
schemaVersion: 1,
|
||||
source: {
|
||||
package: "@adobe/premierepro",
|
||||
version: packageMetadata.version,
|
||||
declarations: "node_modules/@adobe/premierepro/src/premierepro.d.ts",
|
||||
declarationsSha256,
|
||||
coverageManifest: "src/resources/adobe-uxp-coverage.json",
|
||||
},
|
||||
semantics: {
|
||||
mapped: "The exact declaration symbol is referenced by at least one coverage-manifest entry; this alone is not live-host verification.",
|
||||
unmapped: "No coverage-manifest entry references the exact declaration symbol; this is a review queue, not proof that a standalone MCP tool is appropriate.",
|
||||
},
|
||||
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} Adobe 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("Adobe API inventory is stale. Run npm run adobe:api-inventory.");
|
||||
process.exitCode = 1;
|
||||
} else {
|
||||
console.log(`Adobe API inventory is current: ${entries.length} symbols from ${packageMetadata.version}.`);
|
||||
}
|
||||
} else {
|
||||
await writeFile(outputPath, rendered);
|
||||
console.log(`Wrote ${entries.length} Adobe API symbols (${mapped} mapped, ${entries.length - mapped} unmapped).`);
|
||||
}
|
||||
Reference in New Issue
Block a user