First fully working version of the playground editor

This commit is contained in:
Syrus Akbary 2015-11-27 23:48:48 -08:00
parent 4e258b5def
commit 42db605fbd
14 changed files with 1449 additions and 96 deletions

7
.gitignore vendored
View File

@ -63,5 +63,10 @@ target/
/tests/django.sqlite /tests/django.sqlite
/graphene/index.json /graphene/index.json
/graphene/meta.json /graphene/meta.json
/meta.json
/index.json
/docs/playground/graphene-js/pypyjs-release-nojit/
/docs/static/playground/lib

View File

@ -54,7 +54,7 @@
} }
#graphiql-container .docExplorerShow { #graphiql-container .docExplorerShow {
background: #F9F9F9; background: transparent;
border: none; border: none;
border-bottom: solid 1px #d0d0d0; border-bottom: solid 1px #d0d0d0;
border-left: solid 1px rgba(0, 0, 0, 0.2); border-left: solid 1px rgba(0, 0, 0, 0.2);
@ -207,10 +207,9 @@
} }
#graphiql-container .execute-button { #graphiql-container .execute-button {
background: white; background: transparent;
border: solid 1px #999; border: solid 1px #777;
border-radius: 17px; border-radius: 17px;
box-shadow: 0 1px 0 #fff;
cursor: pointer; cursor: pointer;
fill: #444; fill: #444;
height: 34px; height: 34px;
@ -218,12 +217,22 @@
padding: 0; padding: 0;
width: 34px; width: 34px;
} }
#graphiql-container .execute-button path {
fill: #777;
}
#graphiql-container .execute-button:hover {
border-color: #333;
}
#graphiql-container .execute-button:hover path {
fill: #333;
}
#graphiql-container .execute-button:active { #graphiql-container .execute-button:active {
background: #EEE; background: white;
box-shadow: border-color: #db594c;
inset 0 0 2px rgba(0, 0, 0, 0.2), }
inset 0 0 6px rgba(0, 0, 0, 0.1); #graphiql-container .execute-button:active path {
fill: #db594c;
} }
#graphiql-container .execute-button:focus { #graphiql-container .execute-button:focus {
@ -380,72 +389,72 @@ div.CodeMirror-lint-message-error, div.CodeMirror-lint-message-warning {
} }
/* Comment */ /* Comment */
.cm-comment { #graphiql-container .cm-comment {
color: #999; color: #999;
} }
/* Punctuation */ /* Punctuation */
.cm-punctuation { #graphiql-container .cm-punctuation {
color: #555; color: #555;
} }
/* Keyword */ /* Keyword */
.cm-keyword { #graphiql-container .cm-keyword {
color: #B11A04; color: #B11A04;
} }
/* OperationName, FragmentName */ /* OperationName, FragmentName */
.cm-def { #graphiql-container .cm-def {
color: #D2054E; color: #D2054E;
} }
/* FieldName */ /* FieldName */
.cm-property { #graphiql-container .cm-property {
color: #1F61A0; color: #1F61A0;
} }
/* FieldAlias */ /* FieldAlias */
.cm-qualifier { #graphiql-container .cm-qualifier {
color: #1C92A9; color: #1C92A9;
} }
/* ArgumentName and ObjectFieldName */ /* ArgumentName and ObjectFieldName */
.cm-attribute { #graphiql-container .cm-attribute {
color: #8B2BB9; color: #8B2BB9;
} }
/* Number */ /* Number */
.cm-number { #graphiql-container .cm-number {
color: #2882F9; color: #2882F9;
} }
/* String */ /* String */
.cm-string { #graphiql-container .cm-string {
color: #D64292; color: #D64292;
} }
/* Boolean */ /* Boolean */
.cm-builtin { #graphiql-container .cm-builtin {
color: #D47509; color: #D47509;
} }
/* EnumValue */ /* EnumValue */
.cm-string-2 { #graphiql-container .cm-string-2 {
color: #0B7FC7; color: #0B7FC7;
} }
/* Variable */ /* Variable */
.cm-variable { #graphiql-container .cm-variable {
color: #397D13; color: #397D13;
} }
/* Directive */ /* Directive */
.cm-meta { #graphiql-container .cm-meta {
color: #B33086; color: #B33086;
} }
/* Type */ /* Type */
.cm-atom { #graphiql-container .cm-atom {
color: #CA9800; color: #CA9800;
} }
/* BASICS */ /* BASICS */

View File

@ -3,7 +3,6 @@
@import 'https://fonts.googleapis.com/css?family=Raleway:400,500,600,200,100&.css' @import 'https://fonts.googleapis.com/css?family=Raleway:400,500,600,200,100&.css'
global-reset()
normalize-css() normalize-css()
@import 'hljs.css' @import 'hljs.css'

View File

@ -9,30 +9,135 @@
display flex display flex
flex-direction row flex-direction row
min-width 960px min-width 960px
.loading
position absolute
display block
left 0
right 0
bottom 0
top 0
z-index 10000
background rgba(255,255,255,.6)
.playground-schema .playground-schema
min-width 400px min-width 400px
width 36% width 36%
border-right 1px solid #E0E0E0 border-right 1px solid #E0E0E0
box-shadow 0 0 8px rgba(0, 0, 0, 0.15) // box-shadow 0 0 8px rgba(0, 0, 0, 0.15)
position relative position relative
z-index 100 z-index 100
.CodeMirror display flex
position: absolute; flex-direction: column
top: 0;
left: 0;
height: 100%;
width: 100%;
font-size: 13px;
font-family: 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace;
color: #141823;
.cm-def .cm-def
&.called-function transition all .3s ease-in-out
background rgba(219, 89, 76, .2) background transparent
.activeline
.cm-def
$color = #D7D3F1
// $color = rgba(219, 89, 76, .2)
background $color
border-radius 1px border-radius 1px
box-shadow 0 0 0 3px rgba(219, 89, 76, .2) box-shadow 0 0 0 2px $color
.playground-schema-editor
flex 1
position relative
.CodeMirror
font-size: 13px;
position absolute
height 100%
width 100%
top 0
left 0
right 0
bottom 0
font-family: 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace;
color: #141823;
.CodeMirror-lines
padding 20px 0
.playground-schema-header
// height 48px
// font-family 'Raleway', sans-serif
// font-weight 300
// line-height 48px
// padding 0 10px
// border-bottom solid 1px #d0d0d0
height: 48px;
font-family: 'Raleway', sans-serif;
color: #999;
font-weight: 600;
font-size: 12px;
text-transform: uppercase;
line-height: 52px;
padding: 0 12px;
border-bottom: solid 1px #d0d0d0;
background: #F9F9F9;
.playground-graphiql .playground-graphiql
flex 1 flex 1
height 100% height 100%
.cm-s-graphene
/* Comment */
.cm-s-graphene .cm-comment
color: #999;
/* Punctuation */
.cm-s-graphene .cm-punctuation
color: #555;
/* Keyword */
.cm-s-graphene .cm-keyword
// color: #B11A04;
// color #D2054E
color #a71d5d
/* OperationName, FragmentName */
.cm-s-graphene .cm-def
// color: #D2054E;
color: #1F61A0;
/* FieldName */
.cm-s-graphene .cm-property
color: #333;
/* FieldAlias */
.cm-s-graphene .cm-qualifier
color: #1C92A9;
/* ArgumentName and ObjectFieldName */
.cm-s-graphene .cm-attribute
color: #8B2BB9;
/* Number */
.cm-s-graphene .cm-number
color: #2882F9;
/* String */
.cm-s-graphene .cm-string
color: #D64292;
/* Boolean */
.cm-s-graphene .cm-builtin
color: #D47509;
/* EnumValue */
.cm-s-graphene .cm-string-2
color: #0B7FC7;
/* Variable */
.cm-s-graphene .cm-variable
color: #333;
/* Directive */
.cm-s-graphene .cm-meta
color: #B33086;
/* Type */
.cm-s-graphene .cm-atom
color: #CA9800;

