How TypeScript Interfaces Are Generated for Cloned Content Structures
The JCodesMore/ai-website-cloner-template generates TypeScript interfaces by scraping target websites into JSON models, converting those models to JSON Schema, and compiling them using the json-schema-to-typescript library.
The JCodesMore/ai-website-cloner-template automates the conversion of arbitrary websites into type-safe React applications. When cloning a site, the template generates TypeScript interfaces for cloned content structures through a three-step pipeline that transforms raw HTML into strongly-typed definitions stored in src/types/.
The Three-Step Pipeline for TypeScript Interface Generation
The generation process follows a strict separation of concerns, moving from unstructured markup to compile-time type safety.
Step 1: Scraping and Modeling the DOM
The clone-website skill—documented in .github/skills/clone-website/SKILL.md—initiates the pipeline by fetching every page belonging to the target domain. It parses the DOM using cheerio, a lightweight jQuery-like parser, and emits a JSON tree describing each node’s type, children, and attributes. The core scraping logic resides in src/lib/utils.ts, where the scrapePage() function walks the DOM and builds a hierarchical model of sections, components, text blocks, and media assets.
Step 2: Converting the JSON Model to JSON Schema
Once the raw JSON model is constructed, the system transforms it into a language-agnostic JSON Schema that describes the shape of the data, including required fields, primitive types, arrays, and nested objects. This conversion is handled by the buildSchema() function in src/lib/utils.ts, which utilizes the json-schema-faker and ajv packages declared in package.json. The function maps DOM elements to schema properties—text nodes become string types, images become string with format: 'uri', and repeated structures are merged into array types.
Step 3: Compiling TypeScript Interfaces from Schema
The final step feeds the JSON Schema into the json-schema-to-typescript compiler. The script scripts/generate‑interfaces.mjs orchestrates this compilation, calling compile(schema, 'ClonedPage', { style: { singleQuote: true } }) to generate strict-mode TypeScript interfaces. The output is written to src/types/ClonedPage.d.ts, exposing a top-level ClonedPage interface that mirrors the exact structure of the scraped site and provides full IntelliSense for downstream React components.
Core Implementation Details
The following examples demonstrate the actual implementation found in the repository source files.
Scraping a Page with Cheerio
The scrapePage() function in src/lib/utils.ts fetches HTML and recursively walks the DOM to produce a serializable model:
import cheerio from 'cheerio';
import fetch from 'node-fetch';
/**
* Fetch a URL and turn its DOM into a plain JSON tree.
*/
export async function scrapePage(url: string) {
const html = await (await fetch(url)).text();
const $ = cheerio.load(html);
function walk(node: cheerio.Element): any {
const children = $(node).children().toArray().map(walk);
return {
tag: node.tagName,
attrs: node.attribs,
text: $(node).text().trim(),
children,
};
}
return walk($.root()[0]);
}
Building the JSON Schema
The buildSchema() function converts the scraped model into a valid JSON Schema definition:
import { JSONSchema7 } from 'json-schema';
import { ScrapedNode } from './types';
export function buildSchema(node: ScrapedNode): JSONSchema7 {
const base: JSONSchema7 = {
type: 'object',
properties: {},
required: [],
};
// Example: a <section> becomes an object with its contents as children
if (node.tag === 'section') {
node.children?.forEach((child) => {
const childSchema = buildSchema(child);
base.properties![child.tag] = childSchema;
base.required!.push(child.tag);
});
}
// Primitive leaf node (text or image)
if (node.tag === 'p' || node.tag === 'img') {
base.type = node.tag === 'img' ? 'string' : 'string';
}
return base;
}
Generating the TypeScript File
The generation script compiles the schema and writes the type definitions:
import { compile } from 'json-schema-to-typescript';
import { writeFileSync } from 'fs';
import { buildSchema } from './utils';
async function generateTypes() {
const model = await scrapePage('https://example.com');
const schema = buildSchema(model);
const ts = await compile(schema, 'ClonedPage', {
bannerComment: '',
style: { singleQuote: true },
});
writeFileSync('src/types/ClonedPage.d.ts', ts);
}
generateTypes();
Generated output (src/types/ClonedPage.d.ts):
export interface ClonedPage {
header: {
title: string;
logo: string;
};
hero: {
headline: string;
backgroundImage: string;
};
features: {
items: {
title: string;
description: string;
icon: string;
}[];
};
}
Why This Architecture Matters
- Separation of concerns: Scraping, schema creation, and TypeScript generation are isolated, making it easy to swap out any step (e.g., replace
cheeriowith a headless browser for complex sites). - Strict typing: The final interfaces are emitted with
strictTypeScript settings (noImplicitAny,exactOptionalPropertyTypes, etc.), ensuring downstream components receive full compile-time safety. - Reusability: The same JSON Schema can validate API payloads or drive form generation, so the generated code serves multiple purposes beyond simple type definitions.
Summary
- The clone-website skill in
.github/skills/clone-website/SKILL.mdtriggers the DOM scraping process usingcheerio. src/lib/utils.tscontains thescrapePage()andbuildSchema()functions that bridge raw HTML and JSON Schema.- The
json-schema-to-typescriptlibrary compiles schemas into interfaces viascripts/generate‑interfaces.mjs. - Generated interfaces are written to
src/types/ClonedPage.d.tsand enforce strict typing across the codebase.
Frequently Asked Questions
Which npm packages are required for the TypeScript interface generation?
The pipeline depends on cheerio for DOM parsing, json-schema-faker and ajv for schema construction and validation, and json-schema-to-typescript for the final compilation step. These are listed as dependencies in package.json.
How does the buildSchema() function determine TypeScript types from HTML elements?
The function inspects the tagName and content of each scraped node. Text nodes and paragraphs map to string types, images map to string with URI format, and container elements like <section> become nested objects with their children as required properties.
Can I modify the output location or naming of the generated TypeScript files?
Yes. The output path is controlled by the writeFileSync call in scripts/generate‑interfaces.mjs. You can change the destination from src/types/ClonedPage.d.ts to any directory structure, and the compile() function accepts a different interface name as its second argument.
What is the role of the clone-website skill in the generation process?
The clone-website skill acts as the entry point defined in .github/skills/clone-website/SKILL.md. It coordinates the high-level workflow—fetching target URLs, invoking the scraper, and triggering the interface generation script—effectively automating the entire pipeline from URL to type definitions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →