Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a59da0c
added the change required for gcp-na, added oclife-manifest.json to g…
cs-raj Jan 10, 2024
767b581
Merge pull request #80 from Contentstack-Solutions/feat/CS-43273
cs-raj Jan 10, 2024
776517d
feat: generate graphql type def using introspection query
aman19K Jan 12, 2024
31c5362
version bump
aman19K Jan 12, 2024
cf9cc6b
refactor: added graphql example
aman19K Jan 12, 2024
2532bb3
refactor: graphql typedef
aman19K Jan 12, 2024
0cef388
Merge pull request #82 from Contentstack-Solutions/feat/CS-43209
aman19K Jan 12, 2024
3967087
Merge pull request #84 from Contentstack-Solutions/staging
aman19K Jan 12, 2024
c121c89
Merge branch 'development' into feat/graphql-support
aman19K Jan 12, 2024
4a782b9
added early access header support
shafeeqd959 Jan 16, 2024
5395265
Merge branch 'development' of github.com:Contentstack-Solutions/conte…
shafeeqd959 Jan 16, 2024
09fc486
Merge pull request #85 from Contentstack-Solutions/feat/early-access-…
shafeeqd959 Jan 16, 2024
c0be3bd
feat: unit test cases setup , graphql test cases & ui text changes
aman19K Jan 18, 2024
a3c4db8
refactor: test cases
aman19K Jan 18, 2024
9fe5adf
Merge pull request #86 from Contentstack-Solutions/Feat/CS-43211-grap…
aman19K Jan 18, 2024
7ece847
Merge branch 'development' into feat/graphql-support
aman19K Jan 18, 2024
d7192bc
remove extra version
aman19K Jan 18, 2024
36d73e0
fix indentation
aman19K Jan 18, 2024
6de4e22
Merge remote-tracking branch 'origin/development' into feat/CS-43112-…
cs-raj Jan 24, 2024
4517f09
fix: directory issues
aman19K Jan 24, 2024
688c10b
Merge branch 'development' into feat/graphql-support
aman19K Jan 24, 2024
d368b2a
remove duplicate version
aman19K Jan 24, 2024
01d827e
remove unused var
aman19K Jan 24, 2024
ce379c6
Merge pull request #88 from Contentstack-Solutions/feat/graphql-support
aman19K Jan 24, 2024
d1f8c8f
Merge branch 'development' into feat/CS-43112-gcp-support
cs-raj Jan 24, 2024
c272655
Merge pull request #87 from Contentstack-Solutions/feat/CS-43112-gcp-…
cs-raj Jan 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
/yarn.lock
node_modules
.vscode/
oclif.manifest.json
1,470 changes: 1,287 additions & 183 deletions package-lock.json

Large diffs are not rendered by default.

