"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
const path_1 = require("path");
const bluebird_1 = __importDefault(require("bluebird"));
const mkdirp = require("mkdirp");
const json_schema_to_typescript_1 = require("json-schema-to-typescript");
const json_schema_ref_parser_1 = require("@apidevtools/json-schema-ref-parser");
const ajv_1 = __importDefault(require("ajv"));
const ajv_pack_1 = __importDefault(require("ajv-pack"));
const ajv_2 = require("@oada/formats/lib/ajv");
const formats_1 = __importStar(require("@oada/formats"));
const normalize_1 = require("./normalize");
// Where to put compiled types
const typesDir = path_1.resolve('./');
const compileStr = '`$ yarn build`';
// Create ajv for packing validation functions
// @ts-ignore
const ajv = new ajv_1.default({ loadSchema: ajv_2.loadSchema, sourceCode: true });
// Compile the schema files to TypeScript types
async function doCompile() {
    const metaSchema = await json_schema_ref_parser_1.dereference('https://json-schema.org/draft/2019-09/schema');
    ajv.addMetaSchema(metaSchema);
    const formats = await formats_1.default();
    // Compile schemas to TS types
    for await (const { key, path, schema } of formats_1.schemas()) {
        //normalize(schema)
        const { $id } = schema;
        const file = key
            .replace(/^https:\/\/formats\.openag\.io/, '')
            .replace(/^\//, './');
        const outfile = path_1.join(typesDir, file.replace(/\.schema\.json$/, '.ts'));
        const name = path_1.basename(path, '.schema.json');
        const cwd = path_1.join(typesDir, path_1.dirname(path));
        const typeName = `${name[0].toUpperCase()}${name.substr(1)}`;
        // Pack up validation function
        const validate = await ajv.compileAsync(schema);
        const packed = ajv_pack_1.default(ajv, validate);
        const packedfile = path_1.join(typesDir, file.replace(/\.schema\.json$/, '-validate.js'));
        // Make the banner comment a bit more informative
        // TODO: Figure out some TS magic to use instead of this code generation??
        const bannerComment = `
        /* tslint:disable */
        /**
         * File was automatically generated using json-schema-to-typescript.
         * DO NOT MODIFY IT BY HAND.
         * Instead, modify the source file ${key} of @oada/formats
         * and run ${compileStr} to regenerate this file.
         */

        // Import packed validation function
        import validate from './${name}-validate.js'

        /**
         * $id of the source schema
         * @see {@link ${$id}}
         */
        export const $id = '${$id}'

        /**
         * Returns true if val is a @type ${typeName}, false otherwise
         */
        export function is (val: any): val is ${typeName} {
          return validate(val) as boolean
        }

        /**
         * Asserts that val is a @type ${typeName}
         */
        export function assert (val: any): asserts val is ${typeName} {
          if (!validate(val) as boolean) {
            throw {
              errors: validate.errors,
              input: val
            }
          }
        }

        // Augment module interface?
        //declare module '@oada/formats' {
        //  /**
        //   * @todo Figure out how do type overrides for getSchema
        //   */
        //  interface OADAFormats {
        //    validate(ref: '${$id}' | '${key}', data: any): data is ${typeName}
        //  }
        //}

        export default ${typeName}
      `;
        console.debug(`Compiling ${key} to TypeScript types`);
        console.debug(`Outputting ${outfile}`);
        try {
            const r = /^https:\/\/formats\.openag\.io/;
            const ts = await json_schema_to_typescript_1.compileFromFile(path, {
                bannerComment,
                unreachableDefinitions: true,
                normalizerRules: normalize_1.rules,
                $refOptions: {
                    // Use local versions of openag schemas
                    resolve: {
                        // @ts-ignore
                        oada: {
                            order: 0,
                            canRead: r,
                            async read({ url }) {
                                var _a;
                                return JSON.stringify((_a = formats.getSchema(url)) === null || _a === void 0 ? void 0 : _a.schema);
                            },
                        },
                    },
                },
                cwd,
            });
            await mkdirp(path_1.dirname(outfile));
            // TODO: Figure out wtf is up with mkdirp that I need this...
            await bluebird_1.default.delay(50);
            await fs_1.promises.writeFile(packedfile, packed);
            await fs_1.promises.writeFile(outfile, ts);
        }
        catch (err) {
            console.error(`Error compiling ${key}: %O`, err);
        }
    }
}
doCompile();
//# sourceMappingURL=compile.js.map