Skip to content

Commit

Permalink
feat: generate type definitions from the json schema
Browse files Browse the repository at this point in the history
  • Loading branch information
k-yle committed Dec 26, 2024
1 parent 54c2a7d commit 3131e9e
Show file tree
Hide file tree
Showing 4 changed files with 264 additions and 7 deletions.
1 change: 0 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export default [
'indent': ['off', 4],
'keyword-spacing': 'error',
'linebreak-style': ['error', 'unix'],
'no-await-in-loop': 'error',
'no-caller': 'error',
'no-catch-shadow': 'error',
'no-console': 'warn',
Expand Down
68 changes: 67 additions & 1 deletion lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import fs from 'fs';
import { globSync } from 'glob';
import jsonschema from 'jsonschema';
import path from 'path';
import { fileURLToPath } from 'url';
import shell from 'shelljs';
import YAML from 'js-yaml';
import marky from 'marky';
import { createRequire } from 'module';
import { compileFromFile } from 'json-schema-to-typescript';
import { toSafeString } from 'json-schema-to-typescript/dist/src/utils.js';

import fetchTranslations from './translations.js';

Expand Down Expand Up @@ -187,7 +190,8 @@ function processData(options, type) {
minifyJSON(distDir + '/preset_defaults.json', distDir + '/preset_defaults.min.json'),
minifyJSON(distDir + '/deprecated.json', distDir + '/deprecated.min.json'),
minifyJSON(distDir + '/discarded.json', distDir + '/discarded.min.json'),
minifyJSON(distDir + '/translations/' + sourceLocale + '.json', distDir + '/translations/' + sourceLocale + '.min.json')
minifyJSON(distDir + '/translations/' + sourceLocale + '.json', distDir + '/translations/' + sourceLocale + '.min.json'),
generateTypeDefs(distDir),
];

if (doFetchTranslations) {
Expand Down Expand Up @@ -693,6 +697,68 @@ function generateIconsList(presets, fields, categories) {
return Object.keys(icons).sort();
}

/** @param {string} distDir */
async function generateTypeDefs(distDir) {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const inputFolder = path.join(__dirname, '../schemas');

/**
* Some generated files use plural names because they
* export an object, e.g. `Fields = Record<string, Field>`
*/
const KEY_MAP = {
field: 'fields',
preset: 'presets',
preset_category: 'preset_categories',
};
const fileNames = await fs.promises.readdir(inputFolder);

for (const fileName of fileNames) {
const key = fileName.replace('.json', '');
const pluralKey = KEY_MAP[key];

let base = `
declare const json: ${toSafeString(pluralKey || key)};
export default json;
`;

if (pluralKey) {
base += `
export type ${toSafeString(pluralKey)} = {
[id: string]: ${toSafeString(key)}
};
`;
}

const tsFile = await compileFromFile(path.join(inputFolder, fileName), {
additionalProperties: false,
bannerComment: base,

// ensure that the default export uses a consistent name
customName: (schema) =>
schema.$schema && schema.$id ? path.parse(schema.$id).name : undefined,
});

await fs.promises.writeFile(
path.join(distDir, `${pluralKey || key}.d.json.ts`),
tsFile,
);
}

// finally, create the index file which re-exports everything
// as named types.
const indexFile = fileNames
.map((fileName) => {
const key = fileName.replace('.json', '');
return `export type * from './${KEY_MAP[key] || key}.d.json.ts';`;
})
.join('\n');

await fs.promises.writeFile(
path.join(distDir, 'index.d.ts'),
indexFile + '\n',
);
}

function validateCategoryPresets(categories, presets) {
Object.keys(categories).forEach(id => {
Expand Down
Loading

0 comments on commit 3131e9e

Please sign in to comment.