mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-01 00:17:26 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			235 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import React from 'react';
 | |
| import ReactDOM from 'react-dom';
 | |
| import { RouteHandler, Link, State } from 'react-router';
 | |
| import CodeMirror from 'codemirror';
 | |
| import { graphql } from 'graphql';
 | |
| import GraphiQL from 'graphiql';
 | |
| import schema from './schema';
 | |
| import pypyjs_vm from 'pypyjs';
 | |
| 
 | |
| import 'codemirror/mode/python/python';
 | |
| import 'codemirror/addon/lint/lint';
 | |
| import '../css/playground.styl';
 | |
| 
 | |
| if (typeof PUBLIC_PATH === "undefined") {
 | |
|   var PUBLIC_PATH = '';
 | |
| }
 | |
| 
 | |
| pypyjs_vm.rootURL = `${PUBLIC_PATH}/playground/lib/`;
 | |
| pypyjs_vm.cacheKey = 'graphene';
 | |
| 
 | |
| CodeMirror.registerHelper('lint', 'python', function (text, options, editor) {
 | |
|   return (options.errors || []).map((error) => {
 | |
|     var tokens = editor.getLineTokens(error.line - 1);
 | |
|     tokens = tokens.filter((token, pos) => {
 | |
|       return !!token.type || token.string.trim().length > 0;
 | |
|     });
 | |
|     if (!tokens) return [];
 | |
|     return {
 | |
|       message: `${error.name}: ${error.message}`,
 | |
|       severity: 'error',
 | |
|       type: 'syntax',
 | |
|       from: CodeMirror.Pos(error.line - 1, tokens[0].start),
 | |
|       to: CodeMirror.Pos(error.line - 1, tokens[tokens.length-1].end),
 | |
|     };
 | |
|   });
 | |
| });
 | |
| 
 | |
| function graphQLFetcher(graphQLParams) {
 | |
|   return graphql(schema, graphQLParams.query);
 | |
| }
 | |
| 
 | |
| var default_interpreter;
 | |
