bcherny / json-schema-to-typescript

Compile JSON Schema to TypeScript type declarations
https://bcherny.github.io/json-schema-to-typescript-browser/
MIT License
2.96k stars 393 forks source link

[Feature] Add single file output for multi file input #272

Open Ethan-Arrowood opened 4 years ago

Ethan-Arrowood commented 4 years ago

238 is adding the ability to specify multiple file input for this library.

An additional feature would be to allow the user to specify a single file output for a multi file input and have everything be concatenated into the single file output.

Currently, a check is in place in the CLI to throw an error when the user attempts this operation.

smil2k commented 4 years ago

I'm using this script to generate all the types into one file:

import { compileFromFile } from 'json-schema-to-typescript'
const directoryTree = require('directory-tree');
const fs = require("fs");

fs.writeFileSync('src/types.d.ts', "/* tslint:disable */\n/** Execute `npm run compileSchema` to regenerate **/\n\n");

directoryTree('../restapi/schemas', { extensions: /\.json$/ }, (item, PATH) => {
  console.log(item.path);

  let basename = PATH.basename(item.name, ".json");

  compileFromFile(item.path, { 
    cwd: "../restapi/schemas",
    bannerComment: "// ----------------------------------------------- " 
  })
    .then(ts => fs.appendFileSync("src/types.d.ts", ts));
});

Probably it would be a great addition to the CLI sometime in the future ;-)

tadhgmister commented 4 years ago

I would like to implement this as I have similar needs, primarily that the set of used names needs to persist over multiple calls to compile (so definition names don't overlap) and possibly only export the main schema instead of all defined types.

I've never used ava before, would I just add some tests in the same format to testCLI.ts and then commit what ever files get generated from running?

shahinghasemi commented 2 years ago

It's also good to first append all typescripts together then write it to file once, since it's I/O it's better to be used minimum.

for each item do
  const ts = await compileFromFile(item.path, { 
      cwd: "../restapi/schemas",
      bannerComment: "// ----------------------------------------------- " 
  })
  appendedSchemasTogether += ts;

fs.writeFileSync("src/types.d.ts", appendedSchemasTogether)
drhr commented 2 years ago

just FYI, keep an eye on #258, I'm working on de-duping output both for multi- and single-out scenarios - I have the stdout case handled there, so I'm planning to account for this case as well.

I implemented a few changes very similar to #338, namely: removing the exception (of course), and pulling up the UsedNames set to a higher context.

However, for de-duping in #258, I had to augment UsedNames to include a "scope" concept, so that we only dodge/increment used names when required, to better handle the multi-out case by considering the isolation afforded by the files' scopes. I treat stdout / single-out as one big scope, which causes my solution to effectively reduce down to what #338 is doing.

More to come here - still need to refactor and test as time permits - just wanted to drop a note that this is in progress as a side effect of #258.

JDone-forgame commented 5 months ago

My solution is to design a three-layer directory, including the root directory, module directory, and specific JSON file directory. Use a script to merge it into a type output file, as shown below.

|-- route |---- json |------ game |-------- create_player.json |------ user |-------- user_login.json |---- index.ts |---- index.d.ts

index.ts

import path from "path";
import fs from "fs";
import { compileFromFile } from "json-schema-to-typescript";

async function compileJSONSchema() {
    try {
        const jsonDir = path.join(__dirname, 'json');
        const promiseArr: any[] = [];
        getCompileFromDir(jsonDir, promiseArr)
        const compileRet: string[] = await Promise.all(promiseArr);
        let writeStr = '/**\n * 自动生成的 JSON Schema 类型定义文件\n * 请勿手动修改此文件\n * @author JupiterOcean\n */\n\n';
        for (let one of compileRet) {
            one = one.slice(236);
            writeStr += one + '\n';
        }
        fs.writeFileSync(path.join(__dirname, 'index.d.ts'), writeStr, { encoding: 'utf-8' })
        console.log('JSON Schema 编译完成!')
    } catch (error) {
        console.error(error);
    }
}

function getCompileFromDir(dir: string, promiseArr: any[]) {
    const files = fs.readdirSync(dir);
    files.forEach((file) => {
        if (fs.lstatSync(path.join(dir, file)).isDirectory()) {
            getCompileFromDir(path.join(dir, file), promiseArr);
        } else {
            if (file.endsWith('.json')) promiseArr.push(compileFromFile(path.join(dir, file)));
        }
    })
}

compileJSONSchema();

package.json

"scripts": {
    "compile-schema": "npx ts-node src/routes/index.ts"
 },

If there are any problems, please correct them. I hope it will be helpful to you.