diff --git a/.gitattributes b/.gitattributes index 26eb69c228..d00f1cfd41 100644 --- a/.gitattributes +++ b/.gitattributes @@ -234,5 +234,6 @@ dist/* binary output/** linguist-generated=true output/schema/validation-errors.json linguist-generated=false +compiler-rs/compiler-wasm-lib/pkg/* linguist-generated=true #################################################################################################### diff --git a/Makefile b/Makefile index 4a89371e39..9cde11d7e6 100644 --- a/Makefile +++ b/Makefile @@ -49,10 +49,11 @@ transform-expand-generics: ## Create a new schema with all generics expanded @npm run transform-expand-generics --prefix compiler transform-to-openapi: ## Generate the OpenAPI definition from the compiled schema - @npm run transform-to-openapi --prefix compiler + @npm run transform-to-openapi -- --schema output/schema/schema.json --flavor stack --output output/openapi/elasticsearch-openapi.json + @npm run transform-to-openapi -- --schema output/schema/schema.json --flavor serverless --output output/openapi/elasticsearch-serverless-openapi.json filter-for-serverless: ## Generate the serverless version from the compiled schema - @npm run --prefix compiler filter-by-availability -- --serverless --visibility=public --input ../output/schema/schema.json --output ../output/schema/schema-serverless.json + @npm run --prefix compiler filter-by-availability -- --serverless --visibility=public --input ../output/schema/schema.json --output ../output/output/openapi/elasticsearch-serverless-openapi.json dump-routes: ## Create a new schema with all generics expanded @npm run dump-routes --prefix compiler diff --git a/compiler-rs/Cargo.lock b/compiler-rs/Cargo.lock index 949680ee91..bb56551417 100644 --- a/compiler-rs/Cargo.lock +++ b/compiler-rs/Cargo.lock @@ -91,6 +91,38 @@ dependencies = [ "serde", ] +[[package]] +name = "argh" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ff18325c8a36b82f992e533ece1ec9f9a9db446bd1c14d4f936bac88fcd240" +dependencies = [ + "argh_derive", + "argh_shared", + "rust-fuzzy-search", +] + +[[package]] +name = "argh_derive" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b2b83a50d329d5d8ccc620f5c7064028828538bdf5646acd60dc1f767803" +dependencies = [ + "argh_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "argh_shared" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a464143cc82dedcdc3928737445362466b7674b5db4e2eb8e869846d6d84f4f6" +dependencies = [ + "serde", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -192,7 +224,7 @@ dependencies = [ "anyhow", "arcstr", "clap", - "derive_more", + "derive_more 1.0.0", "indexmap", "itertools", "once_cell", @@ -208,8 +240,9 @@ name = "clients_schema_to_openapi" version = "0.1.0" dependencies = [ "anyhow", - "clap", + "argh", "clients_schema", + "derive_more 2.0.1", "icu_segmenter", "indexmap", "openapiv3", @@ -230,6 +263,7 @@ name = "compiler-wasm-lib" version = "0.1.0" dependencies = [ "anyhow", + "argh", "clients_schema", "clients_schema_to_openapi", "console_error_panic_hook", @@ -283,7 +317,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl 2.0.1", ] [[package]] @@ -297,6 +340,17 @@ dependencies = [ "syn", ] +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -905,6 +959,12 @@ dependencies = [ "vrd 0.0.7", ] +[[package]] +name = "rust-fuzzy-search" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2" + [[package]] name = "rustc-demangle" version = "0.1.24" diff --git a/compiler-rs/Cargo.toml b/compiler-rs/Cargo.toml index 294ac02bc0..7644c40d1c 100644 --- a/compiler-rs/Cargo.toml +++ b/compiler-rs/Cargo.toml @@ -10,6 +10,7 @@ members = [ [workspace.dependencies] anyhow = "1" arcstr = "1" +argh = "0.1" clap = "4" console_error_panic_hook = "0.1" convert_case = "0.6" diff --git a/compiler-rs/clients_schema_to_openapi/Cargo.toml b/compiler-rs/clients_schema_to_openapi/Cargo.toml index 7b82fa0bc5..5277450797 100644 --- a/compiler-rs/clients_schema_to_openapi/Cargo.toml +++ b/compiler-rs/clients_schema_to_openapi/Cargo.toml @@ -7,6 +7,8 @@ publish = false [dependencies] clients_schema = {path="../clients_schema"} +argh = { workspace = true } +derive_more = { version = "2", features = ["from_str"] } serde_json = { workspace = true } serde_ignored = { workspace = true } icu_segmenter = { workspace = true } @@ -16,5 +18,3 @@ indexmap = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true } -clap = { workspace = true, features = ["derive"] } - diff --git a/compiler-rs/clients_schema_to_openapi/src/cli.rs b/compiler-rs/clients_schema_to_openapi/src/cli.rs new file mode 100644 index 0000000000..b7a53eaea7 --- /dev/null +++ b/compiler-rs/clients_schema_to_openapi/src/cli.rs @@ -0,0 +1,62 @@ +use std::path::PathBuf; +use argh::FromArgs; +use clients_schema::Flavor; +use crate::Configuration; + +/// Convert schema.json to an OpenAPI schema +#[derive(Debug, FromArgs)] +pub struct Cli { + /// schema file to transform. + #[argh(option)] + pub schema: PathBuf, + + /// output file. + #[argh(option)] + pub output: PathBuf, + + //---- Fields from lib::Configuration + + /// the flavor to generate [all, stack, serverless - default = all] + #[argh(option, default = "SchemaFlavor::All")] + pub flavor: SchemaFlavor, + + /// add enum descriptions to property descriptions [default = true] + #[argh(option, default = "true")] + pub lift_enum_descriptions: bool, + + /// generate only this namespace (can be repeated) + #[argh(option)] + pub namespace: Vec, +} + +use derive_more::FromStr; + +#[derive(Debug, Clone, PartialEq, FromStr)] +pub enum SchemaFlavor { + /// No schema filtering + All, + /// Stack (stateful) flavor + Stack, + /// Serverless flavor + Serverless, +} + +impl From for Configuration { + fn from(val: Cli) -> Configuration { + let flavor = match val.flavor { + SchemaFlavor::All => None, + SchemaFlavor::Serverless => Some(Flavor::Serverless), + SchemaFlavor::Stack => Some(Flavor::Stack), + }; + + Configuration { + flavor, + lift_enum_descriptions: val.lift_enum_descriptions, + namespaces: if val.namespace.is_empty() { + None + } else { + Some(val.namespace) + }, + } + } +} diff --git a/compiler-rs/clients_schema_to_openapi/src/lib.rs b/compiler-rs/clients_schema_to_openapi/src/lib.rs index 34bbd5cf30..3fe4bb03e1 100644 --- a/compiler-rs/clients_schema_to_openapi/src/lib.rs +++ b/compiler-rs/clients_schema_to_openapi/src/lib.rs @@ -19,6 +19,7 @@ mod components; mod paths; mod schemas; mod utils; +pub mod cli; use indexmap::IndexMap; @@ -29,18 +30,10 @@ use crate::components::TypesAndComponents; pub struct Configuration { pub flavor: Option, + pub namespaces: Option>, pub lift_enum_descriptions: bool, } -impl Default for Configuration { - fn default() -> Self { - Self { - flavor: None, - lift_enum_descriptions: true, - } - } -} - /// Convert an API model into an OpenAPI v3 schema, optionally filtered for a given flavor pub fn convert_schema(mut schema: IndexedModel, config: Configuration) -> anyhow::Result { // Expand generics @@ -105,6 +98,11 @@ pub fn convert_expanded_schema(model: &IndexedModel, config: &Configuration) -> // Endpoints for endpoint in &model.endpoints { + if let Some(namespaces) = &config.namespaces { + if !namespaces.contains(&endpoint.name) { + continue; + } + } paths::add_endpoint(endpoint, &mut tac, &mut openapi.paths)?; } diff --git a/compiler-rs/clients_schema_to_openapi/src/main.rs b/compiler-rs/clients_schema_to_openapi/src/main.rs index 2cf3193172..1df140395a 100644 --- a/compiler-rs/clients_schema_to_openapi/src/main.rs +++ b/compiler-rs/clients_schema_to_openapi/src/main.rs @@ -15,18 +15,15 @@ // specific language governing permissions and limitations // under the License. -use std::path::{Path, PathBuf}; -use anyhow::bail; - -use clap::{Parser, ValueEnum}; -use clients_schema::Flavor; +use std::fs::File; +use clients_schema::IndexedModel; use tracing::Level; use tracing_subscriber::fmt::format::FmtSpan; use tracing_subscriber::FmtSubscriber; -use clients_schema_to_openapi::Configuration; +use clients_schema_to_openapi::cli::Cli; fn main() -> anyhow::Result<()> { - let cli = Cli::parse(); + let cli: Cli = argh::from_env(); let subscriber = FmtSubscriber::builder() .with_writer(std::io::stderr) @@ -35,139 +32,9 @@ fn main() -> anyhow::Result<()> { .finish(); tracing::subscriber::set_global_default(subscriber)?; - cli.run()?; - + let schema = IndexedModel::from_reader(File::open(&cli.schema)?)?; + let output = cli.output.clone(); + let openapi = clients_schema_to_openapi::convert_schema(schema, cli.into())?; + serde_json::to_writer_pretty(File::create(&output)?, &openapi)?; Ok(()) } - -// fn main() -> anyhow::Result<()> { -// -// let subscriber = FmtSubscriber::builder() -// .with_writer(std::io::stderr) -// .with_max_level(Level::TRACE) -// .with_span_events(FmtSpan::EXIT) -// .finish(); -// tracing::subscriber::set_global_default(subscriber)?; -// -// clients_schema_to_openapi::convert_schema_file( -// "../output/schema/schema-no-generics.json", -// None, -// |e| true, -// //|e| e.name == "search", -// //|e| e.name == "clear_scroll", -// //|e| e.name.starts_with("indices."), -// //|e| e.name == "indices.exists_alias" || e.name == "indices.delete_alias", -// //|e| &e.name[0..1] < "d", -// std::fs::File::create("../output/openapi/elasticsearch-openapi.json")? -// //std::io::stdout() -// )?; -// -// Ok(()) -// } - -impl Cli { - fn run(self) -> anyhow::Result<()> { - let json = if self.schema == Path::new("-") { - std::io::read_to_string(std::io::stdin())? - } else { - std::fs::read_to_string(self.schema)? - }; - - let model: clients_schema::IndexedModel = match serde_json::from_str(&json) { - Ok(indexed_model) => indexed_model, - Err(e) => bail!("cannot parse schema json: {}", e) - }; - - let flavor = match self.flavor { - Some(SchemaFlavor::All) | None => None, - Some(SchemaFlavor::Stack) => Some(Flavor::Stack), - Some(SchemaFlavor::Serverless) => Some(Flavor::Serverless), - }; - - let config = Configuration { - flavor, - ..Default::default() - }; - - let openapi = clients_schema_to_openapi::convert_schema(model, config)?; - - let output: Box = { - if let Some(output) = self.output { - if output == Path::new("-") { - Box::new(std::io::stdout()) - } else { - Box::new(std::fs::File::create(output)?) - } - } else { - Box::new(std::io::stdout()) - } - }; - let output = std::io::BufWriter::new(output); - - serde_json::to_writer_pretty(output, &openapi)?; - - Ok(()) - } -} - -#[derive(Debug, Parser)] -#[command(author, version, about, long_about = None)] -pub struct Cli { - /// Schema file to transform. Use '-' for stdin. - schema: PathBuf, - - #[arg(short, long)] - /// Output file. Defaults to stdout. - output: Option, - - /// Elasticsearch flavor to produce - #[arg(short, long)] - flavor: Option, -} - -#[derive(Debug, Clone, PartialEq, ValueEnum)] -pub enum SchemaFlavor { - /// No schema filtering - All, - /// Stack (stateful) flavor - Stack, - /// Serverless flavor - Serverless, - // /// Common subset to Stack and Serverless - // Common, -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_full() -> anyhow::Result<()> { - Cli { - schema: "../../output/schema/schema-no-generics.json".into(), - flavor: None, - output: Some("../../output/openapi/elasticsearch-openapi.json".into()), - } - .run() - } - - #[test] - fn test_serverless() -> anyhow::Result<()> { - Cli { - schema: "../../output/schema/schema-no-generics.json".into(), - flavor: Some(SchemaFlavor::Serverless), - output: Some("../../output/openapi/elasticsearch-serverless-openapi.json".into()), - } - .run() - } - - #[test] - fn test_serverless0() -> anyhow::Result<()> { - Cli { - schema: "../../output/schema/schema.json".into(), - flavor: Some(SchemaFlavor::Serverless), - output: Some("../../output/openapi/elasticsearch-serverless-openapi2.json".into()), - } - .run() - } -} diff --git a/compiler-rs/clients_schema_to_openapi/src/paths.rs b/compiler-rs/clients_schema_to_openapi/src/paths.rs index 22cf4f7a4d..391402077a 100644 --- a/compiler-rs/clients_schema_to_openapi/src/paths.rs +++ b/compiler-rs/clients_schema_to_openapi/src/paths.rs @@ -385,7 +385,7 @@ fn split_summary_desc(desc: &str) -> SplitDesc{ let segmenter = SentenceSegmenter::new(); let breakpoints: Vec = segmenter - .segment_str(&desc) + .segment_str(desc) .collect(); if breakpoints.len()<2{ diff --git a/compiler-rs/clients_schema_to_openapi/src/schemas.rs b/compiler-rs/clients_schema_to_openapi/src/schemas.rs index d7c47fabf0..9d4ebe5b4f 100644 --- a/compiler-rs/clients_schema_to_openapi/src/schemas.rs +++ b/compiler-rs/clients_schema_to_openapi/src/schemas.rs @@ -481,7 +481,7 @@ impl<'a> TypesAndComponents<'a> { pub fn property_description(&self, prop: &Property) -> anyhow::Result> { if self.config.lift_enum_descriptions { - Ok(lift_enum_descriptions(prop, &self.model)?.or_else(|| prop.description.clone())) + Ok(lift_enum_descriptions(prop, self.model)?.or_else(|| prop.description.clone())) } else { Ok(prop.description.clone()) } diff --git a/compiler-rs/compiler-wasm-lib/Cargo.toml b/compiler-rs/compiler-wasm-lib/Cargo.toml index 3d162ddf8c..23dd68d683 100644 --- a/compiler-rs/compiler-wasm-lib/Cargo.toml +++ b/compiler-rs/compiler-wasm-lib/Cargo.toml @@ -18,6 +18,7 @@ clients_schema_to_openapi = {path="../clients_schema_to_openapi"} serde_json = { workspace = true } anyhow = { workspace = true } tracing = "0.1" +argh = { workspace = true } console_error_panic_hook = { workspace = true, optional = true } tracing-wasm = "0.2.1" diff --git a/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.d.ts b/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.d.ts index a6545ee4ce..f0efbe39dd 100644 --- a/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.d.ts +++ b/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.d.ts @@ -1,3 +1,7 @@ /* tslint:disable */ /* eslint-disable */ -export function convert_schema_to_openapi(json: string, flavor: string): string; +/** + * Convert schema.json to OpenAPI. The `cwd` argument is the current directory to be used + * if not the system-defined one, as is the case when running with `npm rum --prefix compiler` + */ +export function convert_schema_to_openapi(args: string[], cwd?: string | null): void; diff --git a/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.js b/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.js index 178f4dd87f..1264153823 100644 --- a/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.js +++ b/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib.js @@ -2,6 +2,7 @@ let imports = {}; imports['__wbindgen_placeholder__'] = module.exports; let wasm; +const { readFileSync, writeFileSync } = require(`node:fs`); const { TextDecoder, TextEncoder } = require(`util`); let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); @@ -102,36 +103,39 @@ function getDataViewMemory0() { return cachedDataViewMemory0; } +function isLikeNone(x) { + return x === undefined || x === null; +} + +function passArrayJsValueToWasm0(array, malloc) { + const ptr = malloc(array.length * 4, 4) >>> 0; + for (let i = 0; i < array.length; i++) { + const add = addToExternrefTable0(array[i]); + getDataViewMemory0().setUint32(ptr + 4 * i, add, true); + } + WASM_VECTOR_LEN = array.length; + return ptr; +} + function takeFromExternrefTable0(idx) { const value = wasm.__wbindgen_export_3.get(idx); wasm.__externref_table_dealloc(idx); return value; } /** - * @param {string} json - * @param {string} flavor - * @returns {string} + * Convert schema.json to OpenAPI. The `cwd` argument is the current directory to be used + * if not the system-defined one, as is the case when running with `npm rum --prefix compiler` + * @param {string[]} args + * @param {string | null} [cwd] */ -module.exports.convert_schema_to_openapi = function(json, flavor) { - let deferred4_0; - let deferred4_1; - try { - const ptr0 = passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len0 = WASM_VECTOR_LEN; - const ptr1 = passStringToWasm0(flavor, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - const ret = wasm.convert_schema_to_openapi(ptr0, len0, ptr1, len1); - var ptr3 = ret[0]; - var len3 = ret[1]; - if (ret[3]) { - ptr3 = 0; len3 = 0; - throw takeFromExternrefTable0(ret[2]); - } - deferred4_0 = ptr3; - deferred4_1 = len3; - return getStringFromWasm0(ptr3, len3); - } finally { - wasm.__wbindgen_free(deferred4_0, deferred4_1, 1); +module.exports.convert_schema_to_openapi = function(args, cwd) { + const ptr0 = passArrayJsValueToWasm0(args, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + var ptr1 = isLikeNone(cwd) ? 0 : passStringToWasm0(cwd, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + const ret = wasm.convert_schema_to_openapi(ptr0, len0, ptr1, len1); + if (ret[1]) { + throw takeFromExternrefTable0(ret[0]); } }; @@ -197,6 +201,14 @@ module.exports.__wbg_new_8a6f238a6ece86ea = function() { return ret; }; +module.exports.__wbg_readFileSync_691af69453e7d4ec = function(arg0, arg1, arg2, arg3, arg4) { + const ret = readFileSync(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); +}; + module.exports.__wbg_stack_0ed75d68575b0f3c = function(arg0, arg1) { const ret = arg1.stack; const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); @@ -205,6 +217,10 @@ module.exports.__wbg_stack_0ed75d68575b0f3c = function(arg0, arg1) { getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); }; +module.exports.__wbg_writeFileSync_d2c5ed0808e00dc9 = function(arg0, arg1, arg2, arg3) { + writeFileSync(getStringFromWasm0(arg0, arg1), getStringFromWasm0(arg2, arg3)); +}; + module.exports.__wbindgen_init_externref_table = function() { const table = wasm.__wbindgen_export_3; const offset = table.grow(4); @@ -216,11 +232,24 @@ module.exports.__wbindgen_init_externref_table = function() { ; }; +module.exports.__wbindgen_string_get = function(arg0, arg1) { + const obj = arg1; + const ret = typeof(obj) === 'string' ? obj : undefined; + var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); +}; + module.exports.__wbindgen_string_new = function(arg0, arg1) { const ret = getStringFromWasm0(arg0, arg1); return ret; }; +module.exports.__wbindgen_throw = function(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); +}; + const path = require('path').join(__dirname, 'compiler_wasm_lib_bg.wasm'); const bytes = require('fs').readFileSync(path); diff --git a/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm b/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm index 898e7ef0dd..7e232853fb 100644 Binary files a/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm and b/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm differ diff --git a/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm.d.ts b/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm.d.ts index 781fb0e13a..2d4f44aee3 100644 --- a/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm.d.ts +++ b/compiler-rs/compiler-wasm-lib/pkg/compiler_wasm_lib_bg.wasm.d.ts @@ -1,7 +1,7 @@ /* tslint:disable */ /* eslint-disable */ export const memory: WebAssembly.Memory; -export const convert_schema_to_openapi: (a: number, b: number, c: number, d: number) => [number, number, number, number]; +export const convert_schema_to_openapi: (a: number, b: number, c: number, d: number) => [number, number]; export const __wbindgen_free: (a: number, b: number, c: number) => void; export const __wbindgen_exn_store: (a: number) => void; export const __externref_table_alloc: () => number; diff --git a/compiler-rs/compiler-wasm-lib/src/lib.rs b/compiler-rs/compiler-wasm-lib/src/lib.rs index 62ed5d3987..08245c18c4 100644 --- a/compiler-rs/compiler-wasm-lib/src/lib.rs +++ b/compiler-rs/compiler-wasm-lib/src/lib.rs @@ -15,33 +15,59 @@ // specific language governing permissions and limitations // under the License. -use anyhow::bail; -use clients_schema::{Flavor, IndexedModel}; +use std::path::PathBuf; +use argh::FromArgs; +use clients_schema::IndexedModel; use wasm_bindgen::prelude::*; -use clients_schema_to_openapi::Configuration; +use clients_schema_to_openapi::cli::Cli; +/// Minimal bindings to Node's `fs` module. +mod node_fs { + use wasm_bindgen::prelude::*; + + #[wasm_bindgen(module = "node:fs")] + extern "C" { + #[wasm_bindgen(js_name = "readFileSync")] + pub fn read_file_sync_to_string(path: &str, encoding: &str) -> String; + + #[wasm_bindgen(js_name = "writeFileSync")] + pub fn write_file_sync(path: &str, content: &str); + + #[wasm_bindgen(js_name = "readdirSync")] + pub fn read_dir_sync(path: &str) -> Vec; + } +} + +/// Convert schema.json to OpenAPI. The `cwd` argument is the current directory to be used +/// if not the system-defined one, as is the case when running with `npm rum --prefix compiler` #[wasm_bindgen] -pub fn convert_schema_to_openapi(json: &str, flavor: &str) -> Result { +pub fn convert_schema_to_openapi(args: Vec, cwd: Option) -> Result<(), String> { setup_hooks(); - convert0(json, flavor).map_err(|err| err.to_string()) + + let args = args.iter().map(String::as_str).collect::>(); + let cli = Cli::from_args(&["schema-to-openapi"], &args).map_err(|err| err.output)?; + convert0(cli, cwd).map_err(|err| err.to_string()) } -fn convert0(json: &str, flavor: &str) -> anyhow::Result { - let flavor = match flavor { - "all" => None, - "stack" => Some(Flavor::Stack), - "serverless" => Some(Flavor::Serverless), - _ => bail!("Unknown flavor {}", flavor), +pub fn convert0(cli: Cli, cwd: Option) -> anyhow::Result<()> { + let input = match cwd { + Some(ref cwd) => PathBuf::from(cwd).join(&cli.schema), + None => cli.schema.clone(), }; - let config = Configuration { - flavor, - ..Default::default() + let output = match cwd { + Some(ref cwd) => PathBuf::from(cwd).join(&cli.output), + None => cli.output.clone(), }; + + let json = node_fs::read_file_sync_to_string(&input.to_string_lossy(), "utf8"); let schema = IndexedModel::from_reader(json.as_bytes())?; - let openapi = clients_schema_to_openapi::convert_schema(schema, config)?; + + let openapi = clients_schema_to_openapi::convert_schema(schema, cli.into())?; + let result = serde_json::to_string_pretty(&openapi)?; - Ok(result) + node_fs::write_file_sync(&output.to_string_lossy(), &result); + Ok(()) } pub fn setup_hooks() { diff --git a/compiler/src/transform/schema-to-openapi.ts b/compiler/src/transform/schema-to-openapi.ts index 0f3dae3e72..ddb1e5eea1 100644 --- a/compiler/src/transform/schema-to-openapi.ts +++ b/compiler/src/transform/schema-to-openapi.ts @@ -18,30 +18,12 @@ */ import { convert_schema_to_openapi } from 'compiler-wasm-lib' -import { argv } from 'zx' -import { join } from 'path' -import { readFileSync, writeFileSync } from 'fs' -const inputPath = argv.input ?? join(__dirname, '..', '..', '..', 'output', 'schema', 'schema.json') -const outputPath = argv.output ?? join(__dirname, '..', '..', '..', 'output', 'openapi', 'elasticsearch-serverless-openapi.json') -const outputPathStack = argv.output ?? join(__dirname, '..', '..', '..', 'output', 'openapi', 'elasticsearch-openapi.json') +// Remove the 2 first args ("ts-node", "schema-to-openapi.ts") +const realArgs = process.argv.slice(2) -const inputText = readFileSync( - inputPath, - { encoding: 'utf8' } -) - -const output = convert_schema_to_openapi(inputText, 'serverless') -const outputStack = convert_schema_to_openapi(inputText, 'stack') - -writeFileSync( - outputPath, - output, - 'utf8' -) - -writeFileSync( - outputPathStack, - outputStack, - 'utf8' -) +try { + convert_schema_to_openapi(realArgs, '..') +} catch (e) { + console.log(e) +} diff --git a/package.json b/package.json index 65aafaa259..c1e9575f41 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,7 @@ { + "scripts": { + "transform-to-openapi": "npm run transform-to-openapi --prefix compiler --" + }, "dependencies": { "@redocly/cli": "^1.34.1", "@stoplight/spectral-cli": "^6.14.2"