17 changes: 12 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
{
"name": "contentstack-cli-tsgen",
"description": "Generate TypeScript typings from a Stack.",
"version": "2.2.2",
"version": "2.3.0",
"author": "Michael Davis",
"bugs": "https://github.com/Contentstack-Solutions/contentstack-cli-tsgen/issues",
"dependencies": {
"@contentstack/cli-command": "^1.2.13",
"@contentstack/cli-utilities": "^1.5.2",
"@contentstack/cli-command": "^1.2.17",
"@contentstack/cli-utilities": "^1.5.10",
"@gql2ts/from-schema": "^2.0.0-4",
"lodash": "^4.17.20",
"prettier": "^2.0.5",
"tslib": "^1.13.0"
},
"devDependencies": {
"@oclif/plugin-help": "^3.2.0",
"@oclif/test": "^3.1.12",
"@types/async": "^3.2.18",
"@types/chai": "^4.3.11",
"@types/jest": "^26.0.14",
"@types/lodash": "^4.14.162",
"@types/mocha": "^10.0.6",
"@types/node": "^10.17.28",
"async": "^3.2.4",
"chai": "^5.0.0",
"eslint": "^5.16.0",
"eslint-config-oclif": "^3.1.0",
"eslint-config-oclif-typescript": "^0.1.0",
"globby": "^10.0.2",
"jest": "^26.5.3",
"mocha": "^10.2.0",
"oclif": "^3.7.0",
"ts-jest": "^26.4.1",
"ts-node": "^10.9.1",
Expand Down Expand Up @@ -56,8 +62,9 @@
"postpack": "rm -f oclif.manifest.json",
"posttest": "eslint . --ext .ts --config .eslintrc",
"prepack": "rm -rf lib && tsc -b && oclif manifest && oclif readme",
"test": "jest",
"version": "oclif readme && git add README.md"
"test": "jest --testPathPattern=tests",
"version": "oclif readme && git add README.md",
"test:unit": "mocha --forbid-only -r ts-node/register \"test/**/*.test.ts\""
},
"csdxConfig": {
"shortCommandName": {
Expand Down
55 changes: 39 additions & 16 deletions src/commands/tsgen.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Command} from '@contentstack/cli-command'
import {FlagInput, flags} from '@contentstack/cli-utilities'
import {getGlobalFields, stackConnect, StackConnectionConfig} from '../lib/stack/client'
import {getGlobalFields, stackConnect, StackConnectionConfig, generateGraphQLTypeDef} from '../lib/stack/client'
import {ContentType} from '../lib/stack/schema'
import tsgenRunner from '../lib/tsgen/runner'

Expand All @@ -11,6 +11,8 @@ export default class TypeScriptCodeGeneratorCommand extends Command {
'$ csdx tsgen -a "delivery token alias" -o "contentstack/generated.d.ts"',
'$ csdx tsgen -a "delivery token alias" -o "contentstack/generated.d.ts" -p "I"',
'$ csdx tsgen -a "delivery token alias" -o "contentstack/generated.d.ts" --no-doc',
'$ csdx tsgen -a "delivery token alias" -o "contentstack/generated.d.ts" --api-type graphql',
'$ csdx tsgen -a "delivery token alias" -o "contentstack/generated.d.ts" --api-type graphql --namespace "GraphQL" ',
];

static flags: FlagInput = {
Expand Down Expand Up @@ -56,6 +58,17 @@ export default class TypeScriptCodeGeneratorCommand extends Command {
description: 'include system fields in generated types',
default: false,
}),

'api-type': flags.string({
default: 'rest',
multiple: false,
options: ['rest', 'graphql'],
description: '[Optional] Please enter an API type to generate the type definitions.',
}),

namespace: flags.string({
description: '[Optional]Please enter a namespace for the GraphQL API type to organize the generated types.',
}),
};

async run() {
Expand All @@ -68,6 +81,7 @@ export default class TypeScriptCodeGeneratorCommand extends Command {
const outputPath = flags.output
const branch = flags.branch
const includeSystemFields = flags['include-system-fields']
const namespace = flags.namespace

if (token.type !== 'delivery') {
this.warn('Possibly using a management token. You may not be able to connect to your Stack. Please use a delivery token.')
Expand All @@ -85,24 +99,33 @@ export default class TypeScriptCodeGeneratorCommand extends Command {
branch: branch || null,
}

const [client, globalFields] = await Promise.all([stackConnect(this.deliveryAPIClient.Stack, config, this.cdaHost), getGlobalFields(config, this.cdaHost)])

let schemas: ContentType[] = []
if (client.types?.length) {
if ((globalFields as any)?.global_fields?.length) {
schemas = schemas.concat((globalFields as any).global_fields as ContentType)
schemas = schemas.map(schema => ({
...schema,
schema_type: 'global_field',
}))
if (flags['api-type'] === 'graphql') {
const result = await generateGraphQLTypeDef(config, outputPath, namespace)
if (result) {
this.log(`Successfully added the GraphQL schema type definitions to '${result.outputPath}'.`)
} else {
this.log('No schema found in the stack! Please use a valid stack.')
}
schemas = schemas.concat(client.types)
const result = await tsgenRunner(outputPath, schemas, prefix, includeDocumentation, includeSystemFields)
this.log(`Wrote ${result.definitions} Content Types to '${result.outputPath}'.`)
} else {
this.log('No Content Types exist in the Stack.')
const [client, globalFields] = await Promise.all([stackConnect(this.deliveryAPIClient.Stack, config, this.cdaHost), getGlobalFields(config, this.cdaHost)])

let schemas: ContentType[] = []
if (client.types?.length) {
if ((globalFields as any)?.global_fields?.length) {
schemas = schemas.concat((globalFields as any).global_fields as ContentType)
schemas = schemas.map(schema => ({
...schema,
schema_type: 'global_field',
}))
}
schemas = schemas.concat(client.types)
const result = await tsgenRunner(outputPath, schemas, prefix, includeDocumentation, includeSystemFields)
this.log(`Wrote ${result.definitions} Content Types to '${result.outputPath}'.`)
} else {
this.log('No Content Types exist in the Stack.')
}
}
} catch (error) {
} catch (error: any) {
this.error(error as any, {exit: 1})
}
}
Expand Down
1 change: 1 addition & 0 deletions src/graphQL/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './queries'
98 changes: 98 additions & 0 deletions src/graphQL/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const introspectionQuery = `query IntrospectionQuery{
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}`

export {introspectionQuery}
85 changes: 78 additions & 7 deletions src/lib/stack/client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import * as fs from 'fs'
import * as http from 'https'
import * as async from 'async'
import {ContentTypeCollection} from 'contentstack'
import * as path from 'path'
import { ContentTypeCollection } from 'contentstack'
import {HttpClient, cliux, configHandler} from '@contentstack/cli-utilities'
import {schemaToInterfaces, generateNamespace} from '@gql2ts/from-schema'

import {introspectionQuery} from '../../graphQL'

type RegionUrlMap = {
[prop: string]: string;
Expand All @@ -11,7 +17,17 @@ const REGION_URL_MAPPING: RegionUrlMap = {
us: 'cdn.contentstack.io',
eu: 'eu-cdn.contentstack.com',
'azure-na': 'azure-na-cdn.contentstack.com',
'azure-eu': 'azure-eu-cdn.contentstack.com'
'azure-eu': 'azure-eu-cdn.contentstack.com',
'gcp-na': 'gcp-na-cdn.contentstack.com'
}

const GRAPHQL_REGION_URL_MAPPING: RegionUrlMap = {
na: 'https://graphql.contentstack.com/stacks',
us: 'https://graphql.contentstack.com/stacks',
eu: 'https://eu-graphql.contentstack.com/stacks',
'azure-na': 'https://azure-na-graphql.contentstack.com/stacks',
'azure-eu': 'https://azure-eu-graphql.contentstack.com/stacks',
'gcp-na': 'https://gcp-na-graphql.contentstack.com/stacks'
}

export type StackConnectionConfig = {
Expand All @@ -32,11 +48,12 @@ const queryParams = {
export async function stackConnect(client: any, config: StackConnectionConfig, cdaHost: string) {
try {
const clientParams: {
api_key: string,
delivery_token: string,
environment: string,
region: string,
branch?: string
api_key: string;
delivery_token: string;
environment: string;
region: string;
branch?: string;
early_access?: string[];
} = {
api_key: config.apiKey,
delivery_token: config.token,
Expand All @@ -46,6 +63,12 @@ export async function stackConnect(client: any, config: StackConnectionConfig, c
if (config.branch) {
clientParams.branch = config.branch
}

const earlyAccessHeaders = configHandler.get(`earlyAccessHeaders`);
if (earlyAccessHeaders && Object.keys(earlyAccessHeaders).length > 0) {
clientParams.early_access = Object.values(earlyAccessHeaders);
}

// eslint-disable-next-line new-cap
const stack = client(clientParams)
// check and update host if doesn't exists in REGION_URL_MAPPING
Expand Down Expand Up @@ -139,3 +162,51 @@ export async function getGlobalFields(config: StackConnectionConfig, cdaHost: st
throw new Error('Could not connect to the stack. Please check your credentials.')
}
}

export async function generateGraphQLTypeDef(config: StackConnectionConfig, outputFile: string, namespace: string) {
const spinner = cliux.loaderV2('Fetching graphql schema...')
try {
if (!GRAPHQL_REGION_URL_MAPPING[config.region]) {
throw new Error(`GraphQL content delivery api unavailable for '${config.region}' region`)
}

const query = {
environment: config.environment,
}
const headers: any = {
access_token: config.token,
}
if (config.branch) {
headers.branch = config.branch
}

// Generate graphql schema with introspection query
const url = `${GRAPHQL_REGION_URL_MAPPING[config.region]}/${config.apiKey}`
const result = await new HttpClient()
.headers(headers)
.queryParams(query)
.post(url, {query: introspectionQuery})

cliux.loaderV2('', spinner)

let schema: string
if (namespace) {
schema = generateNamespace(namespace, result?.data)
} else {
schema = schemaToInterfaces(result?.data)
}

//Create and write type def in file
const outputPath = path.resolve(process.cwd(), outputFile)
const dirName = path.dirname(outputPath)
fs.mkdirSync(dirName, {recursive: true})
fs.writeFileSync(outputPath, schema)

return {
outputPath: outputPath,
}
} catch (error: any) {
cliux.loaderV2('', spinner)
throw error
}
}
4 changes: 2 additions & 2 deletions src/lib/stack/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type GlobalField = {
reference_to: string;
schema: Schema;
schema_type?: string;
_version?: number
_version?: number;
} & FieldOptions;

export type ReferenceField = {
Expand Down Expand Up @@ -62,4 +62,4 @@ export type ContentType = {
reference_to?: string;
data_type?: string;
schema_type?: string;
} & Identifier;
} & Identifier;
7 changes: 7 additions & 0 deletions test/helpers/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const path = require('path')
process.env.TS_NODE_PROJECT = path.resolve('test/tsconfig.json')
process.env.NODE_ENV = 'development'

global.oclif = global.oclif || {}
global.oclif.columns = 80

11 changes: 11 additions & 0 deletions test/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../tsconfig",
"compilerOptions": {
"noEmit": true,
"resolveJsonModule": true,
"esModuleInterop": true,
},
"references": [
{"path": ".."}
],
}
Loading