Skip to content

Commit 087ae3b

Browse files
committed
Auto-graphiql when metadata is supplied in a graphiql code-block
1 parent 88b2820 commit 087ae3b

File tree

6 files changed

+42
-113
lines changed

6 files changed

+42
-113
lines changed

resources/writer.js

+1-101
Original file line numberDiff line numberDiff line change
@@ -59,111 +59,12 @@ async function writer(buildDir, file, site) {
5959
data = file.content;
6060
}
6161

62-
data = await writeReact(writePath, file, data);
63-
6462
data = await writeScript(writePath, file, data);
6563

6664
await writeFile(writePath, data);
6765
}
6866

69-
var REACT_COMPONENT_RX = /<react-component (.+?)(?:\/>|><\/react-component>)/g;
70-
71-
var ATTR_RX = /data-([^=]+)=("(?:(?:\\.)|[^"])*")/g;
72-
73-
function writeReact(writePath, file, fileData) {
74-
return new Promise((resolve, reject) => {
75-
var script;
76-
var id = 0;
77-
var withInitialRenders = fileData.replace(REACT_COMPONENT_RX, function (_, componentData) {
78-
var { module, props } = getReactData(componentData);
79-
var componentPath = require.resolve(path.resolve(path.dirname(file.absPath), module));
80-
var component = require(componentPath);
81-
var initialRender = ReactDOM.renderToString(React.createElement(component, props));
82-
var guid = `r${++id}`;
83-
if (!script) {
84-
script = `var React = require('react');\n`;
85-
}
86-
script += `React.render(React.createElement(require("${componentPath}"), ${JSON.stringify(props)}), document.getElementById("${guid}"));\n`;
87-
return `<div id="${guid}">${initialRender}</div>`;
88-
});
89-
90-
if (!script) {
91-
return resolve(fileData);
92-
}
93-
94-
var tmpFile = '/tmp/' + file.relPath.replace('/', '__');
95-
96-
fs.writeFile(tmpFile, script, err => {
97-
if (err) {
98-
return reject(err);
99-
}
100-
101-
var pack = webpack({
102-
bail: true,
103-
entry: tmpFile,
104-
output: {
105-
path: path.dirname(writePath),
106-
filename: path.basename(writePath) + '.[hash].js'
107-
},
108-
externals: {
109-
'react': 'var React'
110-
},
111-
resolveLoader: {
112-
root: path.join(__dirname, '../node_modules')
113-
},
114-
module: {
115-
loaders: [
116-
{
117-
test: /\.jsx?$/,
118-
exclude: /(node_modules|bower_components)/,
119-
loader: 'babel-loader',
120-
query: {
121-
optional: [ 'runtime' ],
122-
}
123-
}
124-
]
125-
}
126-
});
127-
128-
pack.run(function (err, stats) {
129-
if (err) {
130-
return reject(err);
131-
}
132-
133-
resolve(
134-
withInitialRenders.replace(
135-
'</body></html>',
136-
`<script src="/vendor/react-15.0.1.min.js"></script>` +
137-
`<script src="/vendor/react-dom-15.0.1.min.js"></script>` +
138-
`<script src="${path.basename(writePath)}.${stats.hash}.js"></script></body></html>`
139-
)
140-
);
141-
});
142-
143-
});
144-
});
145-
}
146-
147-
function getReactData(componentData) {
148-
var module;
149-
var props = {};
150-
var data = componentData.split(ATTR_RX);
151-
for (var i = 1; i < data.length; i += 3) {
152-
var name = data[i];
153-
var value = JSON.parse(data[i + 1]);
154-
if (name === 'module') {
155-
module = value;
156-
} else {
157-
props[name] =
158-
value === 'true' ? true :
159-
value === 'false' ? false :
160-
!value || isNaN(value) ? value : parseInt(value, 10);
161-
}
162-
}
163-
return { module, props };
164-
}
165-
166-
var SCRIPT_RX = /<script data-inline>([^]+?)<\/script>/gm;
67+
var SCRIPT_RX = /<script data-inline(?:="true")?>([^]+?)<\/script>/gm;
16768

16869
function writeScript(writePath, file, fileData) {
16970
return new Promise((resolve, reject) => {
@@ -269,7 +170,6 @@ function writeScript(writePath, file, fileData) {
269170

270171
});
271172

272-
273173
});
274174
}
275175

site/_core/Marked.js

