Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 6 additions & 29 deletions Docs/astro.config.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,12 @@
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import { config } from "node-config-ts";
import { readdirSync, readFileSync } from "fs";
import { basename, extname, join } from "path";
import { locales } from "./utils/locales";
import { configExport } from "./utils/config";

const locales: Record<string, {
label: string;
lang?: string;
}> = {
en: {
label: "English",
},
};

const dir = "../Assets/lang/translated";
const files = readdirSync(dir);
files.forEach(file => {
if (extname(file) !== ".json")
return;

const filePath = join(dir, file);
const content = readFileSync(filePath, "utf8");

const json = JSON.parse(content);

const fileNameWithoutExtension = basename(file, ".json");

locales[fileNameWithoutExtension] = {
label: json.language,
};
});
// Extract all interfaces from the Config.d.ts file
configExport();
console.log("Interfaces extracted to config.json");

// https://astro.build/config
export default defineConfig({
Expand Down Expand Up @@ -64,7 +41,7 @@ export default defineConfig({
},
favicon: "/favicon.ico",
defaultLocale: "en",
locales,
locales: locales(),
customCss: [
"./src/styles/custom.scss",
"./src/fonts/font-face.scss",
Expand Down
18 changes: 18 additions & 0 deletions Docs/src/components/Config.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
import { readFile } from "fs/promises";

import RenderProperties from "./RenderProperties.astro";

interface Property {
name: string;
type: string | Property[];
}

const data = await readFile("./src/data/config.json", "utf8");
const config: Record<string, Property[]> = JSON.parse(data);
---

{Object.entries(config).map(([interfaceName, properties]) => (
<h3 id={interfaceName}>{interfaceName}</h2>
<RenderProperties properties={properties} importName="node-config-ts" />
))}
45 changes: 45 additions & 0 deletions Docs/src/components/RenderProperties.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
interface Property {
name: string;
type: string | Property[];
}

interface Props {
properties: Property[];
importName: string;
}

const { properties, importName } = Astro.props;

function extractInterfaceName (type: string): [undefined | string, string] {
const match = type.match(/import\("(\S+)"\)\.(\w+)/);
return match ? [match[1], match[2]] : [undefined, type];
};
---
<ul>
{properties.map((p) => {
if (Array.isArray(p.type)) {
return (
<li>
<strong>{p.name}:</strong>
<Astro.self properties={p.type} importName={importName} />
</li>
);
}

const [importModule, extractedType] = extractInterfaceName(p.type);
const isLocal = extractedType !== p.type && importModule === importName;
return (
<li>
<strong>{p.name}:</strong>
{extractedType !== p.type ? isLocal ?(
<a href={`#${extractedType}`}>{extractedType}</a>
) : (
<a href={`../../${importModule}#${extractedType}`}>{extractedType}</a>
) : (
extractedType
)}
</li>
);
})}
</ul>
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ sidebar:
variant: caution
order: 6000
---
import WorkInProgress from '../../../../../../components/WorkInProgress.astro';
import Config from '../../../../../../components/Config.astro';

<WorkInProgress section="misc/reference/config" />
<Config />
2 changes: 2 additions & 0 deletions Docs/src/data/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
82 changes: 82 additions & 0 deletions Docs/utils/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { writeFileSync } from "fs";
import { Project, PropertySignature, Type, ts } from "ts-morph";

interface Property {
name: string;
type: string | Property[];
}

/**
* Process the properties of an object that is not a named interface
* @param {Type} type The type of the object
* @returns {Property[]} The processed properties of type `Property`
* @example
* const properties = processNestedProperties(type);
* console.log(properties);
*/
function processNestedProperties (type: Type): Property[] {
const symbol = type.getSymbol();
if (!symbol)
return [];

const declarations = symbol.getDeclarations();
if (declarations.length === 0)
return [];

const declaration = declarations[0];
if (declaration.isKind(ts.SyntaxKind.TypeLiteral) || declaration.isKind(ts.SyntaxKind.InterfaceDeclaration)) {
const properties = declaration.getProperties();
return processProperties(properties);
}

return [];
}

/**
* Process the properties of an interface/object and return them as an array of Property objects
* @param {PropertySignature} properties The properties of the interface/object
* @returns {Property[]} The processed properties of type `Property`
* @example
* const properties = processProperties(iface.getProperties());
* console.log(properties);
*/
function processProperties (properties: PropertySignature[]): Property[] {
return properties.map((prop) => {
const propType = prop.getType();

// If the property is an object that is not a named interface, we need to process its properties
if (propType.isObject() && propType.isAnonymous()) {
const nestedProperties = processNestedProperties(propType);
return {
name: prop.getName(),
type: nestedProperties,
};
}

return {
name: prop.getName(),
type: propType.getText(),
};
});
}

/**
* Extract all interfaces from the `~/config/Config.d.ts` file and write them to a `config.json` file
* @example
* configExport();
*/
export function configExport () {
const project = new Project();
const filePath = "./config/Config.d.ts";
const sourceFile = project.addSourceFileAtPath(filePath);

const interfaces: Record<string, Property[]> = {};

sourceFile.getModules()[0].getInterfaces().forEach((iface) => {
const name = iface.getName();
const properties = processProperties(iface.getProperties());
interfaces[name] = properties;
});

writeFileSync("./src/data/config.json", JSON.stringify(interfaces, null, 2));
}
35 changes: 35 additions & 0 deletions Docs/utils/locales.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { readFileSync, readdirSync } from "fs";
import { basename, extname, join } from "path";

type localeDict = Record<string, {
label: string;
lang?: string;
}>;

export function locales (): localeDict {
const locales: localeDict = {
en: {
label: "English",
},
};

const dir = "../Assets/lang/translated";
const files = readdirSync(dir);
files.forEach(file => {
if (extname(file) !== ".json")
return;

const filePath = join(dir, file);
const content = readFileSync(filePath, "utf8");

const json = JSON.parse(content);

const fileNameWithoutExtension = basename(file, ".json");

locales[fileNameWithoutExtension] = {
label: json.language,
};
});

return locales;
}
Loading