handoff-app
Version:
Automated documentation toolchain for building client side documentation from figma
159 lines (158 loc) • 7.5 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handlebarsPreviewsPlugin = handlebarsPreviewsPlugin;
const fs_extra_1 = __importDefault(require("fs-extra"));
const handlebars_1 = __importDefault(require("handlebars"));
const path_1 = __importDefault(require("path"));
const logger_1 = require("../../utils/logger");
const vite_logger_1 = require("../utils/vite-logger");
const handlebars_2 = require("../utils/handlebars");
const html_1 = require("../utils/html");
const string_1 = require("../utils/string");
/**
* Constants for the Handlebars previews plugin
*/
const PLUGIN_CONSTANTS = {
PLUGIN_NAME: 'vite-plugin-previews',
SCRIPT_ID: 'script',
DUMMY_EXPORT: 'export default {}',
INSPECT_SUFFIX: '-inspect',
OUTPUT_FORMAT: 'html',
};
/**
* Processes component instances from documentation and creates preview data
* @param componentData - Component transformation data
* @param documentationComponents - Documentation components
*/
function processComponentInstances(componentData, documentationComponents) {
// Use figmaComponentId if provided, otherwise skip implicit matching
if (componentData.figmaComponentId) {
const figmaComponentKey = (0, string_1.slugify)(componentData.figmaComponentId);
if (documentationComponents[figmaComponentKey]) {
for (const instance of documentationComponents[figmaComponentKey].instances) {
const variationId = instance.id;
const instanceValues = Object.fromEntries(instance.variantProperties);
componentData.previews[variationId] = {
title: variationId,
url: '',
values: instanceValues,
};
}
}
}
}
/**
* Renders a Handlebars template with the given preview data
* @param template - Handlebars template string
* @param componentData - Component transformation data
* @param previewData - Preview data to render
* @param injectFieldWrappers - Whether to inject field wrappers for inspection
* @returns Rendered HTML string
*/
function renderHandlebarsTemplate(template, componentData, previewData, injectFieldWrappers) {
return __awaiter(this, void 0, void 0, function* () {
// Register Handlebars helpers with current injection state
(0, handlebars_2.registerHandlebarsHelpers)({ id: componentData.id, properties: componentData.properties || {} }, injectFieldWrappers);
const context = (0, handlebars_2.createHandlebarsContext)({
id: componentData.id,
properties: componentData.properties || {},
title: componentData.title
}, previewData);
const compiled = handlebars_1.default.compile(template)(context);
return yield (0, html_1.formatHtmlWithWrapper)(compiled);
});
}
/**
* Generates preview files for a component variation
* @param componentId - Component identifier
* @param previewKey - Preview variation key
* @param normalHtml - Normal mode HTML
* @param inspectHtml - Inspect mode HTML
* @param emitFile - Vite emitFile function
*/
function emitPreviewFiles(componentId, previewKey, normalHtml, inspectHtml, emitFile) {
emitFile({
type: 'asset',
fileName: `${componentId}-${previewKey}.html`,
source: normalHtml,
});
emitFile({
type: 'asset',
fileName: `${componentId}-${previewKey}${PLUGIN_CONSTANTS.INSPECT_SUFFIX}.html`,
source: inspectHtml,
});
}
/**
* Handlebars previews plugin factory
* @param componentData - Component transformation data
* @param documentationComponents - Documentation components
* @param handoff - Handoff instance
* @returns Vite plugin for Handlebars previews
*/
function handlebarsPreviewsPlugin(componentData, documentationComponents, handoff) {
return {
name: PLUGIN_CONSTANTS.PLUGIN_NAME,
apply: 'build',
config: () => ({
customLogger: (0, vite_logger_1.createViteLogger)(),
}),
resolveId(resolveId) {
if (resolveId === PLUGIN_CONSTANTS.SCRIPT_ID) {
return resolveId;
}
},
load(loadId) {
if (loadId === PLUGIN_CONSTANTS.SCRIPT_ID) {
return PLUGIN_CONSTANTS.DUMMY_EXPORT;
}
},
generateBundle() {
return __awaiter(this, void 0, void 0, function* () {
const componentId = componentData.id;
const templatePath = path_1.default.resolve(componentData.entries.template);
const templateContent = yield fs_extra_1.default.readFile(templatePath, 'utf8');
// Ensure components object exists
if (!documentationComponents) {
documentationComponents = {};
}
// Process component instances from documentation
processComponentInstances(componentData, documentationComponents);
const generatedPreviews = {};
// Generate previews for each variation
for (const previewKey in componentData.previews) {
try {
const previewData = componentData.previews[previewKey];
// Render both normal and inspect modes
const normalModeHtml = yield renderHandlebarsTemplate(templateContent, componentData, previewData, false);
const inspectModeHtml = yield renderHandlebarsTemplate(templateContent, componentData, previewData, true);
// Emit preview files
emitPreviewFiles(componentId, previewKey, normalModeHtml, inspectModeHtml, (file) => this.emitFile(file));
generatedPreviews[previewKey] = normalModeHtml;
componentData.previews[previewKey].url = `${componentId}-${previewKey}.html`;
logger_1.Logger.debug(`Generated Handlebars preview: ${componentId}-${previewKey}`);
}
catch (err) {
logger_1.Logger.error(`Failed to generate Handlebars preview for ${componentId}-${previewKey}`, err);
}
}
// Update component data with results
componentData.format = PLUGIN_CONSTANTS.OUTPUT_FORMAT;
componentData.preview = '';
componentData.code = (0, html_1.trimPreview)(templateContent);
componentData.html = (0, html_1.trimPreview)(generatedPreviews[Object.keys(generatedPreviews)[0]]);
});
},
};
}