@azure-tools/typespec-apiview
Version:
Library for emitting APIView token files from TypeSpec
98 lines • 4.03 kB
JavaScript
import { emitFile, getNamespaceFullName, listServices, NoTarget, resolvePath, } from "@typespec/compiler";
import path from "path";
import { ApiView } from "./apiview.js";
import { reportDiagnostic } from "./lib.js";
export async function $onEmit(context) {
const options = resolveOptions(context);
const emitter = createApiViewEmitter(context.program, options);
await emitter.emitApiView();
}
export function resolveOptions(context) {
var _a;
const resolvedOptions = { ...context.options };
return {
emitterOutputDir: context.emitterOutputDir,
outputFile: resolvedOptions["output-file"],
service: resolvedOptions["service"],
includeGlobalNamespace: (_a = resolvedOptions["include-global-namespace"]) !== null && _a !== void 0 ? _a : false,
};
}
function resolveNamespaceString(namespace) {
// FIXME: Fix this wonky workaround when getNamespaceString is fixed.
const value = getNamespaceFullName(namespace);
return value === "" ? undefined : value;
}
/**
* Ensures that single-value options are not used in multi-service specs unless the
* `--service` option is specified. Single-service specs need not pass this option.
*/
function validateMultiServiceOptions(program, services, options) {
for (const [name, val] of [["output-file", options.outputFile]]) {
if (val && !options.service && services.length > 1) {
reportDiagnostic(program, {
code: "invalid-option",
target: NoTarget,
format: {
name: name
}
});
}
}
}
/**
* If the `--service` option is provided, ensures the service exists and returns the filtered list.
*/
function applyServiceFilter(program, services, options) {
if (!options.service) {
return services;
}
const filtered = services.filter((x) => x.title === options.service);
if (!filtered.length) {
reportDiagnostic(program, {
code: "invalid-service",
target: NoTarget,
format: {
value: options.service
}
});
}
return filtered;
}
function createApiViewEmitter(program, options) {
return { emitApiView };
async function emitApiView() {
var _a, _b, _c;
let services = listServices(program);
if (!services.length) {
reportDiagnostic(program, {
code: "no-services-found",
target: NoTarget
});
return;
}
// applies the default "apiview.json" filename if not provided and there's only a single service
if (services.length === 1) {
options.outputFile = (_a = options.outputFile) !== null && _a !== void 0 ? _a : "apiview.json";
}
validateMultiServiceOptions(program, services, options);
services = applyServiceFilter(program, services, options);
for (const service of services) {
const namespaceString = (_b = resolveNamespaceString(service.type)) !== null && _b !== void 0 ? _b : "Unknown";
const serviceTitle = service.title ? service.title : namespaceString;
const apiview = new ApiView(serviceTitle, namespaceString, options.includeGlobalNamespace);
apiview.compile(program);
apiview.resolveMissingTypeReferences();
if (!program.compilerOptions.noEmit && !program.hasError()) {
const outputFolder = path.dirname(options.emitterOutputDir);
await program.host.mkdirp(outputFolder);
const outputFile = (_c = options.outputFile) !== null && _c !== void 0 ? _c : `${namespaceString}-apiview.json`;
const outputPath = resolvePath(outputFolder, outputFile);
await emitFile(program, {
path: outputPath,
content: JSON.stringify(apiview.asCodeFile()) + "\n"
});
}
}
}
}
//# sourceMappingURL=emitter.js.map