Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

crdtoapi

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

crdtoapi - npm Package Compare versions

Comparing version 0.0.11 to 0.0.12

.prettierrc.js

17

dist/findModels.js

@@ -24,2 +24,5 @@ #!/usr/bin/env node

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: this tool has poor color perception, you are encouraged to change the color and abbr attributes.
export const {{kind}}Model = {

@@ -53,11 +56,11 @@ label: '{{label}}',

program
.version("0.0.11")
.description("Convert CRDs to Group Version Kind Typescript constants")
.option("-i, --in <file>", "Input directory path - required")
.option("-o, --out <file>", "Output directory name")
.option("-m, --match <text>", "match files regexp")
.version('0.0.11')
.description('Convert CRDs to Group Version Kind Typescript constants')
.option('-i, --in <file>', 'Input directory path - required')
.option('-o, --out <file>', 'Output directory name')
.option('-m, --match <text>', 'match files regexp')
.parse(process.argv);
const options = program.opts();
if (!options.in) {
console.log("error: missing mandatory argument --in");
console.log('error: missing mandatory argument --in');
process.exit(1);

@@ -78,3 +81,3 @@ }

try {
const yaml = (0, js_yaml_1.load)(yield (0, promises_1.readFile)(filePath, "utf8"));
const yaml = (0, js_yaml_1.load)(yield (0, promises_1.readFile)(filePath, 'utf8'));
yaml.spec.versions.forEach((version) => {

@@ -81,0 +84,0 @@ const name = `${yaml.spec.names.kind}Model.${version.name}`;

@@ -26,20 +26,20 @@ #!/usr/bin/env node

program
.version("0.0.11")
.description("Convert CRDs to OpenAPI file")
.option("-i, --in <dir>", "Input directory path - required")
.option("-o, --out <file>", "Output file name")
.option("-t, --title <text>", "Module title")
.option("-d, --description <text>", "Module description")
.option("-l, --license <text>", "Module license")
.option("-m, --match <text>", "match files regexp")
.option("--licenseURL <text>", "Module license link")
.option("--contactName <text>", "Module contact name")
.option("--contactEmail <text>", "Module contact email")
.option("--contactURL <text>", "Module contact link")
.option("--apiVersion <text>", "Module API version")
.option("-j, --json", "output as json")
.version('0.0.11')
.description('Convert CRDs to OpenAPI file')
.option('-i, --in <dir>', 'Input directory path - required')
.option('-o, --out <file>', 'Output file name')
.option('-t, --title <text>', 'Module title')
.option('-d, --description <text>', 'Module description')
.option('-l, --license <text>', 'Module license')
.option('-m, --match <text>', 'match files regexp')
.option('--licenseURL <text>', 'Module license link')
.option('--contactName <text>', 'Module contact name')
.option('--contactEmail <text>', 'Module contact email')
.option('--contactURL <text>', 'Module contact link')
.option('--apiVersion <text>', 'Module API version')
.option('-j, --json', 'output as json')
.parse(process.argv);
const options = program.opts();
if (!options.in) {
console.log("error: missing mandatory argument --in");
console.log('error: missing mandatory argument --in');
process.exit(1);

@@ -52,10 +52,10 @@ }

const licenses = {
"Apache-2.0": "http://www.apache.org/licenses/",
"BSD-3": "https://opensource.org/licenses/BSD-3-Clause",
"BSD-2": "https://opensource.org/licenses/BSD-2-Clause",
"GPL-3.0": "www.gnu.org/licenses/gpl-3.0.en.html",
"GPL-2.0": "www.gnu.org/licenses/gpl-2.0.en.html",
"MIT": "https://opensource.org/licenses/MIT",
"MPL": "https://opensource.org/licenses/MPL-2.0",
"ISC": "https://www.isc.org/licenses/",
'Apache-2.0': 'http://www.apache.org/licenses/',
'BSD-3': 'https://opensource.org/licenses/BSD-3-Clause',
'BSD-2': 'https://opensource.org/licenses/BSD-2-Clause',
'GPL-3.0': 'www.gnu.org/licenses/gpl-3.0.en.html',
'GPL-2.0': 'www.gnu.org/licenses/gpl-2.0.en.html',
MIT: 'https://opensource.org/licenses/MIT',
MPL: 'https://opensource.org/licenses/MPL-2.0',
ISC: 'https://www.isc.org/licenses/',
};

@@ -73,3 +73,3 @@ // try to guess the license URL

try {
const yaml = (0, js_yaml_1.load)(yield (0, promises_1.readFile)(filePath, "utf8"));
const yaml = (0, js_yaml_1.load)(yield (0, promises_1.readFile)(filePath, 'utf8'));
yaml.spec.versions.forEach((version) => {

@@ -121,3 +121,3 @@ const name = `${version.name}${yaml.spec.names.kind}`;

const out = {
openapi: "3.1.0",
openapi: '3.1.0',
info: {

@@ -130,8 +130,8 @@ description: options.description,

email: options.contactEmail,
}
},
license: {
name: options.license,
url: licenseURL,
},
},
license: {
name: options.license,
url: licenseURL,
},
components: {

@@ -138,0 +138,0 @@ schemas: data,

{
"name": "crdtoapi",
"version": "0.0.11",
"version": "0.0.12",
"description": "CustomResourceDefinitions to OpensAPI",

@@ -9,3 +9,4 @@ "homepage": "https://github.com/yaacov/crdtoapi",

"crdtoapi": "./dist/index.js",
"crdtomodel": "./dist/findModels.js"
"crdtomodel": "./dist/findModels.js",
"crdtotypes": "./dist/findIntrefaces.js"
},

@@ -16,4 +17,4 @@ "scripts": {

"cleanall": "npm run clean && rm -rf ./node_modules",
"lint": "npx eslint ./src",
"lint:fix": "npx eslint ./src --fix",
"lint": "npx eslint ./src -c .eslintrc.cjs",
"lint:fix": "npx eslint ./src -c .eslintrc.cjs --fix",
"generate": "npx openapi-generator-cli generate -g typescript-fetch --skip-validate-spec -o generated -i"

@@ -36,3 +37,2 @@ },

"devDependencies": {
"@openapitools/openapi-generator-cli": "^2.5.2",
"@types/js-yaml": "^4.0.5",

@@ -44,4 +44,7 @@ "@types/mustache": "^4.2.2",

"eslint": "^8.29.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.8.4",
"typescript": "^4.9.3"
}
}

@@ -5,49 +5,20 @@ [![npm version](https://badge.fury.io/js/crdtoapi.svg)](https://badge.fury.io/js/crdtoapi)

crdtoapi is a tool that creates an [OpenAPI](https://www.openapis.org/) definitions file from [kubernetes](https://kubernetes.io/) [CustomResourceDefinitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/).
crdtoapi are a collection of tools that auto generate Typescript interfaces and constants out of [OpenAPI](https://www.openapis.org/) and [kubernetes](https://kubernetes.io/) [CustomResourceDefinitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) files.
## Usage
Tools:
Use kubernetes CRD definitions to create OpenAPI schema file.
| Name | description |
|------|-------------|
| [crdtoapi](./README.crdtoapi.md) | tool to genrate OpenAPI definition files out of Kubernetes CRDs |
| [crdtomodel](./README.crdtomodel.md) | tool to genrate Typescropt constants out of Kubernetes CRDs |
| [crdtotypes](./README.crdtotypes.md) | tool to genrate Typescropt interfaces out of OpenAPI definitions |
``` bash
npm install --location=global crdtoapi
# add npm bin path to your PATH, or use full
# excutable path, e.g. $(npm bin --location=global)/crdtoapi
crdtoapi --help
## Install
# create an OpenAPI file
crdtoapi -i ./examples/forklift/
# create an OpenAPI file using flags
crdtoapi -i ./examples/forklift/ -o openapi.yaml \
--title "Forklift API" \
--description "Migration toolkit for virtualization (Forklift) API definitions." \
--license "Apache-2.0" \
--apiVersion "2.4.0" \
--contactEmail "kubev2v-dev@redhat.com"
```
Use kubernetes CRD definitions to create Typescript resource constants.
``` bash
crdtomodel --help
# create typescropt constant files in ./tmp dir
mkdir tmp
crdtomodel -i ./examples/forklift/ -o ./tmp
npm install --location=global crdtoapi
```
## Generate some API
OpensAPI comunity provide many [tools](https://openapi.tools/), for example
`openapi-generator-cli` is a tool for auto code generation using OpenAPI definition files.
``` bash
# use openapi-generator-cli:
# npm i --location=global @openapitools/openapi-generator-cli
openapi-generator-cli generate \
-g typescript-fetch \
--skip-validate-spec \
-o generated \
-i openapi.yaml
```

@@ -54,0 +25,0 @@

#!/usr/bin/env node
import { Command } from "commander";
import { load } from "js-yaml";
import { readFile, writeFile, readdir } from "fs/promises";
import path from "path";
import { Command } from 'commander';
import { load } from 'js-yaml';
import { readFile, writeFile, readdir } from 'fs/promises';
import path from 'path';
import Mustache from 'mustache';

@@ -12,2 +12,5 @@

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: this tool has poor color perception, you are encouraged to change the color and abbr attributes.
export const {{kind}}Model = {

@@ -42,7 +45,7 @@ label: '{{label}}',

program
.version("0.0.11")
.description("Convert CRDs to Group Version Kind Typescript constants")
.option("-i, --in <file>", "Input directory path - required")
.option("-o, --out <file>", "Output directory name")
.option("-m, --match <text>", "match files regexp")
.version('0.0.12')
.description('Convert CRDs to Group Version Kind Typescript constants')
.option('-i, --in <file>', 'Input directory path - required')
.option('-o, --out <file>', 'Output directory name')
.option('-m, --match <text>', 'match files regexp')
.parse(process.argv);

@@ -53,4 +56,4 @@

if (!options.in) {
console.log("error: missing mandatory argument --in");
process.exit(1);
console.log('error: missing mandatory argument --in');
process.exit(1);
}

@@ -60,50 +63,50 @@

if (options.match) {
regexpMath = new RegExp(options.match);
regexpMath = new RegExp(options.match);
}
interface Model {
abbr: string;
kind: string;
label: string;
plural: string;
id?: string;
crd?: boolean;
apiVersion: string;
apiGroup?: string;
namespaced?: boolean;
color?: string;
abbr: string;
kind: string;
label: string;
plural: string;
id?: string;
crd?: boolean;
apiVersion: string;
apiGroup?: string;
namespaced?: boolean;
color?: string;
}
interface CustomResourceDefinitions {
metadata: {
metadata: {
name: string;
};
spec: {
group: string;
names: {
kind: string;
listKind: string;
plural: string;
singular: string;
};
scope: string;
versions: {
name: string;
additionalPrinterColumns: {
jsonPath: string;
name: string;
};
spec: {
group: string;
names: {
kind: string;
listKind: string;
plural: string;
singular: string;
};
scope: string;
versions: {
name: string;
additionalPrinterColumns: {
jsonPath: string;
name: string;
type: string;
}[];
schema: {
openAPIV3Schema: Record<string, unknown>;
};
}[];
};
type: string;
}[];
schema: {
openAPIV3Schema: Record<string, unknown>;
};
}[];
};
}
type Models = { [id: string] : Model; };
type Models = { [id: string]: Model };
/**
* Read one CRD file
*
*
* @param filePath is the CRD file to read

@@ -113,35 +116,35 @@ * @returns a dictionary with all the Models objects by kind and version

const readModels = async (filePath: string): Promise<Models> => {
const models: Models = {};
const models: Models = {};
try {
const yaml = load(await readFile(filePath, "utf8")) as CustomResourceDefinitions;
yaml.spec.versions.forEach((version) => {
const name = `${yaml.spec.names.kind}Model.${version.name}`;
try {
const yaml = load(await readFile(filePath, 'utf8')) as CustomResourceDefinitions;
models[name] = {
kind: yaml.spec.names.kind,
apiVersion: version.name,
apiGroup: yaml.spec.group,
yaml.spec.versions.forEach((version) => {
const name = `${yaml.spec.names.kind}Model.${version.name}`;
abbr: yaml.spec.names.kind.slice(0, 2).toUpperCase(),
label: yaml.spec.names.kind,
plural: yaml.spec.names.plural,
models[name] = {
kind: yaml.spec.names.kind,
apiVersion: version.name,
apiGroup: yaml.spec.group,
id: yaml.metadata.name,
crd: true,
namespaced: yaml.spec.scope === 'Namespaced',
};
});
} catch (error) {
console.log(`error occurr ed while reading input file (${error})`);
process.exit(1);
}
abbr: yaml.spec.names.kind.slice(0, 2).toUpperCase(),
label: yaml.spec.names.kind,
plural: yaml.spec.names.plural,
return models;
}
id: yaml.metadata.name,
crd: true,
namespaced: yaml.spec.scope === 'Namespaced',
};
});
} catch (error) {
console.log(`error occurr ed while reading input file (${error})`);
process.exit(1);
}
return models;
};
/**
* Read all CRD files in a directory
*
*
* @param dirPath is the directory to read

@@ -151,24 +154,24 @@ * @returns a dictionary with all the schemas objects by kind and version

const readSchemaDir = async (dirPath: string): Promise<Models> => {
let models: Models = {};
let models: Models = {};
try {
const files = await readdir(dirPath);
try {
const files = await readdir(dirPath);
for (const file of files) {
// If file don't match pattern, continue.
if (regexpMath && file.match(regexpMath) === null) {
continue;
}
for (const file of files) {
// If file don't match pattern, continue.
if (regexpMath && file.match(regexpMath) === null) {
continue;
}
const filePath = path.join(dirPath, file);
const filePath = path.join(dirPath, file);
const data = await readModels(filePath);
models = Object.assign({}, models, data );
}
} catch (error) {
console.log(`error occurr ed while reading the input directory (${error})`);
process.exit(1);
const data = await readModels(filePath);
models = Object.assign({}, models, data);
}
} catch (error) {
console.log(`error occurr ed while reading the input directory (${error})`);
process.exit(1);
}
return models;
return models;
};

@@ -179,34 +182,34 @@

* Use global CLI options as input
*
*
* @returns Promise<strings>
*/
const creatModelTSFiles = async (): Promise<boolean> => {
const data = await readSchemaDir(options.in);
let indexFileText = '';
const data = await readSchemaDir(options.in);
let indexFileText = '';
for (const [key, model] of Object.entries(data)) {
const fileName = `${key}.ts`
const fileText = Mustache.render(FileTemplate, model);
for (const [key, model] of Object.entries(data)) {
const fileName = `${key}.ts`;
const fileText = Mustache.render(FileTemplate, model);
// output one file
if (options.out) {
writeFile(path.normalize(`${options.out}/${fileName}`), fileText);
indexFileText = indexFileText + `export * from './${key}';\n`
} else {
console.log(`${fileName}:`);
console.log(fileText);
console.log();
}
}
// dump index file
// output one file
if (options.out) {
writeFile(path.normalize(`${options.out}/index.ts`), indexFileText);
writeFile(path.normalize(`${options.out}/${fileName}`), fileText);
indexFileText = indexFileText + `export * from './${key}';\n`;
} else {
console.log(`${fileName}:`);
console.log(fileText);
console.log();
}
}
return true;
// dump index file
if (options.out) {
writeFile(path.normalize(`${options.out}/index.ts`), indexFileText);
}
return true;
};
creatModelTSFiles().then(() => {
console.log('Done.');
creatModelTSFiles().then(() => {
console.log('Done.');
});
#!/usr/bin/env node
import { Command } from "commander";
import { load, dump } from "js-yaml";
import { readFile, writeFile, readdir } from "fs/promises";
import path from "path";
import { Command } from 'commander';
import { load, dump } from 'js-yaml';
import { readFile, writeFile, readdir } from 'fs/promises';
import path from 'path';

@@ -13,16 +13,16 @@ /**

program
.version("0.0.11")
.description("Convert CRDs to OpenAPI file")
.option("-i, --in <dir>", "Input directory path - required")
.option("-o, --out <file>", "Output file name")
.option("-t, --title <text>", "Module title")
.option("-d, --description <text>", "Module description")
.option("-l, --license <text>", "Module license")
.option("-m, --match <text>", "match files regexp")
.option("--licenseURL <text>", "Module license link")
.option("--contactName <text>", "Module contact name")
.option("--contactEmail <text>", "Module contact email")
.option("--contactURL <text>", "Module contact link")
.option("--apiVersion <text>", "Module API version")
.option("-j, --json", "output as json")
.version('0.0.12')
.description('Convert CRDs to OpenAPI file')
.option('-i, --in <dir>', 'Input directory path - required')
.option('-o, --out <file>', 'Output file name')
.option('-t, --title <text>', 'Module title')
.option('-d, --description <text>', 'Module description')
.option('-l, --license <text>', 'Module license')
.option('-m, --match <text>', 'match files regexp')
.option('--licenseURL <text>', 'Module license link')
.option('--contactName <text>', 'Module contact name')
.option('--contactEmail <text>', 'Module contact email')
.option('--contactURL <text>', 'Module contact link')
.option('--apiVersion <text>', 'Module API version')
.option('-j, --json', 'output as json')
.parse(process.argv);

@@ -33,4 +33,4 @@

if (!options.in) {
console.log("error: missing mandatory argument --in");
process.exit(1);
console.log('error: missing mandatory argument --in');
process.exit(1);
}

@@ -40,33 +40,33 @@

if (options.match) {
regexpMath = new RegExp(options.match);
regexpMath = new RegExp(options.match);
}
type License = "Apache-2.0" | "BSD-3" | "BSD-2" | "GPL-3.0" | "GPL-2.0" | "MIT" | "MPL" | "ISC";
type Schemas = { [id: string] : Record<string, unknown>; };
type License = 'Apache-2.0' | 'BSD-3' | 'BSD-2' | 'GPL-3.0' | 'GPL-2.0' | 'MIT' | 'MPL' | 'ISC';
type Schemas = { [id: string]: Record<string, unknown> };
interface CustomResourceDefinitions {
spec: {
group: string;
names: {
kind: string;
};
scope: string;
versions: {
name: string;
schema: {
openAPIV3Schema: Record<string, unknown>;
};
}[];
spec: {
group: string;
names: {
kind: string;
};
scope: string;
versions: {
name: string;
schema: {
openAPIV3Schema: Record<string, unknown>;
};
}[];
};
}
const licenses: { [id in License] : string; } = {
"Apache-2.0": "http://www.apache.org/licenses/",
"BSD-3": "https://opensource.org/licenses/BSD-3-Clause",
"BSD-2": "https://opensource.org/licenses/BSD-2-Clause",
"GPL-3.0": "www.gnu.org/licenses/gpl-3.0.en.html",
"GPL-2.0": "www.gnu.org/licenses/gpl-2.0.en.html",
"MIT": "https://opensource.org/licenses/MIT",
"MPL": "https://opensource.org/licenses/MPL-2.0",
"ISC": "https://www.isc.org/licenses/",
const licenses: { [id in License]: string } = {
'Apache-2.0': 'http://www.apache.org/licenses/',
'BSD-3': 'https://opensource.org/licenses/BSD-3-Clause',
'BSD-2': 'https://opensource.org/licenses/BSD-2-Clause',
'GPL-3.0': 'www.gnu.org/licenses/gpl-3.0.en.html',
'GPL-2.0': 'www.gnu.org/licenses/gpl-2.0.en.html',
MIT: 'https://opensource.org/licenses/MIT',
MPL: 'https://opensource.org/licenses/MPL-2.0',
ISC: 'https://www.isc.org/licenses/',
};

@@ -79,3 +79,3 @@

* Read one CRD file
*
*
* @param filePath is the CRD file to read

@@ -85,23 +85,23 @@ * @returns a dictionary with all the schemas objects by kind and version

const readSchema = async (filePath: string): Promise<Schemas> => {
const schemas: Schemas = {};
const schemas: Schemas = {};
try {
const yaml = load(await readFile(filePath, "utf8")) as CustomResourceDefinitions;
yaml.spec.versions.forEach((version) => {
const name = `${version.name}${yaml.spec.names.kind}`;
try {
const yaml = load(await readFile(filePath, 'utf8')) as CustomResourceDefinitions;
schemas[name] = version.schema.openAPIV3Schema;
});
} catch (error) {
console.log(`error occurr ed while reading input file (${error})`);
process.exit(1);
}
yaml.spec.versions.forEach((version) => {
const name = `${version.name}${yaml.spec.names.kind}`;
return schemas;
}
schemas[name] = version.schema.openAPIV3Schema;
});
} catch (error) {
console.log(`error occurr ed while reading input file (${error})`);
process.exit(1);
}
return schemas;
};
/**
* Read all CRD files in a directory
*
*
* @param dirPath is the directory to read

@@ -111,24 +111,24 @@ * @returns a dictionary with all the schemas objects by kind and version

const readSchemaDir = async (dirPath: string): Promise<Schemas> => {
let schemas: Schemas = {};
let schemas: Schemas = {};
try {
const files = await readdir(dirPath);
try {
const files = await readdir(dirPath);
for (const file of files) {
// If file don't match pattern, continue.
if (regexpMath && file.match(regexpMath) === null) {
continue;
}
for (const file of files) {
// If file don't match pattern, continue.
if (regexpMath && file.match(regexpMath) === null) {
continue;
}
const filePath = path.join(dirPath, file);
const filePath = path.join(dirPath, file);
const data = await readSchema(filePath);
schemas = Object.assign({}, schemas, data );
}
} catch (error) {
console.log(`error occurr ed while reading the input directory (${error})`);
process.exit(1);
const data = await readSchema(filePath);
schemas = Object.assign({}, schemas, data);
}
} catch (error) {
console.log(`error occurr ed while reading the input directory (${error})`);
process.exit(1);
}
return schemas;
return schemas;
};

@@ -139,40 +139,40 @@

* Use global CLI options as input
*
*
* @returns Promise<string>
*/
const createOpenAPIFile = async (): Promise<string> => {
const data = await readSchemaDir(options.in);
const data = await readSchemaDir(options.in);
const out = {
openapi: "3.1.0",
info: {
description: options.description,
title: options.title,
version: options.apiVersion,
contact: {
url: options.contactURL,
email: options.contactEmail,
}
},
license: {
name: options.license,
url: licenseURL,
},
components: {
schemas: data,
},
};
const out = {
openapi: '3.1.0',
info: {
description: options.description,
title: options.title,
version: options.apiVersion,
contact: {
url: options.contactURL,
email: options.contactEmail,
},
license: {
name: options.license,
url: licenseURL,
},
},
components: {
schemas: data,
},
};
if (options.json) {
return JSON.stringify(out);
}
return dump(out);
if (options.json) {
return JSON.stringify(out);
}
return dump(out);
};
createOpenAPIFile().then((outString) => {
if (options.out) {
writeFile(options.out, outString);
} else {
console.log(outString);
}
createOpenAPIFile().then((outString) => {
if (options.out) {
writeFile(options.out, outString);
} else {
console.log(outString);
}
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc