haveapi-typescript-client 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +204 -0
- data/Rakefile +8 -0
- data/bin/haveapi-typescript-client +5 -0
- data/docs/documentation.md +104 -0
- data/haveapi-typescript-client.gemspec +18 -0
- data/lib/haveapi/typescript_client/cli.rb +41 -0
- data/lib/haveapi/typescript_client/documentation.rb +316 -0
- data/lib/haveapi/typescript_client/emitter.rb +239 -0
- data/lib/haveapi/typescript_client/generator.rb +176 -0
- data/lib/haveapi/typescript_client/ir.rb +202 -0
- data/lib/haveapi/typescript_client/naming.rb +38 -0
- data/lib/haveapi/typescript_client/snapshot.rb +32 -0
- data/lib/haveapi/typescript_client/version.rb +5 -0
- data/lib/haveapi/typescript_client.rb +12 -0
- data/template/action.ts.erb +13 -0
- data/template/api.ts.erb +28 -0
- data/template/index.ts.erb +3 -0
- data/template/resource.ts.erb +30 -0
- data/template/runtime.ts.erb +169 -0
- data/template/types.ts.erb +4 -0
- metadata +73 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b186bae5d9688166db1bc7d4f2c364e6731a513b45216d89f2043cb0574bce53
|
|
4
|
+
data.tar.gz: cfb2abb678d80782680f9faadf8f251e438398be33d7bfddda0c4d5181e76f8c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b5ef31267e2c521a419835232fce76a35f5f9201d74c5d80f8d2a3fbac1d06edf7c29c02830f2362d5a080f28ef4a32561f5d4529de7091bac61578f98e838d2
|
|
7
|
+
data.tar.gz: ffd998fad046255884700004a42673b1389e60d1d651b61945f051c25f3910e33d76b97583bedd8489b2fa4926e1981204be83476e9f6136ec3887b79050d40c
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Jakub Skokan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# TypeScript client generator
|
|
2
|
+
|
|
3
|
+
Generate a typed TypeScript client for one API version from a saved HaveAPI
|
|
4
|
+
protocol 2 schema. Call resources and actions by name, with types for their
|
|
5
|
+
arguments and results. A request executor connects those calls to the existing
|
|
6
|
+
`haveapi-client` runtime or your application's adapter.
|
|
7
|
+
|
|
8
|
+
## Install the generator
|
|
9
|
+
|
|
10
|
+
The generator is packaged as the Ruby gem `haveapi-typescript-client`. Once a
|
|
11
|
+
release containing the generator and shared schema API is available, install it
|
|
12
|
+
with:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
gem install haveapi-typescript-client
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The packaged command is `haveapi-typescript-client`; it accepts the same `fetch`
|
|
19
|
+
and `generate` arguments shown below. Its Ruby `haveapi-client` dependency must
|
|
20
|
+
contain the shared schema API. An older gem in the same version range is not
|
|
21
|
+
sufficient. For unreleased development source, use the checkout setup below.
|
|
22
|
+
See the [release guide](../../doc/agent-instructions/releases.md) for coordinated
|
|
23
|
+
packaging and trusted-publisher setup.
|
|
24
|
+
|
|
25
|
+
## Prepare the source tools
|
|
26
|
+
|
|
27
|
+
The generator requires Ruby 3.2 or newer. From the HaveAPI checkout root:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
nix develop
|
|
31
|
+
BUNDLE_GEMFILE="$PWD/clients/typescript/Gemfile" bundle install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The component bundle uses the Ruby client from the same checkout. Record the
|
|
35
|
+
checkout revision and resolved dependency inputs. Generation reads local files
|
|
36
|
+
using the prepared dependencies and runs without contacting the API.
|
|
37
|
+
|
|
38
|
+
Applications need a TypeScript compiler and the `haveapi-client` JavaScript
|
|
39
|
+
runtime. The supported runtime version is exactly `0.30.2`.
|
|
40
|
+
|
|
41
|
+
## Fetch, save and generate
|
|
42
|
+
|
|
43
|
+
The example API at `https://example.test/api/v1.0/` has `Widget#Update` at
|
|
44
|
+
`/api/v1.0/widgets/{widget_id}`, a nullable string `name` input and an integer
|
|
45
|
+
`id` output. Replace the example URL, version and resource names with those of
|
|
46
|
+
your API.
|
|
47
|
+
|
|
48
|
+
From the HaveAPI root:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
mkdir -p /path/to/widget-client/schema
|
|
52
|
+
BUNDLE_GEMFILE="$PWD/clients/typescript/Gemfile" bundle exec ruby \
|
|
53
|
+
clients/typescript/bin/haveapi-typescript-client fetch https://example.test/api/v1.0/ \
|
|
54
|
+
--api-version 1.0 --profile public \
|
|
55
|
+
--output /path/to/widget-client/schema/api.json
|
|
56
|
+
BUNDLE_GEMFILE="$PWD/clients/typescript/Gemfile" bundle exec ruby \
|
|
57
|
+
clients/typescript/bin/haveapi-typescript-client generate \
|
|
58
|
+
--schema /path/to/widget-client/schema/api.json --api-version 1.0 \
|
|
59
|
+
--output /path/to/widget-client/src/generated
|
|
60
|
+
BUNDLE_GEMFILE="$PWD/clients/typescript/Gemfile" bundle exec ruby \
|
|
61
|
+
clients/typescript/bin/haveapi-typescript-client generate \
|
|
62
|
+
--schema /path/to/widget-client/schema/api.json --api-version 1.0 \
|
|
63
|
+
--output /path/to/widget-client/src/generated --check
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The saved schema's parent directory must already exist. Fetch uses the exact
|
|
67
|
+
version URL, including its mount prefix; it does not select a server default.
|
|
68
|
+
The explicit generation version must match the saved snapshot. `--check` reports
|
|
69
|
+
missing or stale output without changing it. Keep handwritten files outside
|
|
70
|
+
`src/generated`.
|
|
71
|
+
|
|
72
|
+
For Basic capture, set `WIDGET_PASSWORD` in your environment, then run:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
BUNDLE_GEMFILE="$PWD/clients/typescript/Gemfile" bundle exec ruby \
|
|
76
|
+
clients/typescript/bin/haveapi-typescript-client fetch https://example.test/api/v1.0/ \
|
|
77
|
+
--api-version 1.0 --profile basic-user --basic-user demo \
|
|
78
|
+
--basic-password-env WIDGET_PASSWORD \
|
|
79
|
+
--output /path/to/widget-client/schema/api.json
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
For an existing HaveAPI token, set `WIDGET_TOKEN` and run:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
BUNDLE_GEMFILE="$PWD/clients/typescript/Gemfile" bundle exec ruby \
|
|
86
|
+
clients/typescript/bin/haveapi-typescript-client fetch https://example.test/api/v1.0/ \
|
|
87
|
+
--api-version 1.0 --profile token-user --token-env WIDGET_TOKEN \
|
|
88
|
+
--output /path/to/widget-client/schema/api.json
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The two authentication choices are mutually exclusive. Token capture first reads
|
|
92
|
+
anonymous discovery at the same version endpoint, then uses the advertised token
|
|
93
|
+
header. Supply a token you have already acquired. `--profile` labels the capture;
|
|
94
|
+
it does not change authentication. Permissions and enabled plugins determine
|
|
95
|
+
which resources the snapshot contains. Failed capture preserves an existing
|
|
96
|
+
output file.
|
|
97
|
+
|
|
98
|
+
## Use the generated client
|
|
99
|
+
|
|
100
|
+
In the application containing the generated files, install the supported runtime
|
|
101
|
+
and a TypeScript compiler:
|
|
102
|
+
|
|
103
|
+
```sh
|
|
104
|
+
cd /path/to/widget-client
|
|
105
|
+
npm install --save-exact haveapi-client@0.30.2
|
|
106
|
+
npm install --save-dev typescript
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Import the local generated entry point:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { AsyncClient } from 'haveapi-client';
|
|
113
|
+
import { createClient } from './src/generated/index.js';
|
|
114
|
+
|
|
115
|
+
const runtime = new AsyncClient('https://example.test/api/v1.0');
|
|
116
|
+
const api = createClient({ execute: spec => runtime.request(spec) });
|
|
117
|
+
|
|
118
|
+
const result = await api.widget.update({
|
|
119
|
+
path: { widget_id: 1 },
|
|
120
|
+
params: { name: 'new name' },
|
|
121
|
+
});
|
|
122
|
+
console.log(result.data.id);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The executor's base URL includes the mount and API version. Do not add a
|
|
126
|
+
constructor version option: raw `request` calls already use this versioned base.
|
|
127
|
+
Configure authentication through the runtime or your application's adapter;
|
|
128
|
+
generated authentication actions are excluded and permissions still apply.
|
|
129
|
+
|
|
130
|
+
Pass action arguments in one options object: `path` for resource IDs, `params`
|
|
131
|
+
for input fields, and `meta` for metadata. The same object accepts request
|
|
132
|
+
headers, a timeout and an abort signal. Results contain typed `data`, metadata,
|
|
133
|
+
the response envelope and HTTP status. Runtime errors reject the promise.
|
|
134
|
+
Raw request results cannot be passed to
|
|
135
|
+
`AsyncClient.waitForCompletion`; see the
|
|
136
|
+
[JavaScript runtime guide](../js/README.md#advanced-usage-and-reference).
|
|
137
|
+
|
|
138
|
+
## Schemas and types
|
|
139
|
+
|
|
140
|
+
Input is a format 1 snapshot with `api_version`, `protocol_version` (major 2),
|
|
141
|
+
`source_url`, `profile`, `mount_path` and `description`. The description includes
|
|
142
|
+
application resources, authentication discovery, the metadata namespace and
|
|
143
|
+
versioned routes. The source URL records where the schema came from and is never
|
|
144
|
+
contacted during generation. See the
|
|
145
|
+
[snapshot reference](../../doc/agent-instructions/development.md#typescript-snapshots-and-provenance)
|
|
146
|
+
for the format and capture helper.
|
|
147
|
+
|
|
148
|
+
A snapshot covers the resources visible to its capture profile and plugins.
|
|
149
|
+
Server permissions and validation still apply when you call an action. Review
|
|
150
|
+
snapshots before sharing them; they must not contain credentials or tokens.
|
|
151
|
+
Unsupported schema shapes, unsafe routes and name collisions stop generation
|
|
152
|
+
before output is written. These include input lists, Custom IO formats and
|
|
153
|
+
GET/OPTIONS actions with object-input metadata.
|
|
154
|
+
|
|
155
|
+
- Omitted input fields stay omitted. Nullable `null`, `false`, zero and empty
|
|
156
|
+
strings are preserved. Numeric integers and path IDs must be JavaScript safe
|
|
157
|
+
integers; path strings are also supported. Datetime values remain strings.
|
|
158
|
+
- Custom body input accepts JSON. Custom query input accepts only scalars.
|
|
159
|
+
- Output fields can be absent or null; associations are partial records and
|
|
160
|
+
Custom output is `unknown`. Generated types do not validate response data.
|
|
161
|
+
|
|
162
|
+
## Generated files and regeneration
|
|
163
|
+
|
|
164
|
+
Browse resource and action types in their own modules:
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
src/generated/
|
|
168
|
+
index.ts
|
|
169
|
+
api.ts
|
|
170
|
+
runtime.ts
|
|
171
|
+
types.ts
|
|
172
|
+
resources/
|
|
173
|
+
widget/
|
|
174
|
+
resource.ts
|
|
175
|
+
actions/
|
|
176
|
+
update.ts
|
|
177
|
+
resources/
|
|
178
|
+
child/
|
|
179
|
+
resource.ts
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Import from `index.ts` in application code. Resource directories and action
|
|
183
|
+
filenames follow the generated accessor names; aliases share their canonical
|
|
184
|
+
action's module. Individual module paths are not stable package exports.
|
|
185
|
+
|
|
186
|
+
The generator owns the entire `src/generated` directory and records its files in
|
|
187
|
+
`.haveapi-generated.json`. Regeneration replaces owned files and removes stale
|
|
188
|
+
output, including nested directories. It refuses symlinks and foreign files.
|
|
189
|
+
Commit the whole generated tree and manifest together. Regenerate with the
|
|
190
|
+
recorded schema and HaveAPI revision, and keep that generator/client pair
|
|
191
|
+
together when reverting versions.
|
|
192
|
+
|
|
193
|
+
An interrupted write can leave mixed output. Restore the committed generated
|
|
194
|
+
tree before regenerating. If the first generation was interrupted before an
|
|
195
|
+
ownership manifest was written, preserve that partial directory and generate
|
|
196
|
+
into a fresh empty `src/generated`. Do not edit the manifest to bypass a refusal.
|
|
197
|
+
|
|
198
|
+
The Ruby server can render examples using this generated interface; see
|
|
199
|
+
[generated documentation profiles](docs/documentation.md).
|
|
200
|
+
|
|
201
|
+
## Development
|
|
202
|
+
|
|
203
|
+
See [generator development](../../doc/agent-instructions/development.md#typescript-generator)
|
|
204
|
+
for contributor setup, checks and implementation contracts.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Generated TypeScript documentation examples
|
|
2
|
+
|
|
3
|
+
The Ruby server can show examples for a generated TypeScript SDK alongside its
|
|
4
|
+
dynamic TypeScript clients. The generated examples use the SDK's public
|
|
5
|
+
`createClient` factory and `haveapi-client` version `0.30.2` for requests and
|
|
6
|
+
authentication. The server prepares the SDK model at mount time and renders
|
|
7
|
+
examples when users view the documentation.
|
|
8
|
+
|
|
9
|
+
## Configure the SDK profile
|
|
10
|
+
|
|
11
|
+
Register the profile for the same API version as the SDK:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
api.documentation_clients('1.0',
|
|
15
|
+
typescript: {
|
|
16
|
+
package_name: '@example/widget-client',
|
|
17
|
+
package_version: '1.2.3',
|
|
18
|
+
snapshot_path: '/absolute/path/to/widget-client/schema.json'
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
api.mount('/mount/')
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`package_name` is an ordinary scoped or unscoped npm package name.
|
|
25
|
+
`package_version` is optional and accepts a concrete SemVer, without ranges or
|
|
26
|
+
tags. Omitting it leaves package-version selection to the package manager; it
|
|
27
|
+
does not prove the package is available. Configure a package that users can
|
|
28
|
+
install through its supported distribution channel.
|
|
29
|
+
|
|
30
|
+
An optional `snapshot_path` selects the exact saved schema used for the SDK.
|
|
31
|
+
Without it, the server builds the adapter from its complete mounted declaration.
|
|
32
|
+
This private description excludes all defaults, prose and samples. An optional
|
|
33
|
+
`generator_version` must match the installed generator version.
|
|
34
|
+
|
|
35
|
+
The generator is an optional server dependency. Invalid profile fields, missing
|
|
36
|
+
generator code, unreadable or invalid snapshots and version mismatches reject
|
|
37
|
+
startup without publishing partial profiles. The profile accepts package identity,
|
|
38
|
+
snapshot and generator-version settings. Configure authentication in the client
|
|
39
|
+
runtime. Existing dynamic TypeScript examples remain separate.
|
|
40
|
+
|
|
41
|
+
## Rendered calls and compatibility
|
|
42
|
+
|
|
43
|
+
Examples bind the selected API version URL directly:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import {AsyncClient} from 'haveapi-client';
|
|
47
|
+
import {createClient} from '@example/widget-client';
|
|
48
|
+
|
|
49
|
+
const runtime = new AsyncClient('https://api.example.test/mount/v1.0');
|
|
50
|
+
const api = createClient({execute: spec => runtime.request(spec)});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The version and mount belong in the runtime's base URL. Its constructor `version`
|
|
54
|
+
option does not prefix raw requests. Public examples need no setup. Protected
|
|
55
|
+
examples use the runtime's Basic authentication or an existing HaveAPI token,
|
|
56
|
+
with credentials read from `HAVEAPI_USER`, `HAVEAPI_PASSWORD` or `HAVEAPI_TOKEN`.
|
|
57
|
+
Both the saved SDK and current authorized help must advertise the provider;
|
|
58
|
+
token header names must agree. Token acquisition, renewal and OAuth are outside
|
|
59
|
+
this adapter.
|
|
60
|
+
|
|
61
|
+
The adapter resolves names and aliases from a frozen SDK model. It then checks
|
|
62
|
+
the current user's help, action and filtered sample. Changed routes, methods,
|
|
63
|
+
versions, layouts, namespaces or used field contracts produce a limitation.
|
|
64
|
+
Hidden fields and defaults are not filled from the private model. Unrelated
|
|
65
|
+
optional additions do not prevent a compatible example.
|
|
66
|
+
|
|
67
|
+
Samples use the existing example DSL. Path arguments follow its declared order;
|
|
68
|
+
input wire names map to generated input names. The DSL has no separate input
|
|
69
|
+
metadata carrier, so actions requiring input metadata produce a limitation.
|
|
70
|
+
Inputs preserve omission, null, false, zero and empty strings. Unsafe integer IDs,
|
|
71
|
+
invalid JSON and structured Custom query values cannot be rendered. Output keys
|
|
72
|
+
remain wire names, with guards for optional, null and unknown values.
|
|
73
|
+
|
|
74
|
+
Successful examples retain `data`, `meta`, `envelope` and `httpStatus`. Rejection
|
|
75
|
+
examples inspect the runtime's error receipt without printing server diagnostics.
|
|
76
|
+
Requests are not retried. A successful request does not establish completion of
|
|
77
|
+
a server-side operation; raw receipts cannot be passed to `waitForCompletion`.
|
|
78
|
+
|
|
79
|
+
## Adapter and checks
|
|
80
|
+
|
|
81
|
+
The generator provides `HaveAPI::TypeScriptClient::Documentation` through
|
|
82
|
+
`require 'haveapi/typescript_client/documentation'`. Its factories accept a full
|
|
83
|
+
description or saved snapshot. `resolve` returns a frozen canonical action;
|
|
84
|
+
`render` returns the server's code or limitation result. Rendering performs no
|
|
85
|
+
file, network, generator or compiler work.
|
|
86
|
+
|
|
87
|
+
Focused unit checks compile the actual rendered programs against generated
|
|
88
|
+
fixture modules with TypeScript 6, NodeNext/ES2022, `exactOptionalPropertyTypes`,
|
|
89
|
+
`noUncheckedIndexedAccess` and `verbatimModuleSyntax`. They cover aliases, nested
|
|
90
|
+
paths, filtered fields, stale contracts, supported authentication and errors.
|
|
91
|
+
|
|
92
|
+
Run the wire harness with a prepared published `haveapi-client@0.30.2`
|
|
93
|
+
installation:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
HAVEAPI_TYPESCRIPT_RUNTIME=/absolute/path/to/haveapi-client/dist/haveapi-client.js \
|
|
97
|
+
HAVEAPI_RELEASE_TOOLS_ONLY=1 nix develop --command bundle exec ruby \
|
|
98
|
+
clients/typescript/spec/documentation/wire.rb
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The harness verifies the runtime artifact's hash, compiles the rendered snippets,
|
|
102
|
+
and runs them against a local server at root and mounted URLs. It checks exact
|
|
103
|
+
requests, Basic and existing-token routing, aliases, nested IDs and rejection
|
|
104
|
+
handling. It downloads no runtime and calls no production API.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require_relative 'lib/haveapi/typescript_client/version'
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = 'haveapi-typescript-client'
|
|
5
|
+
spec.version = HaveAPI::TypeScriptClient::VERSION
|
|
6
|
+
spec.authors = ['Jakub Skokan']
|
|
7
|
+
spec.summary = 'Generate typed TypeScript operations from saved HaveAPI schemas'
|
|
8
|
+
spec.license = 'MIT'
|
|
9
|
+
spec.required_ruby_version = '>= 3.2'
|
|
10
|
+
spec.files = Dir.chdir(__dir__) do
|
|
11
|
+
Dir['{bin,lib,template}/**/*', 'docs/*.md', 'README.md', 'LICENSE.txt',
|
|
12
|
+
'Gemfile', 'Rakefile', 'haveapi-typescript-client.gemspec'].select { |path| File.file?(path) }.sort
|
|
13
|
+
end
|
|
14
|
+
spec.bindir = 'bin'
|
|
15
|
+
spec.executables = ['haveapi-typescript-client']
|
|
16
|
+
spec.require_paths = ['lib']
|
|
17
|
+
spec.add_dependency 'haveapi-client', '~> 0.31.0'
|
|
18
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'optparse'
|
|
2
|
+
require_relative '../typescript_client'
|
|
3
|
+
|
|
4
|
+
module HaveAPI::TypeScriptClient
|
|
5
|
+
class Cli
|
|
6
|
+
def self.run(argv = ARGV, out: $stdout, err: $stderr)
|
|
7
|
+
argv = argv.dup
|
|
8
|
+
command = argv.shift
|
|
9
|
+
if command == 'fetch'
|
|
10
|
+
return HaveAPI::Schema::FetchCommand.run(argv, out:, err:, command_name: 'haveapi-typescript-client')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
argv.unshift(command) if %w[-h --help].include?(command)
|
|
14
|
+
options = {}
|
|
15
|
+
parser = OptionParser.new do |opts|
|
|
16
|
+
opts.banner = 'Usage: haveapi-typescript-client fetch URL [options] | generate --schema FILE --api-version VERSION --output DIR [--check]'
|
|
17
|
+
opts.on('--schema FILE') { |value| options[:schema] = value }
|
|
18
|
+
opts.on('--api-version VERSION') { |value| options[:version] = value }
|
|
19
|
+
opts.on('--output DIR') { |value| options[:output] = value }
|
|
20
|
+
opts.on('--check', 'Check generated output without writing') { options[:check] = true }
|
|
21
|
+
opts.on('-h', '--help') do
|
|
22
|
+
out.puts(opts)
|
|
23
|
+
return 0
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
parser.parse!(argv)
|
|
27
|
+
raise Error, 'expected generate subcommand and no positional arguments' unless command == 'generate' && argv.empty?
|
|
28
|
+
raise Error, 'generate requires --schema and --output' unless options[:schema] && options[:output]
|
|
29
|
+
|
|
30
|
+
Snapshot.version!(options[:version])
|
|
31
|
+
schema = Snapshot.load(options[:schema])
|
|
32
|
+
raise Error, 'requested API version differs from snapshot' unless schema.fetch('api_version') == options[:version]
|
|
33
|
+
|
|
34
|
+
Generator.new(schema:).generate(output: options[:output], check: options[:check])
|
|
35
|
+
0
|
|
36
|
+
rescue Error, OptionParser::ParseError, SystemCallError => e
|
|
37
|
+
err.puts("haveapi-typescript-client: #{e.message}")
|
|
38
|
+
1
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|