Skip to content
This repository was archived by the owner on Sep 27, 2023. It is now read-only.

Commit 9af2db6

Browse files
committed
[Transform] Initial implementation that can compile
something for both classic/modern/compat
1 parent 94ad992 commit 9af2db6

9 files changed

+111
-20
lines changed

transform/src/BindingsAtNode.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,18 @@ export function bindingsAtNode(node: ts.Node): Bindings {
109109

110110
while (node.parent != null) {
111111
const parent = node.parent;
112+
node = parent;
112113
if (ts.isBlock(parent) || ts.isSourceFile(parent)) {
113114
findStatementsBindings(parent);
114115
continue;
115116
}
116-
117117
if (ts.isForStatement(parent) && parent.initializer != null) {
118118
findInitializerBindings(parent.initializer);
119119
continue;
120120
}
121121
if (ts.isForOfStatement(parent)) {
122122
findInitializerBindings(parent.initializer);
123+
continue;
123124
}
124125
}
125126
return bindings;

transform/src/RelayQLTransformer.ts

-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ export class RelayQLTransformer {
181181
documentText: string,
182182
{ documentName, enableValidation }: TextTransformOptions,
183183
): RelayQLDefinition<any> {
184-
console.log(documentText);
185184
const document = parse(new Source(documentText, documentName));
186185
const validationErrors = enableValidation
187186
? this.validateDocument(document, documentName)

transform/src/compileGraphQLTag.ts

+27-12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import { getFragmentNameParts } from "./getFragmentNameParts";
55
import { DocumentNode, FragmentDefinitionNode, OperationDefinitionNode } from "graphql";
66
import * as ts from 'typescript';
77
import { NormalizedOptions } from "./Options";
8+
import { createCompatNode } from "./createCompatNode";
9+
import { createClassicNode } from "./createClassicNode";
10+
import { bindingsAtNode } from "./bindingsAtNode";
11+
import { setSourceMapRange } from "typescript";
812

913
/**
1014
* Given a graphql`` tagged template literal, replace it with the appropriate
@@ -13,7 +17,7 @@ import { NormalizedOptions } from "./Options";
1317
export function compileGraphQLTag(
1418
ctx: ts.TransformationContext,
1519
opts: NormalizedOptions,
16-
node: ts.Node,
20+
node: ts.TaggedTemplateExpression,
1721
ast: DocumentNode,
1822
fileName: string,
1923
): ts.Expression {
@@ -28,7 +32,7 @@ export function compileGraphQLTag(
2832
`graphql tag referenced by the property ${objPropName}.`,
2933
);
3034
}
31-
return createAST(ctx, opts, node, mainDefinition, fileName);
35+
return createAST(ctx, opts, node, mainDefinition, fileName, true);
3236
}
3337

3438
const nodeMap: { [key: string]: ts.Expression } = {};
@@ -41,7 +45,7 @@ export function compileGraphQLTag(
4145
}
4246

4347
const [, propName] = getFragmentNameParts(definition.name.value);
44-
nodeMap[propName] = createAST(ctx, opts, null, definition, fileName);
48+
nodeMap[propName] = createAST(ctx, opts, node, definition, fileName, false);
4549
}
4650
return createObject(nodeMap, node);
4751
}
@@ -53,7 +57,7 @@ export function compileGraphQLTag(
5357
'(query, mutation, or subscription) per graphql tag.',
5458
);
5559
}
56-
return createAST(ctx, opts, node, mainDefinition, fileName);
60+
return createAST(ctx, opts, node, mainDefinition, fileName, true);
5761
}
5862

5963
throw new Error(
@@ -64,7 +68,14 @@ export function compileGraphQLTag(
6468
);
6569
}
6670

67-
function createAST(ctx: ts.TransformationContext, opts: NormalizedOptions, node: ts.Node | null, graphqlDefinition: FragmentDefinitionNode | OperationDefinitionNode, fileName: string) {
71+
function createAST(
72+
ctx: ts.TransformationContext,
73+
opts: NormalizedOptions,
74+
node: ts.TaggedTemplateExpression,
75+
graphqlDefinition: FragmentDefinitionNode | OperationDefinitionNode,
76+
fileName: string,
77+
setSoueceMapRange: boolean,
78+
) {
6879
const isCompatMode = Boolean(opts.compat);
6980
const isDevVariable = opts.isDevVariable;
7081
const artifactDirectory = opts.artifactDirectory;
@@ -77,14 +88,18 @@ function createAST(ctx: ts.TransformationContext, opts: NormalizedOptions, node:
7788

7889
const modernNode = createModernNode(ctx, opts, graphqlDefinition, fileName);
7990
if (isCompatMode) {
80-
throw new Error('Not implemented');
81-
// return createCompatNode(
82-
// t,
83-
// modernNode,
84-
// createClassicNode(t, path, graphqlDefinition, state),
85-
// );
91+
console.log('Launching compat mode!');
92+
const result = createCompatNode(
93+
modernNode,
94+
createClassicNode(ctx, bindingsAtNode(node), node, graphqlDefinition, opts),
95+
);
96+
console.log('Done generating stuff');
97+
if (setSourceMapRange) {
98+
ts.setSourceMapRange(result, ts.getSourceMapRange(node));
99+
}
100+
return result;
86101
}
87-
if (node != null) {
102+
if (setSourceMapRange) {
88103
ts.setSourceMapRange(modernNode, ts.getSourceMapRange(node));
89104
}
90105
return modernNode;

transform/src/compileRelayQLTag.ts

-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,5 @@ export function compileRelayQLTag(
2323
tagName,
2424
enableValidation,
2525
});
26-
ts.setSourceMapRange(result, ts.getSourceMapRange(node));
2726
return result;
2827
}

transform/src/createClassicNode.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
print
1919
} from "graphql";
2020
import { NormalizedOptions } from "./Options";
21-
import { Bindings, BindingKind } from "./BindingsAtNode";
21+
import { Bindings, BindingKind } from "./bindingsAtNode";
2222

2323
interface Fragment {
2424
name: string;

transform/src/createCompatNode.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as ts from "typescript";
2+
/**
3+
* Relay Compat transforms graphql definitions into objects with `modern` and
4+
* `classic` keys, each containing the resulting transforms.
5+
*/
6+
export function createCompatNode(
7+
modernNode: ts.Expression,
8+
classicNode: ts.Expression
9+
): ts.Expression {
10+
return ts.createObjectLiteral([
11+
ts.createPropertyAssignment(ts.createIdentifier('modern'), modernNode),
12+
ts.createPropertyAssignment(ts.createIdentifier('classic'), classicNode),
13+
], true);
14+
}
15+

transform/src/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ function visitor(ctx: ts.TransformationContext, sf: ts.SourceFile, opts: Normali
3838
'Check your configuration for TypeScript and ensure you\'ve set a path for your GraphQL schema.'
3939
);
4040
}
41-
return compileRelayQLTag(ctx, opts, opts.relayQLTransformer, node, sf.fileName, relayQLTag[2], relayQLTag[1], true);
41+
const result = compileRelayQLTag(ctx, opts, opts.relayQLTransformer, node, sf.fileName, relayQLTag[2], relayQLTag[1], true);
42+
ts.setSourceMapRange(result, ts.getSourceMapRange(node));
43+
return result;
4244
}
4345
}
4446
return ts.visitEachChild(node, visit, ctx);

