graphile / graphile/crystal

No-biscuit inflection; plus inflection traces

Open
#2,245 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
12.9k
Forks
625
Avg merge
5h 23m
Merged PRs (30d)
24

Description

Overhaul inflection so that it deals with BakedString vs RawString. BakedString.append(...) etc. Prevent thing being cooked twice - no biscuits.

One of these options:

```ts
/**
* TypeScript hack: use this for inflectors that shouldn't be further
* inflected - i.e. they can be used as field, argument, type, etc names
*/
export type CookedString = string & { $$cooked: undefined };

class BakedString extends String {
append(text: BakedString | string) {
return new BakedString(String(this) + text);
}
}
```

If we use BakedString then we can store properties onto it and give it methods for approved modification. One property can track where it came from (i.e. which inflector, and maybe even which version of the inflector e.g. if it came from a plugin). We could even trace all the RawStrings that were fed into that inflector and add those to the trace too, building a mermaid chart of how a particular string was derived. We'd need to then convert the BakedString back to a `string` in `graphile-build` before using it for a type name/field name/argument/etc - but this would also give us an opportunity to perform `assertName` and tell the user exactly where their error is coming from - we can also forbid field/arg names that haven't gone through inflection, encouraging the `builtin` inflector for lazy devs. (We could even trace that a particular field has come through a specific makeExtendSchemaPlugin, for example.)

Then we should make it so that `camelCase`/etc are never used directly - perhaps give them a `__` prefix, they should only be used by inflectors like `field()`, `type()`, `argument()` which are used in non-prefixed inflectors. Inflectors that return RawString should have a `_` prefix.

```ts
/** Every GraphQL type should go through this inflector */
type(this: GraphileBuild.Inflection, rawName: string): CookedString {
return this.upperCamelCase(rawName) as CookedString;
},

/** Every GraphQL field (object, and interfaces) should go through this inflector */
field(this: GraphileBuild.Inflection, fieldNameRaw: string): CookedString {
return this.camelCase(fieldNameRaw) as CookedString;
},

/** Every GraphQL input field (input objects) should go through this inflector */
inputField(
this: GraphileBuild.Inflection,
fieldNameRaw: string,
): CookedString {
return this.field(fieldNameRaw);
},

/** Every GraphQL argument should go through this inflector */
argument(this: GraphileBuild.Inflection, fieldNameRaw: string): CookedString {
return this.inputField(fieldNameRaw);
},
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.