Skip to content

Commit 7fbaab1

Browse files
committed
Make generate-types pipe instead
1 parent fb2b70f commit 7fbaab1

File tree

5 files changed

+114
-79
lines changed

5 files changed

+114
-79
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ node_modules
1010
oclif.manifest.json
1111
.idea
1212
flagsmith.json
13+
FlagsmithTypes.ts
14+
tsconfig.tsbuildinfo

README.md

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ $ npm install -g flagsmith-cli
5353
$ flagsmith COMMAND
5454
running command...
5555
$ flagsmith (--version)
56-
flagsmith-cli/0.1.2 darwin-arm64 node-v18.13.0
56+
flagsmith-cli/0.3.0 darwin-arm64 node-v18.20.4
5757
$ flagsmith --help [COMMAND]
5858
USAGE
5959
$ flagsmith COMMAND
@@ -62,38 +62,70 @@ USAGE
6262
<!-- usagestop -->
6363
# Commands
6464
<!-- commands -->
65+
* [`flagsmith generate-types PROJECT`](#flagsmith-generate-types-project)
6566
* [`flagsmith get [ENVIRONMENT]`](#flagsmith-get-environment)
6667
* [`flagsmith help [COMMANDS]`](#flagsmith-help-commands)
6768

69+
## `flagsmith generate-types PROJECT`
70+
71+
Fetch Flagsmith feature flags as JSON. By default pipes to stdout, allowing use with other tools; or write to a file with -o.
72+
73+
```
74+
USAGE
75+
$ flagsmith generate-types PROJECT [-a <value>] [-o <value>] [-e <value>] [-p]
76+
77+
ARGUMENTS
78+
PROJECT Flagsmith project ID
79+
80+
FLAGS
81+
-a, --api=<value> [default: https://api.flagsmith.com] The API endpoint (if self-hosted)
82+
-e, --exclude=<value> Comma-separated list of feature names to exclude
83+
-o, --output=<value> Write the fetched JSON to a file instead of stdout
84+
-p, --parseObjects (experimental) Include full object values when fetching features
85+
86+
DESCRIPTION
87+
Fetch Flagsmith feature flags as JSON. By default pipes to stdout, allowing use with other tools; or write to a file
88+
with -o.
89+
90+
EXAMPLES
91+
export FLAGSMITH_API_KEY=YOUR_KEY flagsmith generate-types PROJECT_ID | npx quicktype \
92+
--src-lang json \
93+
--lang typescript \
94+
--just-types \
95+
--explicit-unions \
96+
--acronym-style camel \
97+
--top-level FlagsmithTypes \
98+
-o FlagsmithTypes.ts
99+
100+
export FLAGSMITH_API_KEY=YOUR_KEY flagsmith generate-types PROJECT_ID -o features.json
101+
```
102+
103+
_See code: [src/commands/generate-types/index.ts](https://github.com/Flagsmith/flagsmith-cli/blob/v0.3.0/src/commands/generate-types/index.ts)_
104+
68105
## `flagsmith get [ENVIRONMENT]`
69106

70107
Retrieve flagsmith features from the Flagsmith API and output them to a file.
71108

72109
```
73110
USAGE
74-
$ flagsmith get [ENVIRONMENT] [-o <value>] [-a <value>] [-t
75-
<value> -i <value>] [-p] [-e flags|environment]
111+
$ flagsmith get [ENVIRONMENT] [-o <value>] [-a <value>] [-t <trait_key>=<trait_value>... -i <value>]
112+
[-p] [-e flags|environment]
76113
77114
ARGUMENTS
78-
ENVIRONMENT The flagsmith environment key to use, defaults to the environment
79-
variable FLAGSMITH_ENVIRONMENT
115+
ENVIRONMENT The flagsmith environment key to use, defaults to the environment variable FLAGSMITH_ENVIRONMENT
80116
81117
FLAGS
82-
-a, --api=<value> [default: https://edge.api.flagsmith.com/api/v1/] The
83-
API URL to fetch the feature flags from
84-
-e, --entity=<option> [default: flags] The entity to fetch, this will either
85-
be the flags or an environment document used for [local
86-
evaluation](https://docs.flagsmith.com/clients/server-s
87-
ide#local-evaluation-mode-network-behaviour).
118+
-a, --api=<value> [default: https://edge.api.flagsmith.com/api/v1/] The API URL to fetch the feature flags from
119+
-e, --entity=<option> [default: flags] The entity to fetch, this will either be the flags or an environment document
120+
used for [local evaluation](https://docs.flagsmith.com/clients/server-side#local-evaluation-mod
121+
e-network-behaviour).
88122
<options: flags|environment>
89123
-o, --output=<value> [default: ./flagsmith.json] The file path output
90124
-p, --pretty Prettify the output JSON
91125
92126
IDENTITY FLAGS
93-
-i, --identity=<value> The identity for which to fetch
94-
feature flags
95-
-t, --trait=<trait_key>=<trait_value>... Trait key-value pair, separated by
96-
an equals sign (=)
127+
-i, --identity=<value> The identity for which to fetch feature flags
128+
-t, --trait=<trait_key>=<trait_value>... Trait key-value pair, separated by an equals sign (=)
97129
98130
DESCRIPTION
99131
Retrieve flagsmith features from the Flagsmith API and output them to a file.
@@ -116,46 +148,18 @@ EXAMPLES
116148
$ flagsmith get -p
117149
```
118150

119-
_See code: [dist/commands/get/index.ts](https://github.com/Flagsmith/flagsmith-cli/blob/v0.1.4/dist/commands/get/index.ts)_
120-
121-
## `flagsmith generate-types [ENVIRONMENT]`
122-
123-
Generate a fully typed set of your project's current features.
124-
125-
Note: This requires an API Key that is either generated for organisation settings or found in your account.
126-
127-
```
128-
USAGE
129-
$ FLAGSMITH_API_KEY=<KEY> flagsmith generate-types [PROJECT_ID]
130-
131-
ARGUMENTS
132-
PROJECT_ID The flagsmith project id you are fetching the types for.
133-
134-
FLAGS
135-
-a, --api=<value> [default: https://edge.api.flagsmith.com/api/v1/] The
136-
API URL to fetch the feature flags from
137-
-e, --exclude [default: null] Exclude any feature you intend to remove, can be a csv e.g feature_a,feature_b.
138-
-o, --output=<value> [default: ./flagsmith.d.ts] The file path output
139-
-p, --pretty Prettify the output JSON
140-
141-
DESCRIPTION
142-
Retrieve type definitions for the features and their possible remote configuration values.
143-
```
144-
145-
146-
147-
_See code: [dist/commands/get/index.ts](https://github.com/Flagsmith/flagsmith-cli/blob/v0.1.4/dist/commands/get/index.ts)_
151+
_See code: [src/commands/get/index.ts](https://github.com/Flagsmith/flagsmith-cli/blob/v0.3.0/src/commands/get/index.ts)_
148152

149153
## `flagsmith help [COMMANDS]`
150154

151155
Display help for flagsmith.
152156

153157
```
154158
USAGE
155-
$ flagsmith help [COMMANDS] [-n]
159+
$ flagsmith help [COMMANDS...] [-n]
156160
157161
ARGUMENTS
158-
COMMANDS Command to show help for.
162+
COMMANDS... Command to show help for.
159163
160164
FLAGS
161165
-n, --nested-commands Include all nested commands in the output.
@@ -164,6 +168,8 @@ DESCRIPTION
164168
Display help for flagsmith.
165169
```
166170

171+
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v5.2.20/src/commands/help.ts)_
172+
167173
### Type generation examples
168174

169175
[1 - Adding a remote config.mov](1%20-%20Adding%20a%20remote%20config.mov)

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
"@oclif/plugin-help": "^5",
2222
"@oclif/plugin-plugins": "^2.0.1",
2323
"flagsmith": "^9.0.5",
24-
"node-fetch": "^2.6.6",
25-
"quicktype": "^23.0.170"
24+
"node-fetch": "^2.6.6"
2625
},
2726
"devDependencies": {
2827
"@oclif/test": "^2.1.1",
@@ -38,6 +37,7 @@
3837
"mocha": "^11.1.0",
3938
"nodemon": "^3.1.0",
4039
"oclif": "^4.17.41",
40+
"quicktype": "^23.0.170",
4141
"shx": "^0.3.3",
4242
"ts-node": "^10.2.1",
4343
"tslib": "^2.3.1",
Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,55 @@
11
import {Args, Command, Flags} from '@oclif/core'
2-
import jsonToTypescript from '../../util/json-to-typescript'
32
import getAllFeatures from '../../util/get-all-features'
43
import * as fs from 'node:fs'
54

6-
const api = 'https://api.flagsmith.com'
5+
const DEFAULT_API = 'https://api.flagsmith.com'
76
let apiKey = ''
87

98
export default class FlagsmithGenerateTypes extends Command {
10-
static description = 'Generate TypeScript types from a Flagsmith Project'
9+
static description = 'Fetch Flagsmith feature flags as JSON. By default pipes to stdout, allowing use with other tools; or write to a file with -o.'
10+
1111
static examples = [
12-
'export FLAGSMITH_API_KEY=API_KEY flagsmith generate-types PROJECT_ID',
13-
'export FLAGSMITH_API_KEY=API_KEY flagsmith generate-types PROJECT_ID -a https://selfhosted-flagsmith.example.com',
14-
'export FLAGSMITH_API_KEY=API_KEY flagsmith generate-types PROJECT_ID -o ./my-file.d.ts',
15-
'export FLAGSMITH_API_KEY=API_KEY flagsmith generate-types PROJECT_ID -e feature_to_exclude',
12+
`export FLAGSMITH_API_KEY=YOUR_KEY flagsmith generate-types PROJECT_ID | npx quicktype \\
13+
--src-lang json \\
14+
--lang typescript \\
15+
--just-types \\
16+
--explicit-unions \\
17+
--acronym-style camel \\
18+
--top-level FlagsmithTypes \\
19+
-o FlagsmithTypes.ts`,
20+
'export FLAGSMITH_API_KEY=YOUR_KEY flagsmith generate-types PROJECT_ID -o features.json',
1621
]
1722

1823
static flags = {
1924
api: Flags.string({
2025
char: 'a',
21-
description: 'The API to use if you are self hosted',
26+
description: 'The API endpoint (if self-hosted)',
2227
required: false,
23-
default: 'https://api.flagsmith.com',
28+
default: DEFAULT_API,
2429
}),
2530
output: Flags.string({
2631
char: 'o',
27-
description: 'The file path output',
32+
description: 'Write the fetched JSON to a file instead of stdout',
2833
required: false,
29-
default: './flagsmith.d.ts',
3034
}),
3135
exclude: Flags.string({
3236
char: 'e',
33-
description: 'Comma separated list of feature names to exclude from type generation to test feature removal',
37+
description: 'Comma-separated list of feature names to exclude',
38+
required: false,
39+
}),
40+
parseObjects: Flags.boolean({
41+
char: 'p',
42+
description: '(experimental) Include full object values when fetching features',
3443
required: false,
44+
default: false,
3545
}),
3646
}
3747

3848
static args = {
3949
project: Args.string({
40-
description: 'The flagsmith project id to retrieve the features from',
50+
description: 'Flagsmith project ID',
4151
required: true,
4252
}),
43-
output: Args.string({
44-
description: 'The flagsmith project id to retrieve the features from',
45-
required: false,
46-
}),
4753
}
4854

4955
async run(): Promise<void> {
@@ -55,22 +61,43 @@ export default class FlagsmithGenerateTypes extends Command {
5561

5662
apiKey = process.env.FLAGSMITH_API_KEY
5763

58-
const features = await getAllFeatures({project: `${args.project}`, apiKey, api})
64+
const options: {
65+
project: string
66+
apiKey: string
67+
api: string
68+
parseObjects: boolean
69+
} = {
70+
project: args.project,
71+
apiKey,
72+
api: flags.api,
73+
parseObjects: Boolean(flags.parseObjects),
74+
}
75+
76+
if (flags.parseObjects) {
77+
this.warn('⚠️ Experimental: parsing full flag objects')
78+
}
79+
80+
const features = await getAllFeatures(options)
81+
82+
// Exclude specified flags
5983
const excludeList = flags.exclude?.split(',').map(name => name.trim())
6084
if (excludeList?.length) {
61-
excludeList.map((feature: any) => {
62-
console.log('Excluding flag', feature)
63-
features.map(environmentFeature => {
64-
delete environmentFeature[feature]
65-
})
66-
})
85+
for (const featureName of excludeList) {
86+
this.warn(`Excluding flag ${featureName}`)
87+
for (const envFeat of features) {
88+
delete envFeat[featureName]
89+
}
90+
}
6791
}
6892

6993
const jsonString = JSON.stringify(features)
70-
const output = flags.output
7194

72-
const ts = await jsonToTypescript(jsonString)
73-
console.log('Outputting types to', output)
74-
fs.writeFileSync(output, ts)
95+
if (flags.output) {
96+
this.warn(`Writing JSON to ${flags.output}`)
97+
fs.writeFileSync(flags.output, jsonString)
98+
} else {
99+
// Pipe JSON to stdout for further processing
100+
process.stdout.write(jsonString)
101+
}
75102
}
76103
}

src/util/get-all-features.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import {createFlagsmithInstance} from 'flagsmith/isomorphic'
33
import {IFlagsmithFeature} from 'flagsmith'
44
import doGet from './doGet'
55

6-
export default async function (data: { apiKey: string, api: string, project: string }) {
7-
const {api, apiKey, project} = data
6+
export default async function (data: { apiKey: string, api: string, project: string, parseObjects: boolean }) {
7+
const {api, apiKey, project, parseObjects} = data
88
const getReq = doGet(api, apiKey)
99
const environments: { api_key: string, id: number }[] = await getReq(`projects/${project}/environments/`)
1010
return Promise.all(environments.map(v => {
@@ -13,7 +13,7 @@ export default async function (data: { apiKey: string, api: string, project: str
1313
const features: Record<string, IFlagsmithFeature['value']> = {}
1414
for (const key of Object.keys(instance.getAllFlags())) {
1515
let value = instance.getValue(key)
16-
if (typeof value === 'string') {
16+
if (typeof value === 'string' && parseObjects) {
1717
try {
1818
value = JSON.parse(value)
1919
} catch {}

0 commit comments

Comments
 (0)