Security News
Opengrep Emerges as Open Source Alternative Amid Semgrep Licensing Controversy
Opengrep forks Semgrep to preserve open source SAST in response to controversial licensing changes.
**This is just a proof of concept right now. Everything is very thrown together and inefficient. If it encounters any AST nodes I haven't considered yet, it will simply error out.**
This is just a proof of concept right now. Everything is very thrown together and inefficient. If it encounters any AST nodes I haven't considered yet, it will simply error out.
TypeScript First GraphQL is a library for deriving a GraphQL schema from your lightly-annotated TypeScript code. The goal is to make your TypeScript code, and its types, the source of truth for your GraphQL schema without requiring decorators or other special syntax/APIs.
Opt classes and methods on your existing models into your GraphQL API by annotating them with a simple comment. TypeScript First GraphQL will derive the GraphQL schema for you via static analysis.
/** @GQLType */
export default class Query {
/** @GQLField */
me(): UserResolver {
return new UserResolver();
}
/**
* @GQLField
* @deprecated Please use `me` instead.
*/
viewer(): UserResolver {
return new UserResolver();
}
}
/**
* A user in our kick-ass system!
* @GQLType User
*/
class UserResolver {
/** @GQLField */
name: string = 'Alice';
/** @GQLField */
greeting(args: { salutation: string }): string {
return `${args.salutation}, ${this.name}`;
}
}
Extracts the following GraphQL schema:
type Query {
me: User
viewer: User @deprecated(reason: "Please use `me` instead.")
}
"""A user in our kick-ass system!"""
type User {
name: String
greeting(salutation: String!): String
}
Still very rough, but you can try it out with:
Note: Globs will be evaluated relative to the current working directory.
git clone ...
pnpm install
pnpm cli <glob of files to analyze>
# Example: `pnpm cli "example-server/**/*.ts"`
In order for TypeScript First GraphQL to be able to extract GraphQL schema from
your code, simply mark which classes and methods should be included in the schema by
marking them with special JSDoc tags such as /** @GQLType */
or /** @GQLField */
.
Any comment text preceding the JSDoc @
tag will be used as that element's description.
Note that JSDocs must being with
/**
(two asterix). However, they may be consolidated into a single line.
GraphQL types can be defined by placing a @GQLType
docblock directly before a:
/**
* Here I can write a description of my type that will be included in the schema.
* @GQLType <optional name of the type, if different from class name>
*/
class MyClass {
/** @GQLField */
someField: string;
}
GraphQL interfaces can be defined by placing a @GQLInterface
docblock directly before an:
/**
* A description of my interface.
* @GQLInterface <optional name of the type, if different from class name>
*/
interface MyClass {
/** @GQLField */
someField: string;
}
All @GQLType
types which implement the interface in TypeScript will
automatically implement it in GraphQL as well.
Within a @GQLType
class, you can define GraphQL fields by placing a @GQLField
directly before a:
/**
* A description of some field.
* @GQLField <optional name of the field, if different from property name>
*/
someField: string;
/**
* A description of my field.
* @GQLField <optional name of the field, if different from method name>
*/
myField(): string {
return "Hello World";
}
Note: TypeScript First GraphQL makes all fields nullable by default in keeping with GraphQL best practices. In the future, we should make this configurable.
If you wish to define arguments for a field, define your argument types inline:
/** @GQLField */
myField(args: { greeting: string }): string {
return `${args.greeting} World`;
}
Default values for arguments can be defined by using the =
operator with destructuring:
/** @GQLField */
myField({ greeting = "Hello" }: { greeting: string }): string {
return `${greeting} World`;
}
Arguments can be given descriptions by using the /**
syntax:
/** @GQLField */
myField(args: {
/** A description of the greeting argument */
greeting: string
}): string {
return `${args.greeting} World`;
}
To mark a field as deprecated, use the @deprecated
JSDoc tag:
/**
* @GQLField
* @deprecated Please use myNewField instead.
*/
myOldField(): string {
return "Hello World";
}
GraphQL unions can be defined by placing a @GQLUnion
docblock directly before a:
/**
* A description of my union.
* @GQLUnion <optional name of the union, if different from type name>
*/
type MyUnion = User | Post;
GraphQL custom sclars can be defined by placing a @GQLScalar
docblock directly before a:
/**
* A description of my custom scalar.
* @GQLScalar <optional name of the scalar, if different from type name>
*/
type MyCustomString = string;
GraphQL enums can be defined by placing a @GQLEnum
docblock directly before a:
/**
* A description of my enum.
* @GQLEnum <optional name of the enum, if different from type name>
*/
enum MyEnum {
/** A description of my variant */
OK = "OK"
/** A description of my other variant */
ERROR = "ERROR"
}
Note that the values of the enum are used as the GraphQL enum values, and must be string literals.
To mark a variants as deprecated, use the @deprecated
JSDoc tag directly before it:
/** @GQLEnum */
enum MyEnum {
OK = "OK"
/** @deprecated Please use OK instead. */
OKAY = "OKAY"
ERROR = "ERROR"
}
We also support defining enums using a union of string literals, howerver there are some limitations to this approach:
This is due to the fact that TypeScript does not see JSDoc comments as "attaching" to string literal types.
/**
* A description of my enum.
* @GQLEnum <optional name of the enum, if different from type name>
*/
type MyEnum = "OK" | "ERROR";
GraphQL input types can be defined by placing a @GQLInput
docblock directly before a:
/**
* Description of my input type
* @GQLInput <optional name of the input, if different from type name>
*/
type MyInput = {
name: string;
age: number;
};
See example-server/
in the repo root for a working example. Here we run the static
analysis at startup time. Nice for development, but not ideal for production
where you would want to cache the schema and write it to disk for other tools to
see.
See CONTRIBUTING.md
in the repo root for details on how to make changes to this project.
Because TypeScript First GraphQL relies on static analysis to infer types, it requires that your GraphQL fields use types that can be statically analyzed. This means that you can't use complex derived types in positions where TypeScript First GraphQL needs to be able to infer the type. For example, field arguments and return values.
Using decorators to signal that a class/method/etc should be included in the schema would have some advantages:
However, it also has some disadvantages:
Given these tradeoffs, we've decided to use comments instead of decorators.
FAQs
[![Join our Discord!](https://img.shields.io/discord/1089650710796320868?logo=discord)](https://capt.dev/grats-chat)
The npm package grats receives a total of 193 weekly downloads. As such, grats popularity was classified as not popular.
We found that grats demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Opengrep forks Semgrep to preserve open source SAST in response to controversial licensing changes.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.