Skip to content

Commit

Permalink
feat(cli): exports json schema (#2362)
Browse files Browse the repository at this point in the history
## Describe your changes

Fixes
https://linear.app/nango/issue/NAN-1154/produce-json-schema-locally
Fixes
https://linear.app/nango/issue/NAN-1155/upload-json-schema-when-deploying

- Output `schema.ts` and `schema.json` in `.nango/` folder
We decided to not output additional stuff at the root level to avoid
cluttering the main folder. Customers can choose what they to commit.
And we will add more output in the coming weeks/months (most likely zod,
then others languages maybe)

- Rename `load` to `loadValidateParse`
For clarification because it wasn't super obvious it could fail with
validation error.

- Touch a bit deploy.service to prepare new files to be sent but the
logic is the same as before (not yet sending json)
  • Loading branch information
bodinsamuel committed Jun 25, 2024
1 parent 0c80bfd commit a40e180
Show file tree
Hide file tree
Showing 24 changed files with 560 additions and 206 deletions.
109 changes: 108 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 82 additions & 0 deletions packages/cli/lib/__snapshots__/sync.unit.cli-test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`generate function tests > should init the expected files in the nango-integrations directory 1`] = `
"// ---------------------------
// This file was generated by Nango (vTest)
// You can version this file
// ---------------------------
export interface GithubIssue {
id: number;
owner: string;
repo: string;
issue_number: number;
title: string;
author: string;
author_id: string;
state: string;
date_created: Date;
date_last_modified: Date;
};
"
`;

exports[`generate function tests > should init the expected files in the nango-integrations directory 2`] = `
"{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/GithubIssue",
"definitions": {
"GithubIssue": {
"type": "object",
"properties": {
"id": {
"type": "number"
},
"owner": {
"type": "string"
},
"repo": {
"type": "string"
},
"issue_number": {
"type": "number"
},
"title": {
"type": "string"
},
"author": {
"type": "string"
},
"author_id": {
"type": "string"
},
"state": {
"type": "string"
},
"date_created": {
"type": "string",
"format": "date-time"
},
"date_last_modified": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"owner",
"repo",
"issue_number",
"title",
"author",
"author_id",
"state",
"date_created",
"date_last_modified"
],
"additionalProperties": false
}
},
"$comment": "This file was generated by Nango (vTest)"
}"
`;
8 changes: 4 additions & 4 deletions packages/cli/lib/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { spawn } from 'child_process';
import type { ChildProcess } from 'node:child_process';