transform/test/TSTransform-test.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@ const schemaPath = path.resolve(__dirname, 'testschema.rfc.graphql');
2020

2121
describe('TSTransform', () => {
2222
it('Modern should compile', async () => {
23-
const text = 'createFragmentContainer(MyComponent, {todo: graphql`fragment MyFragment_todo on MyType { id }`})';
23+
const text = 'createFragmentContainer(MyComponent, {todo: graphql`fragment MyFragment_todo on Node { id }`})';
2424

2525
expect(transformWithOptions({ isDevVariable: 'IS_DEV', artifactDirectory: '/testing/artifacts' }, text, '/test/MyComponent.ts')).toMatchSnapshot('modern test');
2626
});
27+
it('Compat should compile', async () => {
28+
const text = 'createFragmentContainer(MyComponent, {todo: graphql`fragment MyFragment_todo on Node { id }`})';
29+
30+
expect(transformWithOptions({ isDevVariable: 'IS_DEV', artifactDirectory: '/testing/artifacts', schema: schemaPath, compat: true }, text, '/test/MyComponent.ts')).toMatchSnapshot('compat test');
31+
});
2732
it('Classic should compile', async () => {
2833
const text = 'createFragmentContainer(MyComponent, {todo: () => Relay.QL`fragment on Node { id }`})';
2934

transform/test/__snapshots__/TSTransform-test.ts.snap

+57-2
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,74 @@ Object {
3838
}
3939
`;
4040

41+
exports[`TSTransform Compat should compile: compat test 1`] = `
42+
Object {
43+
"diagnostics": Array [],
44+
"outputText": "createFragmentContainer(MyComponent, { todo: {
45+
modern: function () {
46+
if (IS_DEV) {
47+
var node = require(\\"../testing/artifacts/MyFragment_todo.graphql\\").default;
48+
if (node.hash && node.hash !== \\"9daa79e3d5938020fd9af9ff08a0f4e4\\") {
49+
console.error(\\"The definition of 'MyFragment_todo' appears to have changed. Run \`relay-compiler\` to update the generated files to receive the expected data.\\");
50+
}
51+
}
52+
return require(\\"../testing/artifacts/MyFragment_todo.graphql\\").default;
53+
},
54+
classic: function (RelayQL_GENERATED) {
55+
return {
56+
kind: \\"FragmentDefinition\\",
57+
argumentDefinitions: [],
58+
node: function () {
59+
return {
60+
children: [
61+
{
62+
fieldName: \\"id\\",
63+
kind: \\"Field\\",
64+
metadata: {
65+
isRequisite: true
66+
},
67+
type: \\"String\\"
68+
},
69+
{
70+
fieldName: \\"__typename\\",
71+
kind: \\"Field\\",
72+
metadata: {
73+
isGenerated: true,
74+
isRequisite: true
75+
},
76+
type: \\"String\\"
77+
}
78+
],
79+
id: RelayQL_GENERATED.__id(),
80+
kind: \\"Fragment\\",
81+
metadata: {
82+
isAbstract: true
83+
},
84+
name: \\"MyFragment_todo\\",
85+
type: \\"Node\\"
86+
};
87+
}()
88+
};
89+
}
90+
} });
91+
//# sourceMappingURL=MyComponent.js.map",
92+
"sourceMapText": "{\\"version\\":3,\\"file\\":\\"MyComponent.js\\",\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"MyComponent.ts\\"],\\"names\\":[],\\"mappings\\":\\"AAAA,uBAAuB,CAAC,WAAW,EAAE,EAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAAgD,EAAC,CAAC,CAAA\\"}",
93+
}
94+
`;
95+
4196
exports[`TSTransform Modern should compile: modern test 1`] = `
4297
Object {
4398
"diagnostics": Array [],
4499
"outputText": "createFragmentContainer(MyComponent, { todo: function () {
45100
if (IS_DEV) {
46101
var node = require(\\"../testing/artifacts/MyFragment_todo.graphql\\").default;
47-
if (node.hash && node.hash !== \\"e655cc161574f3976cf1b4a8310f6885\\") {
102+
if (node.hash && node.hash !== \\"9daa79e3d5938020fd9af9ff08a0f4e4\\") {
48103
console.error(\\"The definition of 'MyFragment_todo' appears to have changed. Run \`relay-compiler\` to update the generated files to receive the expected data.\\");
49104
}
50105
}
51106
return require(\\"../testing/artifacts/MyFragment_todo.graphql\\").default;
52107
} });
53108
//# sourceMappingURL=MyComponent.js.map",
54-
"sourceMapText": "{\\"version\\":3,\\"file\\":\\"MyComponent.js\\",\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"MyComponent.ts\\"],\\"names\\":[],\\"mappings\\":\\"AAAA,uBAAuB,CAAC,WAAW,EAAE,EAAC,IAAI,EAAE;;;;;;;;KAAkD,EAAC,CAAC,CAAA\\"}",
109+
"sourceMapText": "{\\"version\\":3,\\"file\\":\\"MyComponent.js\\",\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"MyComponent.ts\\"],\\"names\\":[],\\"mappings\\":\\"AAAA,uBAAuB,CAAC,WAAW,EAAE,EAAC,IAAI,EAAE;;;;;;;;KAAgD,EAAC,CAAC,CAAA\\"}",
55110
}
56111
`;

0 commit comments

Comments
 (0)