| class Playground extends React.Component {
 | |
|   constructor() {
 | |
|     super();
 | |
|     this.state = {pypyjs: false, stdout: '', response:''};
 | |
|   }
 | |
|   stdout() {
 | |
|     console.log('stdout', arguments);
 | |
|   }
 | |
|   componentDidMount() {
 | |
|     if (default_interpreter) {
 | |
|       this.pypy_interpreter = default_interpreter;
 | |
|       this.pypy_interpreter.stdout = this.stdout.bind(this);
 | |
|     }
 | |
|     else {
 | |
|       this.pypy_interpreter = new pypyjs_vm({
 | |
|         stdin: function(){},
 | |
|         stdout: this.stdout.bind(this),
 | |
|         stderr: function(){},
 | |
|         rootURL: `${PUBLIC_PATH}/playground/lib/`
 | |
|       });
 | |
|       default_interpreter = this.pypy_interpreter;
 | |
|     }
 | |
| 
 | |
|     this.pypyjs = this.pypy_interpreter.ready().then(() => {
 | |
|       return this.pypy_interpreter.exec(`
 | |
| import graphene
 | |
| import js
 | |
| from collections import OrderedDict
 | |
| from graphql.core.execution.executor import Executor
 | |
| from graphql.core.execution.middlewares.sync import SynchronousExecutionMiddleware
 | |
| from graphql.core.error import GraphQLError, format_error
 | |
| 
 | |
| def get_wrapped(f):
 | |
|     if hasattr(f, 'func_closure') and f.func_closure:
 | |
|         return get_wrapped(f.func_closure[0].cell_contents)
 | |
|     return f
 | |
| 
 | |
| class TrackResolver(SynchronousExecutionMiddleware):
 | |
|     @staticmethod
 | |
|     def run_resolve_fn(resolver, original_resolver):
 | |
|         if resolver.func.__module__ == '__main__':
 | |
|             line = get_wrapped(resolver.func).resolver.func_code.co_firstlineno
 | |
|             js.globals.markLine(line-3)
 | |
|         return SynchronousExecutionMiddleware.run_resolve_fn(resolver, original_resolver)
 | |
| 
 | |
| __graphene_executor = Executor([TrackResolver()], map_type=OrderedDict)
 | |
| `);
 | |
|     }).then(() => {
 | |
|       this.createSchema(this.props.initialSchema);
 | |
|     }).then(() => {
 | |
|       this.setState({pypyjs: true, response:'"Execute the query for see the results"'});
 | |
|     });
 | |
| 
 | |
|     window.markLine = (lineNo) => {
 | |
|       this.markLine(lineNo);
 | |
|     }
 | |
| 
 | |
|     this.editor = CodeMirror(ReactDOM.findDOMNode(this.refs.schemaCode), {
 | |
|       value: this.props.initialSchema,
 | |
|       mode:  "python",
 | |
|       theme: "graphene",
 | |
|       lineNumbers: true,
 | |
|       tabSize: 4,
 | |
|       indentUnit: 4,
 | |
|       gutters: ["CodeMirror-linenumbers", "breakpoints"],
 | |
|       lint: {
 | |
|         errors: [],
 | |
|       },
 | |
|     });
 | |
|     this.editor.on("change", this.onEditorChange.bind(this));
 | |
|   }
 | |
|   onEditorChange() {
 | |
|     if (this.changeTimeout) {
 | |
|       clearTimeout(this.changeTimeout);
 | |
|     }
 | |
|     if (this.props.onEditSchema) {
 | |
|       var value = this.editor.getValue();
 | |
|       if (value != this.props.initialSchema) {
 | |
|         this.props.onEditSchema(value)
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     this.changeTimeout = setTimeout(() =>
 | |
|       this.updateSchema()
 | |
|     , 300);
 | |
|   }
 | |
|   updateSchema() {
 | |
|     this.createSchema(this.editor.getValue());
 | |
|   }
 | |
|   createSchema(code) {
 | |
|     if (this.previousCode == code) return;
 | |
|     console.log('createSchema');
 | |
|     this.validSchema = null;
 | |
|     this.pypyjs.then(() => {
 | |
|       return this.pypy_interpreter.exec(`
 | |
| schema = None
 | |
| ${code}
 | |
| assert schema, 'You have to define a schema'
 | |
| `)
 | |
|     }).then(() => {
 | |
|       console.log('NO ERRORS');
 | |
|       this.removeErrors();
 | |
|       this.validSchema = true;
 | |
|     }, (err) => {
 | |
|       this.editor.options.lint.errors = [];
 | |
|       console.log('ERRORS', err);
 | |
|       this.logError(err);
 | |
|       this.validSchema = false;
 | |
|     }).then(this.updateGraphiQL.bind(this));
 | |
|     this.previousCode = code;
 | |
|   }
 | |
|   updateGraphiQL() {
 | |
|     if (this.validSchema) {
 | |
|       this.refs.graphiql.state.schema = null;
 | |
|       this.refs.graphiql.componentDidMount();
 | |
|       this.refs.graphiql.forceUpdate();
 | |
|       this.refs.graphiql.refs.docExplorer.forceUpdate();
 | |
|     }
 | |
|   }
 | |
|   logError(error) {
 | |
|     var lines = error.trace.split('\n');
 | |
|     var file_errors = lines.map((errorLine) => {
 | |
|       return errorLine.match(/File "<string>", line (\d+)/);
 | |
|     }).filter((x) => !! x);
 | |
|     if (!file_errors.length) return;
 | |
|     var line = parseInt(file_errors[file_errors.length-1][1]);
 | |
|     error.line = line-2;
 | |
|     if (error.name == "ImportError" && error.message == "No module named django") {
 | |
|       error.message = "Django is not supported yet in Playground editor";
 | |
|     }
 | |
|     this.editor.options.lint.errors.push(error);
 | |
|     CodeMirror.signal(this.editor, 'change', this.editor);
 | |
|   }
 | |
|   removeErrors() {
 | |
|     this.editor.options.lint.errors = [];
 | |
|     CodeMirror.signal(this.editor, 'change', this.editor);
 | |
|   }
 | |
|   fetcher (graphQLParams) {
 | |
|     if (!this.validSchema) {
 | |
|       return graphQLFetcher(arguments);
 | |
|     }
 | |
|     return this.execute(graphQLParams.query);
 | |
|   }
 | |
|   execute(query) {
 | |
|     // console.log('execute', query);
 | |
|     return this.pypyjs.then(() => {
 | |
|       var x = `
 | |
| import json
 | |
| result = __graphene_executor.execute(schema.schema, '''${query}''')
 | |
| result_dict = {};
 | |
| if result.errors:
 | |
|   result_dict['errors'] = [format_error(e) for e in result.errors]
 | |
| if result.data:
 | |
|   result_dict['data'] = result.data
 | |
| result_json = json.dumps(result_dict)
 | |
| `;
 | |
|       return this.pypy_interpreter.exec(x)
 | |
|     }
 | |
|     ).then(() =>
 | |
|       this.pypy_interpreter.get(`result_json`)
 | |
|     ).then((data) => {
 | |
|       var json_data = JSON.parse(data);
 | |
|       return json_data;
 | |
|     });
 | |
|   }
 | |
|   markLine(lineNo) {
 | |
|     console.log(lineNo);
 | |
|     var hlLine = this.editor.addLineClass(lineNo, "text", "activeline");
 | |
|     // var mark = this.editor.markText({line: lineNo, ch: 0}, {line: lineNo, ch: 10}, {className: "called-function"});
 | |
|     setTimeout(() => {
 | |
|         this.editor.removeLineClass(lineNo, "text", "activeline");
 | |
|     }, 1200);
 | |
|   }
 | |
|   render() {
 | |
|     return (
 | |
|       <div className="playground">
 | |
|         {!this.state.pypyjs?<div className="loading" />:null}
 | |
|         <div className="playground-schema">
 | |
|           <header className="playground-schema-header">
 | |
|             Schema
 | |
|           </header>
 | |
|           <div className="playground-schema-editor" ref="schemaCode" />
 | |
|         </div>
 | |
|         <div className="playground-graphiql">
 | |
|             <GraphiQL ref="graphiql" fetcher={this.fetcher.bind(this)} response={this.state.response} onEditQuery={this.props.onEditQuery} query={this.props.initialQuery}/>
 | |
|         </div>
 | |
|       </div>
 | |
|     );
 | |
|   }
 | |
| }
 | |
| 
 | |
| module.exports = Playground;
 |