import { NANGO_INTEGRATIONS_NAME, getNangoRootPath, getPkgVersion, printDebug } from './utils.js';
import { loadYamlAndGeneratedModel } from './services/model.service.js';
import { loadYamlAndGenerate } from './services/model.service.js';
import { TYPES_FILE_NAME, exampleSyncName } from './constants.js';
import { compileAllFiles, compileSingleFile, getFileToCompile } from './services/compile.service.js';
import { getLayoutMode } from './utils/layoutMode.js';
Expand All @@ -35,7 +35,7 @@ export function generate({ fullPath, debug = false }: { fullPath: string; debug?
const githubExampleTemplateContents = fs.readFileSync(path.resolve(__dirname, './templates/github.sync.ejs'), 'utf8');
const postConnectionTemplateContents = fs.readFileSync(path.resolve(__dirname, './templates/post-connection.ejs'), 'utf8');

const res = loadYamlAndGeneratedModel({ fullPath, debug });
const res = loadYamlAndGenerate({ fullPath, debug });
if (!res.success) {
return;
}
Expand Down Expand Up @@ -204,7 +204,7 @@ NANGO_DEPLOY_AUTO_CONFIRM=false # Default value`

export function tscWatch({ fullPath, debug = false }: { fullPath: string; debug?: boolean }) {
const tsconfig = fs.readFileSync(`${getNangoRootPath()}/tsconfig.dev.json`, 'utf8');
const res = loadYamlAndGeneratedModel({ fullPath, debug });
const res = loadYamlAndGenerate({ fullPath, debug });
if (!res.success) {
console.log(chalk.red(res.error?.message));
if (res.error?.payload) {
Expand Down Expand Up @@ -277,7 +277,7 @@ export function configWatch({ fullPath, debug = false }: { fullPath: string; deb
const watcher = chokidar.watch(watchPath, { ignoreInitial: true });

watcher.on('change', () => {
loadYamlAndGeneratedModel({ fullPath, debug });
loadYamlAndGenerate({ fullPath, debug });
});
}

Expand Down
8 changes: 4 additions & 4 deletions packages/cli/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { DryRunService } from './services/dryrun.service.js';
import { v1toV2Migration, directoryMigration } from './services/migration.service.js';
import { getNangoRootPath, upgradeAction, NANGO_INTEGRATIONS_LOCATION, printDebug } from './utils.js';
import type { ENV, DeployOptions } from './types.js';
import { load } from './services/config.service.js';
import { parse } from './services/config.service.js';
import { nangoConfigFile } from '@nangohq/nango-yaml';

class NangoCommand extends Command {
Expand Down Expand Up @@ -264,15 +264,15 @@ program
const { autoConfirm } = this.opts();
const fullPath = process.cwd();
await verificationService.necessaryFilesExist({ fullPath, autoConfirm });
const { success, error, response: parsed } = load(path.resolve(fullPath, NANGO_INTEGRATIONS_LOCATION));
const { success, error, response } = parse(path.resolve(fullPath, NANGO_INTEGRATIONS_LOCATION));

if (!success || !parsed) {
if (!success || !response?.parsed) {
console.log(chalk.red(error?.message));
process.exitCode = 1;
return;
}

console.log(chalk.green(JSON.stringify({ ...parsed, models: Array.from(parsed.models.values()) }, null, 2)));
console.log(chalk.green(JSON.stringify({ ...response.parsed, models: Array.from(response.parsed.models.values()) }, null, 2)));
});

// admin only commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,32 @@ export type Anonymous_unauthenticated_action_inputoutputunion_input = true | 'he
// ------ /Models
"
`;
exports[`generate exports > json > should export to JSON 1`] = `
"{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/Test",
"definitions": {
"Test": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "array",
"items": {
"type": "number"
}
}
},
"required": [
"id",
"name"
],
"additionalProperties": false
}
},
"$comment": "This file was generated by Nango (vTest)"
}"
`;
30 changes: 24 additions & 6 deletions packages/cli/lib/services/compile.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import * as tsNode from 'ts-node';
import chalk from 'chalk';
import path from 'path';
import { build } from 'tsup';
import { localFileService } from '@nangohq/shared';

import { getNangoRootPath, printDebug } from '../utils.js';
import { loadYamlAndGeneratedModel } from './model.service.js';
import { loadYamlAndGenerate } from './model.service.js';
import parserService from './parser.service.js';
import type { NangoYamlParsed, ScriptTypeLiteral } from '@nangohq/types';
import type { NangoYamlParsed, ScriptFileType, ScriptTypeLiteral } from '@nangohq/types';
import { getProviderConfigurationFromPath } from '@nangohq/nango-yaml';

const ALLOWED_IMPORTS = ['url', 'crypto', 'zod', 'node:url', 'node:crypto'];
Expand All @@ -25,7 +24,7 @@ export async function compileAllFiles({
fullPath: string;
scriptName?: string;
providerConfigKey?: string;
type?: string;
type?: ScriptFileType;
}): Promise<boolean> {
const tsconfig = fs.readFileSync(`${getNangoRootPath()}/tsconfig.dev.json`, 'utf8');

Expand All @@ -37,7 +36,7 @@ export async function compileAllFiles({
fs.mkdirSync(distDir);
}

const res = loadYamlAndGeneratedModel({ fullPath, debug });
const res = loadYamlAndGenerate({ fullPath, debug });
if (!res.success) {
return false;
}
Expand All @@ -55,7 +54,7 @@ export async function compileAllFiles({

let scriptDirectory: string | undefined;
if (scriptName && providerConfigKey && type) {
scriptDirectory = localFileService.resolveTsFileLocation({ scriptName, providerConfigKey, type }).replace(fullPath, '');
scriptDirectory = resolveTsFileLocation({ fullPath, scriptName, providerConfigKey, type }).replace(fullPath, '');
console.log(chalk.green(`Compiling ${scriptName}.ts in ${fullPath}${scriptDirectory}`));
}

Expand Down Expand Up @@ -256,6 +255,25 @@ export function getFileToCompile({ fullPath, filePath }: { fullPath: string; fil
};
}

export function resolveTsFileLocation({
fullPath,
scriptName,
providerConfigKey,
type
}: {
fullPath: string;
scriptName: string;
providerConfigKey: string;
type: ScriptFileType;
}) {
const nestedPath = path.resolve(fullPath, providerConfigKey, type, `${scriptName}.ts`);
if (fs.existsSync(nestedPath)) {
return fs.realpathSync(path.resolve(nestedPath, '../'));
}

return fs.realpathSync(path.join(fullPath, './'));
}

export function listFilesToCompile({
fullPath,
scriptDirectory,
Expand Down
Loading

0 comments on commit a40e180

Please sign in to comment.