View File

@ -9,6 +9,7 @@ var CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = function(config, env) { module.exports = function(config, env) {
var IS_STATIC = env === 'static'; var IS_STATIC = env === 'static';
var entry = config._config.entry.slice(); var entry = config._config.entry.slice();
var publicPath = config._config.output.publicPath;
// var output = config._config.output; // var output = config._config.output;
// output.filename = "[name].js"; // output.filename = "[name].js";
config._config.entry = { config._config.entry = {
@ -25,9 +26,6 @@ module.exports = function(config, env) {
resolveLoader: { resolveLoader: {
root: path.join(__dirname, "node_modules"), root: path.join(__dirname, "node_modules"),
modulesDirectories: ['./'], modulesDirectories: ['./'],
alias: {
'copy': 'file-loader?name=[path][name].[ext]&context=./static',
}
}, },
resolve: { resolve: {
root: path.join(__dirname, "node_modules"), root: path.join(__dirname, "node_modules"),
@ -35,6 +33,7 @@ module.exports = function(config, env) {
'original-react': path.join(__dirname, "node_modules", "react"), 'original-react': path.join(__dirname, "node_modules", "react"),
'react/lib': path.join(__dirname, "node_modules", "react", "lib"), 'react/lib': path.join(__dirname, "node_modules", "react", "lib"),
'react': path.join(__dirname, 'patched-react.js'), 'react': path.join(__dirname, 'patched-react.js'),
'pypyjs': '../playground/graphene-js/pypyjs',
'playground-page': (env != "static")?'../playground/page':'../pages/_empty', 'playground-page': (env != "static")?'../playground/page':'../pages/_empty',
'playground-wrapper': (env == "develop")?'../playground/page':'../playground/wrapper', 'playground-wrapper': (env == "develop")?'../playground/page':'../playground/wrapper',
}, },
@ -45,7 +44,10 @@ module.exports = function(config, env) {
config.plugin('extract-css', ExtractTextPlugin, ["app.css"]); config.plugin('extract-css', ExtractTextPlugin, ["app.css"]);
} }
config.plugin('static', CopyWebpackPlugin, [[{ from: '../static'}]]); config.plugin('static', CopyWebpackPlugin, [[{ from: '../static'}]]);
config.plugin('define-env', webpack.DefinePlugin, [{"ENV": JSON.stringify(env)}]); config.plugin('define-env', webpack.DefinePlugin, [{
"ENV": JSON.stringify(env),
"PUBLIC_PATH": JSON.stringify(publicPath),
}]);
// if (env != "static") { // if (env != "static") {
// config.plugin('commons', webpack.optimize.CommonsChunkPlugin, ["commons.js"]); // config.plugin('commons', webpack.optimize.CommonsChunkPlugin, ["commons.js"]);
// } // }

View File

@ -5,7 +5,7 @@ export default class Html extends React.Component {
render() { render() {
var title = this.props.title || DocumentTitle.rewind(); var title = this.props.title || DocumentTitle.rewind();
return ( return (
<html lang={this.props.lang}> <html lang={this.props.lang} manifest="/graphene.appcache">
<head> <head>
<meta charSet="utf-8"/> <meta charSet="utf-8"/>
<meta httpEquiv="X-UA-Compatible" content="IE=edge"/> <meta httpEquiv="X-UA-Compatible" content="IE=edge"/>

View File

@ -13,12 +13,13 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"codemirror": "5.9.0",
"copy-webpack-plugin": "^0.2.0", "copy-webpack-plugin": "^0.2.0",
"es6-promise": "^3.0.2",
"extract-text-webpack-plugin": "^0.9.1", "extract-text-webpack-plugin": "^0.9.1",
"gatsby": "^0.7.2", "gatsby": "^0.7.2",
"graphiql": "^0.4.2", "graphiql": "^0.4.2",
"graphql": "^0.4.13", "graphql": "^0.4.13",
"codemirror": "5.9.0",
"jeet": "^6.1.2", "jeet": "^6.1.2",
"lodash": "^3.10.1", "lodash": "^3.10.1",
"nib": "^1.1.0", "nib": "^1.1.0",

View File

@ -0,0 +1 @@
pypy-release-nojit

View File

@ -0,0 +1,107 @@
//
// FunctionPromise: possibly-asynchronous function constructor.
//
// This is a prototype polyfill for a FunctionPromise object as described in:
//
// https://bugzilla.mozilla.org/show_bug.cgi?id=854627
//
// Where possible it will arrange for the function body to be parsed/compiled
// off of the main thread, with the function object returned asynchronously
// via a promise. The fallback implementation processes just falls back to
// the standard synchronous Function() constructor.
//
// It doesn't (yet) have the following features from the linked proposal:
//
// * ability to copy to different workers
// * ability to store in IndexedDB
//
function FunctionPromise(/* [args1[, args2[, ...argN]],], functionBody) */) {
var useFallback =
typeof window === "undefined" ||
window.FunctionPromise !== FunctionPromise ||
typeof document === "undefined" ||
typeof document.createElement === "undefined" ||
typeof document.head === "undefined" ||
typeof document.head.appendChild === "undefined" ||
typeof Blob === "undefined" ||
typeof URL === "undefined" ||
typeof URL.createObjectURL === "undefined";
var args = Array.prototype.slice.call(arguments);
// For the fallback case, we just use the normal Function constructor.
if (useFallback) {
try {
var fn = Function.apply(null, args);
return Promise.resolve(fn);
} catch (err) {
return Promise.reject(err);
}
}
// If we have all the necessary pieces, we can do this asynchronously
// by writing a <script> tag into the DOM.
var funcid = FunctionPromise._nextid++;
return new Promise(function(resolve, reject) {
try {
var funcSrc = [];
funcSrc.push("window.FunctionPromise._results[" + funcid + "]=");
funcSrc.push("function(");
if (args.length > 1) {
funcSrc.push(args[0]);
for (var i = 1; i < args.length - 1; i++) {
funcSrc.push(",");
funcSrc.push(args[i]);
}
}
funcSrc.push("){");
funcSrc.push(args[args.length - 1]);
funcSrc.push("}");
var dataUrl = URL.createObjectURL(new Blob(funcSrc));
var scriptTag = document.createElement("script");
var cleanup = function() {
URL.revokeObjectURL(dataUrl);
scriptTag.remove();
delete window.FunctionPromise._results[funcid];
}
scriptTag.onerror = function() {
reject(new Error("unknown error loading FunctionPromise"))
cleanup();
}
scriptTag.onload = function() {
if (window.FunctionPromise._results[funcid]) {
resolve(window.FunctionPromise._results[funcid]);
} else {
// No function, something must have gone wrong.
// Likely a syntax error in the function body string.
// Fall back to Function() constructor to surface it.
try {
Function.apply(null, args);
reject(new Error("unknown error fulfilling FunctionPromise"));
} catch (err) {
reject(err);
}
}
cleanup();
}
scriptTag.src = dataUrl;
document.head.appendChild(scriptTag);
} catch (err) {
reject(err);
}
});
}
FunctionPromise._nextid = 0;
FunctionPromise._results = {};
if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
if (typeof Promise === "undefined") {
Promise = require('es6-promise').Promise;
}
module.exports = FunctionPromise;
}

View File

@ -0,0 +1,32 @@
#!/bin/bash
if [ ! -d pypyjs-release-nojit ] ; then
git clone git@github.com:pypyjs/pypyjs-release-nojit.git
fi
GRAPHENE_DIR="$(python -c "import os; import graphene; print os.path.dirname(graphene.__file__)")"
GRAPHQL_DIR="$(python -c "import os; import graphql; print os.path.dirname(graphql.__file__)")"
GRAPHQL_RELAY_DIR="$(python -c "import os; import graphql_relay; print os.path.dirname(graphql_relay.__file__)")"
SIX_DIR="$(python -c "import os; import six; print six.__file__.rstrip('c')")"
cd pypyjs-release-nojit
eval python tools/module_bundler.py add ./lib/modules "$GRAPHENE_DIR"
eval python tools/module_bundler.py add ./lib/modules "$GRAPHQL_DIR"
eval python tools/module_bundler.py add ./lib/modules "$GRAPHQL_RELAY_DIR"
eval python tools/module_bundler.py add ./lib/modules "$SIX_DIR"
python ./tools/module_bundler.py preload ./lib/modules graphene
python ./tools/module_bundler.py preload ./lib/modules graphql
python ./tools/module_bundler.py preload ./lib/modules graphql_relay
python ./tools/module_bundler.py preload ./lib/modules six
python ./tools/module_bundler.py remove ./lib/modules unittest
lib_dirname=`perl -e 'use Cwd "abs_path";print abs_path(shift)' lib/`
if [ -d ../../../static/playground/lib ] ; then
rm ../../../static/playground/lib
fi
exec ln -s "$lib_dirname/" ../../../static/playground

View File

@ -0,0 +1,983 @@
//
// pypyjs: an experimental in-browser python environment.
//
(function() {
// Expose the main pypyjs function at global scope for this file,
// as well as in any module exports or 'window' object we can find.
if (this) {
this.pypyjs = pypyjs;
}
if (typeof window !== "undefined") {
window.pypyjs = pypyjs;
}
if (typeof module !== "undefined") {
if (typeof module.exports !== "undefined") {
module.exports = pypyjs;
}
}
// Generic debugging printf.
var debug = function(){};
if (typeof console !== "undefined") {
debug = console.log.bind(console);
} else if (typeof print !== "undefined" && typeof window === "undefined") {
debug = print;
}
// Find the directory containing this very file.
// It can be quite difficult depending on execution environment...
if (typeof __dirname === "undefined" || true) {
var __dirname = "./";
// A little hackery to find the URL of this very file.
// Throw an error, then parse the stack trace looking for filenames.
var errlines = (new Error()).stack.split("\n");
for (var i = 0; i < errlines.length; i++) {
var match = /(at Anonymous function \(|at |@)(.+\/)pypyjs.js/.exec(errlines[i]);
if (match) {
__dirname = match[2];
break;
}
}
}
if (__dirname.charAt(__dirname.length - 1) !== "/") {
__dirname += "/";
}
if (typeof Promise === "undefined") {
var Promise = require('es6-promise').Promise;
}
// Ensure we have reference to a 'FunctionPromise' constructor.
var FunctionPromise = require("./FunctionPromise.js");
if (typeof FunctionPromise === "undefined") {
throw "FunctionPromise object not found";
}
// Some extra goodies for nodejs.
if (typeof process !== 'undefined') {
if (Object.prototype.toString.call(process) === '[object process]') {
var fs = require("fs");
var path = require("path");
}
}
// Create functions for handling default stdio streams.
// These will be shared by all VM instances by default.
//
// We default stdout and stderr to process outputs if available,
// printing/logging functions otherwise, and /dev/null if nothing
// else is available. Unfortunately there's no good way to read
// synchronously from stdin in javascript, so that's always /dev/null.
var devNull = {
stdin: function() { return null; },
stdout: function() { },
stderr: function() { }
}
var stdio = {
stdin: null,
stdout: null,
stderr: null
}
stdio.stdin = devNull.stdin;
if (typeof process !== "undefined") {
if (typeof process.stdout !== "undefined") {
stdio.stdout = function(x) { process.stdout.write(x); }
}
if (typeof process.stderr !== "undefined") {
stdio.stderr = function(x) { process.stderr.write(x); }
}
}
var _print, _printErr;
if (typeof window === "undefined") {
// print, printErr from v8, spidermonkey
if (typeof print !== "undefined") {
_print = print;
}
if (typeof printErr !== "undefined") {
_printErr = printErr;
}
}
if (typeof console !== "undefined") {
if (typeof _print === "undefined") {
_print = console.log.bind(console);
}
if (typeof _printErr === "undefined") {
_printErr = console.error.bind(console);
}
}
if (stdio.stdout == null && typeof _print !== "undefined") {
// print()/console.log() will add a newline, so we buffer until we
// receive one and then let it add it for us.
stdio.stdout = (function() {
var buffer = [];
return function(data) {
for (var i = 0; i < data.length; i++) {
var x = data.charAt(i);
if (x !== "\n") {
buffer.push(x);
} else {
_print(buffer.join(""));
buffer.splice(undefined, buffer.length);
}
}
}
})();
}
if (stdio.stderr == null && typeof _printErr !== "undefined") {
// printErr()/console.error() will add a newline, so we buffer until we
// receive one and then let it add it for us.
stdio.stderr = (function() {
var buffer = [];
return function(data) {
for (var i = 0; i < data.length; i++) {
var x = data.charAt(i);
if (x !== "\n") {
buffer.push(x);
} else {
_printErr(buffer.join(""));
buffer.splice(undefined, buffer.length);
}
}
}
})();
}
if (stdio.stdout === null) {
stdio.stdout = devNull.stdout;
}
if (stdio.stderr === null) {
stdio.stderr = devNull.stderr;
}
function pypyjs(opts) {
opts = opts || {};
this.rootURL = opts.rootURL;
this.totalMemory = opts.totalMemory || 128 * 1024 * 1024;
this.autoLoadModules = opts.autoLoadModules || true;
this._pendingModules = {};
this._loadedModules = {};
this._allModules = {};
// Allow opts to override default IO streams.
this.stdin = opts.stdin || stdio.stdin;
this.stdout = opts.stdout || stdio.stdout;
this.stderr = opts.stderr || stdio.stderr;
// Default to finding files relative to this very file.
if (!this.rootURL && !pypyjs.rootURL) {
pypyjs.rootURL = __dirname;
}
if (this.rootURL && this.rootURL.charAt(this.rootURL.length - 1) !== "/") {
this.rootURL += "/";
}
// If we haven't already done so, fetch and load the code for the VM.
// We do this once and cache the result for re-use, so that we don't
// have to pay asmjs compilation overhead each time we create the VM.
if (! pypyjs._vmBuilderPromise) {
pypyjs._vmBuilderPromise = this.fetch("pypyjs.vm.js").then((function(xhr) {
// Parse the compiled code, hopefully asynchronously.
// Unfortunately our use of Function constructor here doesn't
// play very well with nodejs, where things like 'module' and
// 'require' are not in the global scope. We have to pass them
// in explicitly as arguments.
var funcBody = [
// This is the compiled code for the VM.
xhr.responseText,
'\n',
// Ensure that some functions are available on the Module,
// for linking with jitted code.
'if (!Module._jitInvoke && typeof _jitInvoke !== "undefined") {',
' Module._jitInvoke = _jitInvoke;',
'}',
// Keep some functions that are not exported by default, but
// which appear in this scope when evaluating the above.
"Module._emjs_make_handle = _emjs_make_handle;",
"Module._emjs_free = _emjs_free;",
// Call dependenciesFulfilled if it won't be done automatically.
"dependenciesFulfilled=function() { inDependenciesFulfilled(FS); };",
"if(!memoryInitializer||(!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER))dependenciesFulfilled();",
].join("");
return FunctionPromise("Module", "inDependenciesFulfilled", "require",
"module", "__filename", "__dirname", funcBody)
}).bind(this));
}
// Create a new instance of the compiled VM, bound to local state
// and a local Module object.
this._ready = new Promise((function(resolve, reject) {
// Initialize the Module object.
// We make it available on this object so that we can use
// its methods to execute code in the VM.
var Module = {};
this._module = Module;
Module.TOTAL_MEMORY = this.totalMemory;
// We will set up the filesystem manually when we're ready.
Module.noFSInit = true;
Module.thisProgram = "/lib/pypyjs/pypyjs.js";
Module.filePackagePrefixURL = this.rootURL || pypyjs.rootURL;
Module.memoryInitializerPrefixURL = this.rootURL || pypyjs.rootURL;
Module.locateFile = function(name) {
return (this.rootURL || pypyjs.rootURL) + name;
}
// Don't start or stop the program, just set it up.
// We'll call the API functions ourself.
Module.noInitialRun = true;
Module.noExitRuntime = true;
// Route stdin to an overridable method on the object.
var stdin = (function stdin() {
return this.stdin();
}).bind(this);
// Route stdout to an overridable method on the object.
// We buffer the output for efficiency.
var stdout_buffer = []
var stdout = (function stdout(x) {
var c = String.fromCharCode(x);
stdout_buffer.push(c);
if (c === "\n" || stdout_buffer.length >= 128) {
this.stdout(stdout_buffer.join(""));
stdout_buffer = [];
}
}).bind(this);
// Route stderr to an overridable method on the object.
// We do not buffer stderr.
var stderr = (function stderr(x) {
var c = String.fromCharCode(x);
this.stderr(c);
}).bind(this);
// This is where execution will continue after loading
// the memory initialization data, if any.
var initializedResolve, initializedReject;
var initializedP = new Promise(function(resolve, reject) {
initializedResolve = resolve;
initializedReject = reject;
});
var FS;
var dependenciesFulfilled = function(fs) {
FS = fs;
// Initialize the filesystem state.
try {
FS.init(stdin, stdout, stderr);
Module.FS_createPath("/", "lib/pypyjs/lib_pypy", true, false);
Module.FS_createPath("/", "lib/pypyjs/lib-python/2.7", true, false);
initializedResolve();
} catch (err) {
initializedReject(err);
}
}
// Begin fetching the metadata for available python modules.
// With luck these can download while we jank around compiling
// all of that javascript.
// XXX TODO: also load memory initializer this way.
var moduleDataP = this.fetch("modules/index.json");
pypyjs._vmBuilderPromise.then((function(vmBuilder) {
var args = [
Module,
dependenciesFulfilled,
typeof undefined,
typeof undefined,
typeof undefined,
typeof __dirname
];
// This links the async-compiled module into our Module object.
vmBuilder.apply(null, args);
return initializedP;
}).bind(this)).then((function() {
// Continue with processing the downloaded module metadata.
return moduleDataP.then((function(xhr) {
// Store the module index, and load any preload modules.
var modIndex = JSON.parse(xhr.responseText);
this._allModules = modIndex.modules;
if (modIndex.preload) {
for (var name in modIndex.preload) {
this._writeModuleFile(name, modIndex.preload[name]);
}
}
// It's finally safe to launch the VM.
Module.run();
Module._rpython_startup_code();
var pypy_home = Module.intArrayFromString("/lib/pypyjs/pypyjs.js");
pypy_home = Module.allocate(pypy_home, 'i8', Module.ALLOC_NORMAL);
Module._pypy_setup_home(pypy_home, 0);
Module._free(pypy_home);
var initCode = [
"import js",
"import sys; sys.platform = 'js'",
"import traceback",
"top_level_scope = {'__name__': '__main__'}"
];
initCode.forEach(function(codeStr) {
var code = Module.intArrayFromString(codeStr);
var code = Module.allocate(code, 'i8', Module.ALLOC_NORMAL);
if (!code) {
throw new pypyjs.Error('Failed to allocate memory');
}
var res = Module._pypy_execute_source(code);
if (res < 0) {
throw new pypyjs.Error('Failed to execute python code');
}
Module._free(code);
});
}).bind(this))
}).bind(this))
.then(resolve, reject);
}).bind(this));
};
// A simple file-fetching wrapper around XMLHttpRequest,
// that treats paths as relative to the pypyjs.js root url.
//
pypyjs.prototype.fetch = function (relpath, responseType) {
if (typeof window === "undefined") {
var localStorage = false;
}
else {
var localStorage = window.localStorage;
}
var use_cache = pypyjs.cacheKey && localStorage && relpath != "pypyjs.vm.js";
if (use_cache) {
var item = localStorage.getItem(pypyjs.cacheKey+':'+relpath);
if (item) {
return new Promise((function(resolve, reject) {
resolve({ responseText: item });
}))
}
}
// For the web, use XMLHttpRequest.
if (typeof XMLHttpRequest !== "undefined") {
return new Promise((function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if (xhr.status >= 400) {
reject(xhr)
} else {
if (use_cache && xhr.responseText) {
localStorage.setItem(pypyjs.cacheKey+':'+relpath, xhr.responseText);
}
resolve(xhr);
}
};
var rootURL = this.rootURL || pypyjs.rootURL;
xhr.open('GET', rootURL + relpath, true);
xhr.responseType = responseType || "text";
xhr.send(null);
}).bind(this));
}
// For nodejs, use fs.readFile.
if (typeof fs !== "undefined" && typeof fs.readFile !== "undefined") {
return new Promise((function(resolve, reject) {
var rootURL = this.rootURL || pypyjs.rootURL;
fs.readFile(path.join(rootURL, relpath), function(err, data) {
if (err) return reject(err);
resolve({ responseText: data.toString() });
});
}).bind(this));
}
// For spidermonkey, use snarf (which has a binary read mode).
if (typeof snarf !== "undefined") {
return new Promise((function(resolve, reject) {
var rootURL = this.rootURL || pypyjs.rootURL;
var data = snarf(rootURL + relpath);
resolve({ responseText: data });
}).bind(this));
}
// For d8, use read() and readbuffer().
if (typeof read !== "undefined" && typeof readbuffer !== "undefined") {
return new Promise((function(resolve, reject) {
var rootURL = this.rootURL || pypyjs.rootURL;
var data = read(rootURL + relpath);
resolve({ responseText: data });
}).bind(this));
}
return new Promise(function(resolve, reject) {
reject("unable to fetch files");
});
};
if (typeof localStorage !== "undefined") {
var localStorage = false;
}
// pypyjs.prototype.fetch = function fetch(relpath, responseType) {
// // For the web, use XMLHttpRequest.
// var use_cache = pypyjs.cacheKey && localStorage;
// if (use_cache) {
// if (var item = localStorage.getItem(pypyjs.cacheKey+'-'+relpath)) {
// resolve({ responseText: item });
// }
// }
// if (typeof XMLHttpRequest !== "undefined") {
// return new Promise((function(resolve, reject) {
// var xhr = new XMLHttpRequest();
// xhr.onload = function() {
// if (xhr.status >= 400) {
// reject(xhr)
// } else {
// console.log(xhr.responseText);
// if (use_cache && xhr.responseText) {
// localStorage.setItem(pypyjs.cacheKey+'-'+relpath, xhr.responseText);
// }
// resolve(xhr);
// }
// };
// var rootURL = this.rootURL || pypyjs.rootURL;
// xhr.open('GET', rootURL + relpath, true);
// xhr.responseType = responseType || "text";
// xhr.send(null);
// }).bind(this));
// }
// // For nodejs, use fs.readFile.
// if (typeof fs !== "undefined" && typeof fs.readFile !== "undefined") {
// return new Promise((function(resolve, reject) {
// var rootURL = this.rootURL || pypyjs.rootURL;
// fs.readFile(path.join(rootURL, relpath), function(err, data) {
// if (err) return reject(err);
// resolve({ responseText: data.toString() });
// });
// }).bind(this));
// }
// // For spidermonkey, use snarf (which has a binary read mode).
// if (typeof snarf !== "undefined") {
// return new Promise((function(resolve, reject) {
// var rootURL = this.rootURL || pypyjs.rootURL;
// var data = snarf(rootURL + relpath);
// resolve({ responseText: data });
// }).bind(this));
// }
// // For d8, use read() and readbuffer().
// if (typeof read !== "undefined" && typeof readbuffer !== "undefined") {
// return new Promise((function(resolve, reject) {
// var rootURL = this.rootURL || pypyjs.rootURL;
// var data = read(rootURL + relpath);
// resolve({ responseText: data });
// }).bind(this));
// }
// return new Promise(function(resolve, reject) {
// reject("unable to fetch files");
// });
// };
// Method to execute python source directly in the VM.
//
// This is the basic way to push code into the pypyjs VM.
// Calling code should not use it directly; rather we use it
// as a primitive to build up a nicer execution API.
//
pypyjs.prototype._execute_source = function _execute_source(code) {
var Module = this._module;
code = "try:\n" +
" " + code + "\n" +
"except Exception:\n" +
" typ, val, tb = sys.exc_info()\n" +
" err_name = getattr(typ, '__name__', str(typ))\n" +
" err_msg = str(val)\n" +
" err_trace = traceback.format_exception(typ, val, tb)\n" +
" err_trace = ''.join(err_trace)\n" +
" js.globals['pypyjs']._lastErrorName = err_name\n" +
" js.globals['pypyjs']._lastErrorMessage = err_msg\n" +
" js.globals['pypyjs']._lastErrorTrace = err_trace\n";
var code_chars = Module.intArrayFromString(code);
var code_ptr = Module.allocate(code_chars, 'i8', Module.ALLOC_NORMAL);
if (!code_ptr) {
return Promise.reject(new pypyjs.Error("Failed to allocate memory"));
}
var res = Module._pypy_execute_source(code_ptr);
Module._free(code_ptr);
// XXX TODO: races/re-entrancy on _lastError?
if (pypyjs._lastErrorName) {
var err = new pypyjs.Error(
pypyjs._lastErrorName,
pypyjs._lastErrorMessage,
pypyjs._lastErrorTrace
);
pypyjs._lastErrorName = null;
pypyjs._lastErrorMessage = null;
pypyjs._lastErrorTrace = null;
return Promise.reject(err);
}
if (res < 0) {
return Promise.reject(new pypyjs.Error("Error executing python code"));
}
return Promise.resolve(null);
}
function _escape(value) {
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
}
// Method to determine when the interpreter is ready.
//
// This method returns a promise that will resolve once the interpreter
// is ready for use.
//
pypyjs.prototype.ready = function ready() {
return this._ready;
}
// Method to execute some python code.
//
// This passes the given python code to the VM for execution.
// It's fairly directly analogous to the "exec" statement in python.
// It is not possible to directly access the result of the code, if any.
// Rather you should store it into a variable and then use the get() method.
//
pypyjs.prototype.exec = function exec(code) {
return this._ready.then((function() {
var p = Promise.resolve();
// Find any "import" statements in the code,
// and ensure the modules are ready for loading.
if (this.autoLoadModules) {
p = p.then((function() {
return this.findImportedNames(code);
}).bind(this))
.then((function(imports) {
return this.loadModuleData.apply(this, imports);
}).bind(this))
}
// Now we can execute the code in custom top-level scope.
code = 'exec \'\'\'' + _escape(code) + '\'\'\' in top_level_scope';
p = p.then((function() {
return this._execute_source(code);
}).bind(this));
return p;
}).bind(this));
}
// Method to evaluate an expression.
//
// This method evaluates an expression and returns its value (assuming the
// value can be translated into javascript). It's fairly directly analogous
// to the "eval" function in python.
//
// For backwards-compatibility reasons, it will also evaluate statements.
// This behaviour is deprecated and will be removed in a future release.
//
pypyjs.prototype.eval = function (expr) {
return this._ready.then((function() {
// First try to execute it as an expression.
code = "r = eval('" + _escape(expr) + "', top_level_scope)";
return this._execute_source(code);
}).bind(this)).then(
(function() {
// If that succeeded, return the result.
return this.get("r", true)
}).bind(this),
(function(err) {
if (err && err.name && err.name !== "SyntaxError") {
throw err;
}
// If that failed, try again via exec().
if (typeof console !== "undefined") {
console.warn("Calling pypyjs.eval() with statements is deprecated.");
console.warn("Use eval() for expressions, exec() for statements.");
}
return this.exec(expr);
}).bind(this)
)
}
// Method to evaluate some python code from a file..
//
// This fetches the named file and passes it to the VM for execution.
//
pypyjs.prototype.execfile = function execfile(filename) {
return this.fetch(filename).then((function(xhr) {
var code = xhr.responseText;
return this.exec(code);
}).bind(this));
}
// Method to read a python variable.
//
// This tries to convert the value in the named python variable into an
// equivalent javascript value and returns it. It will fail if the variable
// does not exist or contains a value that cannot be converted.
//
pypyjs._resultsID = 0;
pypyjs._resultsMap = {};
pypyjs.prototype.get = function get(name, _fromGlobals) {
var resid = ""+(pypyjs._resultsID++);
// We can read from global scope for internal use; don't do this from calling code!
if (_fromGlobals) {
var namespace = "globals()";
} else {
var namespace = "top_level_scope";
}
return this._ready.then((function() {
var code = namespace + ".get('" + _escape(name) + "', js.undefined)";
code = "js.convert(" + code + ")"
code = "js.globals['pypyjs']._resultsMap['" + resid + "'] = " + code;
return this._execute_source(code);
}).bind(this)).then((function() {
var res = pypyjs._resultsMap[resid];
delete pypyjs._resultsMap[resid];
return res;
}).bind(this));
}
// Method to set a python variable to a javascript value.
//
// This generates a handle to the given object, and arranges for the named
// python variable to reference it via that handle.
//
pypyjs.prototype.set = function set(name, value) {
return this._ready.then((function() {
var Module = this._module;
var h = Module._emjs_make_handle(value);
name = _escape(name);
var code = "top_level_scope['" + name + "'] = js.Value(" + h + ")";
return this._execute_source(code);
}).bind(this));
}
// Method to run an interactive REPL.
//
// This method takes takes callback function implementing the user
// input prompt, and runs a REPL loop using it. The prompt function
// may either return the input as a string, or a promise resolving to
// the input as a string. If not specified, we read from stdin (which
// works fine in e.g. nodejs, but is almost certainly not what you want
// in the browser, because it's blocking).
//
pypyjs.prototype.repl = function repl(prmpt) {
if (!prmpt) {
// If there's a custom stdin, or we're not in nodejs, then we should
// default to prompting on stdin/stdout. For nodejs, we can build
// an async prompt atop process.stdin.
var buffer = "";
if (this.stdin !== devNull.stdin || typeof process === "undefined") {
prmpt = (function(ps1) {
var input;
this.stdout(ps1);
var c = this.stdin();
while (c) {
var idx = c.indexOf("\n");
if (idx >= 0) {
var input = buffer + c.substr(0, idx + 1);
buffer = c.substr(idx + 1);
return input;
}
buffer += c;
c = this.stdin();
}
input = buffer;
buffer = "";
return input;
}).bind(this);
} else {
prmpt = (function(ps1) {
return new Promise((function(resolve, reject) {
this.stdout(ps1);
var slurp = function() {
process.stdin.once("readable", function() {
var chunk = process.stdin.read();
if (chunk === null) {
slurp();
} else {
chunk = chunk.toString();
var idx = chunk.indexOf("\n");
if (idx < 0) {
buffer += chunk;
slurp();
} else {
resolve(buffer + chunk.substr(0, idx + 1));
buffer = chunk.substr(idx + 1);
}
}
});
}
slurp();
}).bind(this));
}).bind(this);
}
}
// Set up an InteractiveConsole instance,
// then loop forever via recursive promises.
return this._ready.then((function() {
return this.loadModuleData("code");
}).bind(this)).then((function() {
return this._execute_source("import code");
}).bind(this)).then((function() {
return this._execute_source("c = code.InteractiveConsole(top_level_scope)");
}).bind(this)).then((function() {
return this._repl_loop(prmpt, ">>> ");
}).bind(this));
}
pypyjs.prototype._repl_loop = function _repl_loop(prmpt, ps1) {
return Promise.resolve().then((function() {
// Prompt for input, which may happen via async promise.
return prmpt.call(this, ps1);
}).bind(this)).then((function(input) {
// Push it into the InteractiveConsole, a line at a time.
var p = Promise.resolve();
input.split("\n").forEach((function(line) {
// Find any "import" statements in the code,
// and ensure the modules are ready for loading.
if (this.autoLoadModules) {
p = p.then((function() {
return this.findImportedNames(line);
}).bind(this))
.then((function(imports) {
return this.loadModuleData.apply(this, imports);
}).bind(this))
}
var code = 'r = c.push(\'' + _escape(line) + '\')';
p = p.then((function() {
return this._execute_source(code);
}).bind(this));
}).bind(this));
return p;
}).bind(this)).then((function() {
// Check the result from the final push.
return this.get("r", true)
}).bind(this)).then((function(r) {
// If r == 1, we're in a multi-line definition.
// Adjust the prompt accordingly.
if (r) {
return this._repl_loop(prmpt, "... ");
} else {
return this._repl_loop(prmpt, ">>> ");
}
}).bind(this));
}
// Method to look for "import" statements in a code string.
// Returns a promise that will resolve to a list of imported module names.
//
// XXX TODO: this is far from complete and should not be done with a regex.
// Perhaps we can call into python's "ast" module for this parsing?
//
var importStatementRE = /(from\s+([a-zA-Z0-9_\.]+)\s+)?import\s+\(?\s*([a-zA-Z0-9_\.\*]+(\s+as\s+[a-zA-Z0-9_]+)?[ \t]*,?[ \t]*)+[ \t]*\)?/g
pypyjs.prototype.findImportedNames = function findImportedNames(code) {
var match = null;
var imports = [];
importStatementRE.lastIndex = 0;
while ((match = importStatementRE.exec(code)) !== null) {
var relmod = match[2];
if (relmod) {
relmod = relmod + ".";
} else {
relmod = "";
}
var submods = match[0].split("import")[1];
while (submods && /[\s(]/.test(submods.charAt(0))) {
submods = submods.substr(1);
}
while (submods && /[\s)]/.test(submods.charAt(submods.length - 1))) {
submods = submods.substr(0, submods.length - 1);
}
submods = submods.split(/\s*,\s*/);
for (var i = 0; i < submods.length; i++) {
var submod = submods[i];
submod = submod.split(/\s*as\s*/)[0];
imports.push(relmod + submod);
}
}
return Promise.resolve(imports);
}
// Method to load the contents of a python module, along with
// any dependencies. This populates the relevant paths within
// the VMs simulated filesystem so that is can find and import
// the specified module.
//
pypyjs.prototype.loadModuleData = function loadModuleData(/* names */) {
// Each argument is a name that we want to import.
// We must find the longest prefix that is an available module
// and load it along with all its dependencies.
var modules = Array.prototype.slice.call(arguments);
return this._ready.then((function() {
var toLoad = {};
NEXTNAME: for (var i = 0; i < modules.length; i++) {
var name = modules[i];
// Find the nearest containing module for the given name.
// Note that it may not match a module at all, in which case we ignore it.
while (true) {
if (this._allModules[name]) {
break;
}
name = name.substr(0, name.lastIndexOf("."));
if (!name) continue NEXTNAME;
}
this._findModuleDeps(name, toLoad);
}
// Now ensure that each module gets loaded.
// XXX TODO: we could load these concurrently.
var p = Promise.resolve();
for (var name in toLoad) {
p = p.then(this._makeLoadModuleData(name));
}
return p;
}).bind(this));
}
pypyjs.prototype._findModuleDeps = function _findModuleDeps(name, seen) {
if (!seen) seen = {};
var deps = [];
// If we don't know about this module, ignore it.
if (!this._allModules[name]) {
return seen;
}
// Depend on any explicitly-named imports.
var imports = this._allModules[name].imports;
if (imports) {
for (var i = 0; i < imports.length; i++) {
deps.push(imports[i]);
}
}
// Depend on the __init__.py for packages.
if (this._allModules[name].dir) {
deps.push(name + ".__init__");
}
// Include the parent package, if any.
var idx = name.lastIndexOf(".");
if (idx !== -1) {
deps.push(name.substr(0, idx));
}
// Recurse for any previously-unseen dependencies.
seen[name] = true;
for (var i = 0; i < deps.length; i++) {
if (!seen[deps[i]]) {
this._findModuleDeps(deps[i], seen);
}
}
return seen;
}
pypyjs.prototype._makeLoadModuleData = function _makeLoadModuleData(name) {
return (function() {
// If we've already loaded this module, we're done.
if (this._loadedModules[name]) {
return Promise.resolve();
}
// If we're already in the process of loading it, use the existing promise.
if (this._pendingModules[name]) {
return this._pendingModules[name];
}
// If it's a package directory, there's not actually anything to do.
if (this._allModules[name].dir) {
return Promise.resolve();
}
// We need to fetch the module file and write it out.
var modfile = this._allModules[name].file;
var p = this.fetch("modules/" + modfile)
.then((function(xhr) {
var contents = xhr.responseText;
this._writeModuleFile(name, contents)
delete this._pendingModules[name];
}).bind(this))
this._pendingModules[name] = p;
return p;
}).bind(this);
}
pypyjs.prototype._writeModuleFile = function _writeModuleFile(name, data) {
var Module = this._module;
var file = this._allModules[name].file;
// Create the containing directory first.
var dir = file.split("/").slice(0, -1).join("/")
try {
Module.FS_createPath("/lib/pypyjs/lib_pypy", dir, true, false);
} catch (e) { }
// Now we can safely create the file.
var fullpath = "/lib/pypyjs/lib_pypy/" + file;
Module.FS_createDataFile(fullpath, "", data, true, false, true);
this._loadedModules[name] = true;
}
// An error class for reporting python exceptions back to calling code.
// XXX TODO: this could be a lot more user-friendly than a opaque error...
pypyjs.Error = function pypyjsError(name, message, trace) {
if (name && typeof message === "undefined") {
message = name;
name = "";
}
this.name = name || "pypyjs.Error";
this.message = message || "pypyjs Unknown Error";
this.trace = trace || "";
}
pypyjs.Error.prototype = new Error();
pypyjs.Error.prototype.constructor = pypyjs.Error;
// XXX TODO: expose the filesystem for manipulation by calling code.
// Add convenience methods directly on the 'pypyjs' function, that
// will invoke corresponding methods on a default VM instance.
// This makes it look like 'pypyjs' is a singleton VM instance.
pypyjs._defaultVM = null;
pypyjs.stdin = stdio.stdin
pypyjs.stdout = stdio.stdout
pypyjs.stderr = stdio.stderr
var PUBLIC_NAMES = ['ready', 'exec', 'eval', 'execfile', 'get', 'set',
'repl', 'loadModuleData'];
PUBLIC_NAMES.forEach(function(name) {
pypyjs[name] = function() {
if (!pypyjs._defaultVM) {
pypyjs._defaultVM = new pypyjs({
stdin: function(){ return pypyjs.stdin.apply(this, arguments); },
stdout: function(){ return pypyjs.stdout.apply(this, arguments); },
stderr: function(){ return pypyjs.stderr.apply(this, arguments); },
});
}
return pypyjs._defaultVM[name].apply(pypyjs._defaultVM, arguments)
}
})
// For nodejs, run a repl when invoked directly from the command-line.
return pypyjs;
})();

View File

@ -5,10 +5,18 @@ import CodeMirror from 'codemirror';
import { graphql } from 'graphql'; import { graphql } from 'graphql';
import GraphiQL from 'graphiql'; import GraphiQL from 'graphiql';
import schema from './schema'; import schema from './schema';
import pypyjs_vm from 'pypyjs';
import 'codemirror/mode/python/python'; import 'codemirror/mode/python/python';
import '../css/playground.styl'; import '../css/playground.styl';
if (typeof PUBLIC_PATH === "undefined") {
var PUBLIC_PATH = '';
}
pypyjs_vm.rootURL = `${PUBLIC_PATH}/playground/lib/`;
pypyjs_vm.cacheKey = 'graphene';
var baseCode = `import graphene var baseCode = `import graphene
class Query(graphene.ObjectType): class Query(graphene.ObjectType):
@ -36,28 +44,166 @@ function graphQLFetcher(graphQLParams) {
} }
// var schema = null; // var schema = null;
function syntaxError() {
var marker = document.createElement("div");
marker.style.color = "#822";
marker.innerHTML = "●";
return marker;
}
var default_interpreter;
class Playground extends React.Component { class Playground extends React.Component {
constructor() {
super();
this.state = {pypyjs: false, stdout: '', response:''};
}
stdout() {
console.log('stdout', arguments);
}
componentDidMount() { 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");
}).then(() => {
this.createSchema(baseCode);
}).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), { this.editor = CodeMirror(ReactDOM.findDOMNode(this.refs.schemaCode), {
value: baseCode, value: baseCode,
mode: "python", mode: "python",
lineNumbers: true, theme: "graphene",
// lineNumbers: true,
tabSize: 4, tabSize: 4,
indentUnit: 4,
gutters: ["CodeMirror-linenumbers", "breakpoints"]
});
this.editor.on("change", this.onEditorChange.bind(this));
}
onEditorChange() {
if (this.changeTimeout) {
clearTimeout(this.changeTimeout);
}
this.changeTimeout = setTimeout(() =>
this.updateSchema()
, 300);
}
updateSchema() {
this.createSchema(this.editor.getValue());
}
createSchema(code) {
this.validSchema = null;
this.pypyjs.then(() => {
return this.pypy_interpreter.exec(`
schema = None
${code}
assert schema, 'You have to define a schema'
`)
}, (err) => {
this.validSchema = false;
// this.editor.setGutterMarker(5, "breakpoints", syntaxError());
console.log('ERROR', err);
}).then(() => {
if (this.validSchema === null) {
this.validSchema = true;
}
}).then(this.updateGraphiQL.bind(this));
}
updateGraphiQL() {
if (this.validSchema) {
this.refs.graphiql.state.schema = null;
this.refs.graphiql.componentDidMount();
this.refs.graphiql.forceUpdate();
this.refs.graphiql.refs.docExplorer.forceUpdate();
}
}
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 js
import json
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)
executor = Executor([TrackResolver()], map_type=OrderedDict)
result = 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;
}); });
this.markLine(6)
} }
markLine(lineNo) { markLine(lineNo) {
var mark = this.editor.markText({line: lineNo, ch: 0}, {line: lineNo, ch: 30}, {className: "called-function"}); 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(() => { setTimeout(() => {
mark.clear(); this.editor.removeLineClass(lineNo, "text", "activeline");
}, 2000); }, 1200);
} }
render() { render() {
return ( return (
<div className="playground"> <div className="playground">
<div className="playground-schema" ref="schemaCode"/> {!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"> <div className="playground-graphiql">
<GraphiQL ref="graphiql" fetcher={graphQLFetcher} schema={schema} /> <GraphiQL ref="graphiql" fetcher={this.fetcher.bind(this)} response={this.state.response} />
</div> </div>
</div> </div>
); );

View File

@ -1,59 +1,15 @@
/**
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
import { import {
GraphQLObjectType, GraphQLObjectType,
GraphQLSchema,
GraphQLString, GraphQLString,
GraphQLSchema,
} from 'graphql'; } from 'graphql';
var GREETINGS = {
hello: 'Hello worlasdfasdfasssdfasdfasdasdd',
};
/**
* Objects.
* Build up a portrait of your data universe
* using the object type. Here, we define a
* type of object that has a 'hello' field
* that is of the string type.
*/
var GreetingsType = new GraphQLObjectType({
name: 'Greetings',
fields: () => ({
hello: {type: GraphQLString},
}),
});
/**
* The schema.
* Here we export a schema that offers one root
* field named 'greetings', and a method to
* resolve its data.
*
* To learn more about writing GraphQL schemas for Relay, visit:
* https://github.com/graphql/graphql-relay-js
*/
export default new GraphQLSchema({ export default new GraphQLSchema({
query: new GraphQLObjectType({ query: new GraphQLObjectType({
name: 'Query', name: 'Query',
fields: () => ({ fields: () => ({
greetings: { __emptyField: {type: GraphQLString},
type: GreetingsType,
// Here we define a resolver that returns
// the data defined above. Were this schema
// executing on the server side, you could
// write a resolve method that fetches
// live data from a database.
resolve: () => GREETINGS,
},
}), }),
}), }),
}); });

7
docs/static/graphene.appcache vendored Normal file
View File

@ -0,0 +1,7 @@
CACHE MANIFEST
# 2015-11-27 v1.0.0
/playground/lib/pypyjs.vm.js
/playground/lib/pypyjs.vm.js.zmem
NETWORK:
*