+22
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,28 @@ Parser.prototype.tok = function() {
822822
);
823823
}
824824
case 'code': {
825+
if (this.token.lang === 'graphql') {
826+
var lines = this.token.text.split('\n');
827+
var firstLine = lines.shift().match(/^\s*#\s*({.*})$/);
828+
if (firstLine) {
829+
var metaData;
830+
try {
831+
metaData = JSON.parse(firstLine[1]);
832+
} catch (e) {
833+
console.error('Invalid Metadata JSON:', firstLine[1]);
834+
}
835+
if (metaData) {
836+
var query = lines.join('\n');
837+
var variables = JSON.stringify(metaData.variables, null, 2);
838+
return <script data-inline dangerouslySetInnerHTML={{__html: `
839+
import MiniGraphiQL from '../_core/MiniGraphiQL';
840+
import { StarWarsSchema } from './_swapiSchema';
841+
renderHere(<MiniGraphiQL schema={StarWarsSchema}
842+
query={\`${query}\`} variables={\`${variables}\`} />);
843+
`}} />
844+
}
845+
}
846+
}
825847
return <Prism language={this.token.lang} line={this.token.line}>{this.token.text}</Prism>;
826848
}
827849
case 'table': {

site/_core/Prism.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,10 @@ Prism.languages.insertBefore('inside', 'attr-value',{
663663

664664
}(Prism));
665665

666+
var graphqlComment = {
667+
pattern: /#.*/,
668+
greedy: true
669+
};
666670

667671
var graphqlCommon = {
668672
string: {
@@ -671,8 +675,10 @@ var graphqlCommon = {
671675
},
672676
number: /(?:\B-|\b)\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/,
673677
boolean: /\b(?:true|false)\b/,
674-
variable: /\$[a-z_]\w*/i,
675-
comment: /#.*/,
678+
variable: {
679+
pattern: /\$[a-z_]\w*/i,
680+
greedy: true
681+
},
676682
operator: /!|=|\.{3}/,
677683
punctuation: /[!(){|}[\]:=,]/
678684
};
@@ -692,9 +698,11 @@ var graphqlDirective = {
692698
};
693699

694700
Prism.languages.graphql = {
701+
comment: graphqlComment,
695702
'schema-def': {
696703
pattern: /\bschema\b[^{]*{[^{}]*}/,
697704
inside: {
705+
comment: graphqlComment,
698706
keyword: /\bschema\b|[a-zA-Z_]\w*(?=\s*:)/,
699707
'type-name': {
700708
pattern: /(:[\s\[]*)[a-z_]\w*/i,
@@ -707,6 +715,7 @@ Prism.languages.graphql = {
707715
'union-def': {
708716
pattern: /\bunion\b[^=]+=\s*[a-zA-Z_]\w*(?:\s*\|\s*[a-zA-Z_]\w*)*/,
709717
inside: {
718+
comment: graphqlComment,
710719
keyword: /\bunion\b/,
711720
'type-name': {
712721
pattern: /([=|]\s*)[a-z_]\w*/i,
@@ -719,12 +728,15 @@ Prism.languages.graphql = {
719728
'type-def': {
720729
pattern: /\b(?:type|interface|input|enum)\b[\w\W]+?{(?:[^{}]*|[^{}]*{[^{}]*}[^{}]*|[^{}]*{[^{}]*[^{}]*{[^{}]*}[^{}]*}[^{}]*)}/,
721730
inside: {
731+
comment: graphqlComment,
722732
fields: {
723733
pattern: /{(?:[^{}]*|[^{}]*{[^{}]*}[^{}]*|[^{}]*{[^{}]*[^{}]*{[^{}]*}[^{}]*}[^{}]*)}/,
724734
inside: {
735+
comment: graphqlComment,
725736
argDefs: {
726737
pattern: /\([\w\W]*?\)/,
727738
inside: {
739+
comment: graphqlComment,
728740
'attr-name': /[a-z_]\w*(?=\s*:)/i,
729741
'type-name': {
730742
pattern: /(:[\s\[]*)[a-z_]\w*/i,
@@ -743,7 +755,6 @@ Prism.languages.graphql = {
743755
pattern: /(:[\s\[]*)[a-z_]\w*/i,
744756
lookbehind: true
745757
},
746-
comment: /#.*/,
747758
punctuation: /[!{}\[\]:=,]/,
748759
}
749760
},

site/_css/index.less

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ body.index {
125125
.fadein-cols(4);
126126
.fadein-cols(@n) when (@n > 1) { .fadein-cols(@n - 1);
127127
.marketing-col:nth-child(@{n}) {
128-
animation: fade 1.0s 0.7s * @n ease-in-out both;
128+
animation: fade 1.0s 0.5s * @n ease-in-out both;
129129
}
130130
}
131131

site/_css/prism.less

+1
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@
214214
}
215215

216216
/* Variable */
217+
.prism .variable,
217218
.cm-variable {
218219
color: #397D13;
219220
}

site/docs/Learn-Queries.md

+3-8
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,8 @@ When we start working with variables, we need to do three things:
156156

157157
Here's what it looks like all together:
158158

159-
<script data-inline>
160-
import MiniGraphiQL from '../_core/MiniGraphiQL';
161-
import { StarWarsSchema } from './_swapiSchema';
162-
renderHere(<MiniGraphiQL schema={StarWarsSchema} query={`
159+
```graphql
160+
# { "graphiql": true, "variables": { "episode": "JEDI" } }
163161
query HeroNameAndFriends($episode: Episode) {
164162
hero(episode: $episode) {
165163
name
@@ -168,10 +166,7 @@ query HeroNameAndFriends($episode: Episode) {
168166
}
169167
}
170168
}
171-
`} variables={`{
172-
"episode": "JEDI"
173-
}`} />);
174-
</script>
169+
```
175170

176171
Now, in our client code, we can simply pass a different variable rather than needing to construct an entirely new query. This is also in general a good practice for denoting which arguments in our query are expected to be dynamic - we should never be doing string interpolation to construct queries from user-supplied values.
177172

0 commit comments

Comments
 (0)