├── CNAME
├── .gitignore
├── website
├── src
│ ├── parsers
│ │ ├── regexp
│ │ │ ├── codeExample.txt
│ │ │ ├── index.js
│ │ │ ├── transformers
│ │ │ │ └── regexp-tree
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ └── regexp-tree.js
│ │ ├── scala
│ │ │ ├── codeExample.txt
│ │ │ ├── index.js
│ │ │ └── scalameta.js
│ │ ├── json
│ │ │ ├── codeExample.txt
│ │ │ ├── index.js
│ │ │ └── json-to-ast.js
│ │ ├── handlebars
│ │ │ ├── codeExample.txt
│ │ │ ├── index.js
│ │ │ ├── transformers
│ │ │ │ ├── glimmer
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ │ └── glimmer-compiler
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ ├── handlebars.js
│ │ │ ├── glimmer.js
│ │ │ └── utils
│ │ │ │ └── defaultHandlebarsParserInterface.js
│ │ ├── icu
│ │ │ ├── codeExample.txt
│ │ │ ├── index.js
│ │ │ └── intl-messageformat-parser.js
│ │ ├── html
│ │ │ ├── codeExample.txt
│ │ │ ├── index.js
│ │ │ ├── parse5.js
│ │ │ └── htmlparser2.js
│ │ ├── sql
│ │ │ ├── codeExample.txt
│ │ │ ├── index.js
│ │ │ └── sqlite-parser.js
│ │ ├── lua
│ │ │ ├── index.js
│ │ │ ├── codeExample.txt
│ │ │ └── luaparse.js
│ │ ├── css
│ │ │ ├── index.js
│ │ │ ├── codeExample.txt
│ │ │ ├── utils
│ │ │ │ └── defaultCSSParserInterface.js
│ │ │ ├── transformers
│ │ │ │ └── postcss
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ ├── rework.js
│ │ │ ├── csstree.js
│ │ │ ├── cssom.js
│ │ │ └── postcss.js
│ │ ├── markdown
│ │ │ ├── codeExample.txt
│ │ │ ├── index.js
│ │ │ └── remark.js
│ │ ├── php
│ │ │ ├── index.js
│ │ │ ├── codeExample.txt
│ │ │ └── php-parser.js
│ │ ├── js
│ │ │ ├── transformers
│ │ │ │ ├── eslint1
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ ├── loadRulesShim.js
│ │ │ │ │ └── index.js
│ │ │ │ ├── eslint2
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ │ ├── eslint3
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ │ ├── eslint4
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ │ ├── babel
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ │ ├── prettier
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ │ ├── babel6
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ │ ├── babel7
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ │ └── jscodeshift
│ │ │ │ │ ├── codeExample.txt
│ │ │ │ │ └── index.js
│ │ │ ├── index.js
│ │ │ ├── utils
│ │ │ │ ├── defaultESTreeParserInterface.js
│ │ │ │ ├── eslint4Utils.js
│ │ │ │ └── eslintUtils.js
│ │ │ ├── codeExample.txt
│ │ │ ├── babel-eslint.js
│ │ │ ├── esformatter.js
│ │ │ ├── flow.js
│ │ │ ├── acorn-to-esprima.js
│ │ │ ├── typescript-eslint-parser.js
│ │ │ ├── esprima.js
│ │ │ ├── uglify.js
│ │ │ ├── shift.js
│ │ │ ├── espree.js
│ │ │ ├── acorn.js
│ │ │ ├── babylon6.js
│ │ │ ├── babylon7.js
│ │ │ ├── babylon.js
│ │ │ └── recast.js
│ │ ├── yaml
│ │ │ ├── index.js
│ │ │ └── yaml-ast-parser.js
│ │ ├── graphql
│ │ │ ├── index.js
│ │ │ ├── codeExample.txt
│ │ │ └── graphql-js.js
│ │ ├── webidl
│ │ │ ├── index.js
│ │ │ ├── webidl2.js
│ │ │ └── codeExample.txt
│ │ ├── glsl
│ │ │ ├── index.js
│ │ │ ├── codeExample.txt
│ │ │ └── glsl-parser.js
│ │ ├── utils
│ │ │ ├── compileModule.js
│ │ │ ├── transformJSCode.js
│ │ │ ├── defaultParserInterface.js
│ │ │ └── SettingsRenderer.js
│ │ └── index.js
│ ├── shims
│ │ └── jest-validate.js
│ ├── components
│ │ ├── visualization
│ │ │ ├── index.js
│ │ │ ├── JSON.js
│ │ │ ├── css
│ │ │ │ └── tree.css
│ │ │ ├── tree
│ │ │ │ ├── CompactObjectView.js
│ │ │ │ ├── CompactArrayView.js
│ │ │ │ └── RecursiveTreeElement.js
│ │ │ └── Tree.js
│ │ ├── LoadingIndicator.js
│ │ ├── buttons
│ │ │ ├── NewButton.js
│ │ │ ├── ShareButton.js
│ │ │ ├── SaveButton.js
│ │ │ ├── PrettierButton.js
│ │ │ ├── ForkButton.js
│ │ │ ├── ParserButton.js
│ │ │ ├── SnippetButton.js
│ │ │ ├── CategoryButton.js
│ │ │ └── TransformButton.js
│ │ ├── LocalStorage.js
│ │ ├── ErrorMessage.js
│ │ ├── dialogs
│ │ │ ├── ShareDialog.js
│ │ │ └── SettingsDialog.js
│ │ ├── getFocusPath.js
│ │ ├── Transformer.js
│ │ ├── GistBanner.js
│ │ ├── JSONEditor.js
│ │ ├── Toolbar.js
│ │ └── JSCodeshiftEditor.js
│ ├── storage
│ │ ├── api.js
│ │ └── index.js
│ ├── utils
│ │ ├── logger.js
│ │ ├── debounce.js
│ │ ├── stringify.js
│ │ └── url.js
│ ├── containers
│ │ ├── LoadingIndicatorContainer.js
│ │ ├── PasteDropTargetContainer.js
│ │ ├── ErrorMessageContainer.js
│ │ ├── ShareDialogContainer.js
│ │ ├── ASTOutputContainer.js
│ │ ├── CodeEditorContainer.js
│ │ ├── SettingsDialogContainer.js
│ │ ├── TransformerContainer.js
│ │ └── ToolbarContainer.js
│ └── store
│ │ ├── selectors.js
│ │ └── actions.js
├── packages
│ ├── babel5
│ │ ├── index.js
│ │ ├── babel5-package.js
│ │ └── package.json
│ ├── babel6
│ │ ├── index.js
│ │ ├── babel6-package.js
│ │ └── package.json
│ ├── babel7
│ │ ├── index.js
│ │ ├── babel7-package.js
│ │ └── package.json
│ ├── babylon5
│ │ ├── index.js
│ │ ├── babylon-package.js
│ │ └── package.json
│ ├── babylon6
│ │ ├── index.js
│ │ ├── babylon-package.js
│ │ └── package.json
│ ├── babylon7
│ │ ├── index.js
│ │ ├── babylon-package.js
│ │ └── package.json
│ ├── eslint1
│ │ ├── package.js
│ │ ├── package.json
│ │ └── index.js
│ ├── eslint3
│ │ ├── eslint3-package.js
│ │ ├── package.json
│ │ └── index.js
│ ├── eslint4
│ │ ├── eslint4-package.js
│ │ ├── package.json
│ │ └── index.js
│ └── eslint2
│ │ ├── package.json
│ │ └── index.js
├── favicon.png
├── postcss.config.js
├── fontcustom
│ ├── fontcustom_ded1f9e27e44b12eb0dbab11fa9eb21b.eot
│ ├── fontcustom_ded1f9e27e44b12eb0dbab11fa9eb21b.ttf
│ ├── fontcustom_ded1f9e27e44b12eb0dbab11fa9eb21b.woff
│ ├── fontcustom_fa81bdf903b1ca9429bee04d81a635dd.eot
│ ├── fontcustom_fa81bdf903b1ca9429bee04d81a635dd.ttf
│ ├── fontcustom_fa81bdf903b1ca9429bee04d81a635dd.woff
│ ├── fontcustom_ded1f9e27e44b12eb0dbab11fa9eb21b.woff2
│ ├── README.md
│ ├── input-svg
│ │ ├── scala.svg
│ │ ├── GraphQL_Logo.svg
│ │ ├── icu.svg
│ │ └── handlebars.svg
│ ├── fontcustom.css
│ └── config.yml
├── index.ejs
└── .fontcustom-manifest.json
├── assets
├── ast.png
└── source.png
├── .gitmodules
├── app.json
├── server
├── constants.js
├── package.json
├── handlers
│ ├── gist
│ │ ├── loadGist.js
│ │ ├── index.js
│ │ └── saveAnonymousGist.js
│ └── parse.js
└── index.js
├── scripts
├── deploy.sh
├── build-site.sh
└── definition-generator.js
├── .travis.yml
└── .eslintrc
/CNAME:
--------------------------------------------------------------------------------
1 | astexplorer.net
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /out
2 | node_modules
3 | .idea
4 |
--------------------------------------------------------------------------------
/website/src/parsers/regexp/codeExample.txt:
--------------------------------------------------------------------------------
1 | /[a-z]/i
--------------------------------------------------------------------------------
/website/packages/babel5/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babel-core');
2 |
--------------------------------------------------------------------------------
/website/packages/babel6/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babel-core');
2 |
--------------------------------------------------------------------------------
/website/packages/babel7/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babel-core');
2 |
--------------------------------------------------------------------------------
/website/packages/babylon5/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babylon');
2 |
--------------------------------------------------------------------------------
/website/packages/babylon6/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babylon');
2 |
--------------------------------------------------------------------------------
/website/packages/babylon7/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babylon');
2 |
--------------------------------------------------------------------------------
/website/packages/eslint1/package.js:
--------------------------------------------------------------------------------
1 | module.exports = require('eslint/package.json');
2 |
--------------------------------------------------------------------------------
/website/src/shims/jest-validate.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | validate(){},
3 | };
4 |
--------------------------------------------------------------------------------
/assets/ast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/josephfrazier/astexplorer/master/assets/ast.png
--------------------------------------------------------------------------------
/assets/source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/josephfrazier/astexplorer/master/assets/source.png
--------------------------------------------------------------------------------
/website/packages/babel5/babel5-package.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babel-core/package.json');
2 |
--------------------------------------------------------------------------------
/website/packages/babel6/babel6-package.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babel-core/package.json');
2 |
--------------------------------------------------------------------------------
/website/packages/babel7/babel7-package.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babel-core/package.json');
2 |
--------------------------------------------------------------------------------
/website/packages/babylon5/babylon-package.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babylon/package.json');
2 |
--------------------------------------------------------------------------------
/website/packages/babylon6/babylon-package.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babylon/package.json');
2 |
--------------------------------------------------------------------------------
/website/packages/babylon7/babylon-package.js:
--------------------------------------------------------------------------------
1 | module.exports = require('babylon/package.json');
2 |
--------------------------------------------------------------------------------
/website/packages/eslint3/eslint3-package.js:
--------------------------------------------------------------------------------
1 | module.exports = require('eslint/package.json');
2 |
--------------------------------------------------------------------------------
/website/packages/eslint4/eslint4-package.js:
--------------------------------------------------------------------------------
1 | module.exports = require('eslint/package.json');
2 |
--------------------------------------------------------------------------------
/website/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/josephfrazier/astexplorer/master/website/favicon.png
--------------------------------------------------------------------------------
/website/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('autoprefixer')
4 | ]
5 | }
--------------------------------------------------------------------------------
/website/src/parsers/scala/codeExample.txt:
--------------------------------------------------------------------------------
1 | object Main {
2 | def main(args: Array[String]): Unit = {
3 | println("Hello, World!")
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/website/src/parsers/json/codeExample.txt:
--------------------------------------------------------------------------------
1 | {
2 | "key1": [true, false, null],
3 | "key2": {
4 | "key3": [1, 2, "3", 1e10, 1e-3]
5 | }
6 | }
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/codeExample.txt:
--------------------------------------------------------------------------------
1 |
My first paragraph.
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/website/fontcustom/fontcustom_ded1f9e27e44b12eb0dbab11fa9eb21b.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/josephfrazier/astexplorer/master/website/fontcustom/fontcustom_ded1f9e27e44b12eb0dbab11fa9eb21b.woff2
--------------------------------------------------------------------------------
/website/src/parsers/sql/codeExample.txt:
--------------------------------------------------------------------------------
1 | --
2 | -- This is an example query
3 | --
4 | SELECT
5 | foo, bar as baz
6 | FROM
7 | mytable
8 | WHERE
9 | foo LIKE '%neat%'
10 | ORDER BY
11 | foo DESC
12 |
--------------------------------------------------------------------------------
/website/src/parsers/lua/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/lua/lua';
2 |
3 | export const id = 'lua';
4 | export const displayName = 'Lua';
5 | export const mimeTypes = [];
6 | export const fileExtension = 'lua';
7 |
--------------------------------------------------------------------------------
/website/packages/babylon5/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babylon5",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "dependencies": {
7 | "babylon": "^5.8.38"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/packages/babylon6/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babylon6",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "dependencies": {
7 | "babylon": "^6.1.21"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/src/parsers/css/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/css/css';
2 |
3 | export const id = 'css';
4 | export const displayName = 'CSS';
5 | export const mimeTypes = ['text/css'];
6 | export const fileExtension = 'css';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/markdown/codeExample.txt:
--------------------------------------------------------------------------------
1 | # Hello
2 |
3 | Some *emphasis*, **importance**, and `code`.
4 |
5 | ---
6 |
7 | ```javascript
8 | console.log('!');
9 | ```
10 |
11 | * foo
12 | * bar
13 | * baz
14 |
--------------------------------------------------------------------------------
/website/src/parsers/sql/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/sql/sql';
2 |
3 | export const id = 'sql';
4 | export const displayName = 'SQL';
5 | export const mimeTypes = ['text/x-sql'];
6 | export const fileExtension = 'sql';
7 |
--------------------------------------------------------------------------------
/website/packages/babylon7/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babylon7",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "dependencies": {
7 | "babylon": "7.0.0-beta.12"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/src/parsers/icu/index.js:
--------------------------------------------------------------------------------
1 | // import 'codemirror/mode/html/html';
2 |
3 | export const id = 'icu';
4 | export const displayName = 'ICU';
5 | export const mimeTypes = ['text/plain'];
6 | export const fileExtension = 'txt';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/php/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/php/php';
2 |
3 | export const id = 'php';
4 | export const displayName = 'PHP';
5 | export const mimeTypes = ['application/php'];
6 | export const fileExtension = 'php';
7 |
--------------------------------------------------------------------------------
/website/src/storage/api.js:
--------------------------------------------------------------------------------
1 | import 'isomorphic-fetch';
2 |
3 | const API_HOST = process.env.API_HOST || '';
4 |
5 | export default function api(path, options) {
6 | return fetch(`${API_HOST}/api/v1${path}`, options);
7 | }
8 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/eslint1/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default function(context) {
2 | return {
3 | TemplateLiteral(node) {
4 | context.report(node, 'Do not use template literals');
5 | }
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/eslint2/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default function(context) {
2 | return {
3 | TemplateLiteral(node) {
4 | context.report(node, 'Do not use template literals');
5 | }
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/eslint3/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default function(context) {
2 | return {
3 | TemplateLiteral(node) {
4 | context.report(node, 'Do not use template literals');
5 | }
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/eslint4/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default function(context) {
2 | return {
3 | TemplateLiteral(node) {
4 | context.report(node, 'Do not use template literals');
5 | }
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/website/src/parsers/scala/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/clike/clike';
2 |
3 | export const id = 'text/x-scala';
4 | export const displayName = 'Scala';
5 | export const mimeTypes = [];
6 | export const fileExtension = 'scala';
7 |
--------------------------------------------------------------------------------
/website/packages/babel5/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babel5",
3 | "version": "1.0.0",
4 | "description": "Wrapper for Babel v5",
5 | "main": "index.js",
6 | "dependencies": {
7 | "babel-core": "^5.8.38"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/packages/babel6/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babel6",
3 | "version": "1.0.0",
4 | "description": "Wrapper for Babel6",
5 | "main": "index.js",
6 | "dependencies": {
7 | "babel-core": "^6.2.0"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/packages/eslint1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint1",
3 | "version": "1.0.0",
4 | "description": "Wrapper for ESLint 1",
5 | "main": "index.js",
6 | "dependencies": {
7 | "eslint": "^1.10.3"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/packages/eslint2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint2",
3 | "version": "1.0.0",
4 | "description": "Wrapper for ESLint 2",
5 | "main": "index.js",
6 | "dependencies": {
7 | "eslint": "^2.5.3"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/packages/eslint3/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint3",
3 | "version": "1.0.0",
4 | "description": "Wrapper for ESLint 3",
5 | "main": "index.js",
6 | "dependencies": {
7 | "eslint": "^3.16.1"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/packages/eslint4/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint4",
3 | "version": "1.0.0",
4 | "description": "Wrapper for ESLint 4",
5 | "main": "index.js",
6 | "dependencies": {
7 | "eslint": "^4.0.0"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/src/parsers/yaml/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/yaml/yaml';
2 |
3 | export const id = 'yaml';
4 | export const displayName = 'YAML';
5 | export const mimeTypes = ['application/yaml'];
6 | export const fileExtension = 'yaml';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/html/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/htmlmixed/htmlmixed';
2 |
3 | export const id = 'htmlmixed';
4 | export const displayName = 'HTML';
5 | export const mimeTypes = ['text/html'];
6 | export const fileExtension = 'html';
7 |
--------------------------------------------------------------------------------
/website/packages/babel7/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babel7",
3 | "version": "1.0.0",
4 | "description": "Wrapper for Babel v7",
5 | "main": "index.js",
6 | "dependencies": {
7 | "babel-core": "7.0.0-alpha.12"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/src/parsers/graphql/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror-graphql/mode';
2 |
3 | export const id = 'graphql';
4 | export const displayName = 'GraphQL';
5 | export const mimeTypes = ['application/graphql'];
6 | export const fileExtension = 'graphql';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/json/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/javascript/javascript';
2 |
3 | export const id = 'json';
4 | export const displayName = 'JSON';
5 | export const mimeTypes = ['text/javascript'];
6 | export const fileExtension = 'json';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/webidl/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/webidl/webidl';
2 |
3 | export const id = 'webidl';
4 | export const displayName = 'Web IDL';
5 | export const mimeTypes = ['text/x-webidl'];
6 | export const fileExtension = 'webidl';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/js/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/javascript/javascript';
2 |
3 | export const id = 'javascript';
4 | export const displayName = 'JavaScript';
5 | export const mimeTypes = ['text/javascript'];
6 | export const fileExtension = 'js';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/markdown/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/markdown/markdown';
2 |
3 | export const id = 'markdown';
4 | export const displayName = 'Markdown';
5 | export const mimeTypes = ['text/markdown'];
6 | export const fileExtension = 'md';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/regexp/transformers/regexp-tree/codeExample.txt:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | Char({node}) {
3 | // Replace 'a' chars with 'b'.
4 | if (node.kind === 'simple' && node.value === 'a') {
5 | node.value = 'b';
6 | }
7 | }
8 | };
--------------------------------------------------------------------------------
/website/src/parsers/glsl/index.js:
--------------------------------------------------------------------------------
1 | import './codemirror-mode/glsl';
2 |
3 | export const id = 'glsl';
4 | export const displayName = 'GLSL';
5 | export const mimeTypes = ['x-shader/x-vertex', 'x-shader/x-fragment'];
6 | export const fileExtension = 'glsl';
7 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astexplorer",
3 | "scripts": {
4 | },
5 | "env": {
6 | },
7 | "formation": {
8 | },
9 | "addons": [
10 |
11 | ],
12 | "buildpacks": [
13 | {
14 | "url": "heroku/nodejs"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/handlebars/handlebars';
2 |
3 | export const id = 'handlebars';
4 | export const displayName = 'Handlebars';
5 | export const mimeTypes = ['text/x-handlebars-template'];
6 | export const fileExtension = 'handlebars';
7 |
--------------------------------------------------------------------------------
/website/src/utils/logger.js:
--------------------------------------------------------------------------------
1 | export function logEvent(category, action, label) {
2 | global.ga('send', 'event', category, action, label);
3 | }
4 |
5 | export function logError(message, fatal) {
6 | global.ga('send', 'exception', {exDescription: message, exFatal: fatal});
7 | }
8 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/transformers/glimmer/codeExample.txt:
--------------------------------------------------------------------------------
1 | module.exports = class {
2 | transform(ast) {
3 | this.syntax.traverse(ast, {
4 | ElementNode(node) {
5 | node.tag = node.tag.split('').reverse().join('');
6 | }
7 | });
8 |
9 | return ast;
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/babel/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default function ({Plugin, types: t}) {
2 | return new Plugin('ast-transform', {
3 | visitor: {
4 | Identifier(node) {
5 | return t.identifier(node.name.split('').reverse().join(''));
6 | }
7 | }
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/transformers/glimmer-compiler/codeExample.txt:
--------------------------------------------------------------------------------
1 | module.exports = class {
2 | transform(ast) {
3 | this.syntax.traverse(ast, {
4 | ElementNode(node) {
5 | node.tag = node.tag.split('').reverse().join('');
6 | }
7 | });
8 |
9 | return ast;
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/prettier/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default {
2 | "printWidth": 80,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": false,
6 | "singleQuote": false,
7 | "trailingComma": "none",
8 | "bracketSpacing": true,
9 | "jsxBracketSameLine": false,
10 |
11 | "parser": "babylon"
12 | }
13 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/eslint1/loadRulesShim.js:
--------------------------------------------------------------------------------
1 | module.exports = function loadRules(/*rulesDir*/) {
2 | // By default, ESLint tries to load all available rules by looking for every
3 | // file in its "rules" directory. Since we don't care about any of the bundled
4 | // rules, just completely ignore them.
5 | return [];
6 | }
7 |
--------------------------------------------------------------------------------
/server/constants.js:
--------------------------------------------------------------------------------
1 | if (!process.env.AUTH_TOKEN) {
2 | console.error(
3 | 'AUTH_TOKEN is not set! That will result in all gists being anonymous, ' +
4 | 'which is probably not what you want.'
5 | );
6 | process.exit(1);
7 | }
8 |
9 | module.exports = {
10 | AUTH_TOKEN: process.env.AUTH_TOKEN,
11 | SETTINGS_FORMAT: 2,
12 | };
13 |
--------------------------------------------------------------------------------
/website/packages/eslint1/index.js:
--------------------------------------------------------------------------------
1 | // Explicitly require just the stuff we care about to avoid loading
2 | // RuleTester and CLIEngine, which are unnecessary and bloat out the
3 | // package size.
4 | module.exports = {
5 | eslint: require('eslint/lib/eslint'),
6 | sourceCode: require('eslint/lib/util/source-code'),
7 | rules: require('eslint/lib/rules'),
8 | };
9 |
--------------------------------------------------------------------------------
/website/packages/eslint2/index.js:
--------------------------------------------------------------------------------
1 | // Explicitly require just the stuff we care about to avoid loading
2 | // RuleTester and CLIEngine, which are unnecessary and bloat out the
3 | // package size.
4 | module.exports = {
5 | eslint: require('eslint/lib/eslint'),
6 | sourceCode: require('eslint/lib/util/source-code'),
7 | rules: require('eslint/lib/rules'),
8 | };
9 |
--------------------------------------------------------------------------------
/website/packages/eslint3/index.js:
--------------------------------------------------------------------------------
1 | // Explicitly require just the stuff we care about to avoid loading
2 | // RuleTester and CLIEngine, which are unnecessary and bloat out the
3 | // package size.
4 | module.exports = {
5 | eslint: require('eslint/lib/eslint'),
6 | sourceCode: require('eslint/lib/util/source-code'),
7 | rules: require('eslint/lib/rules'),
8 | };
9 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/babel6/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default function (babel) {
2 | const { types: t } = babel;
3 |
4 | return {
5 | name: "ast-transform", // not required
6 | visitor: {
7 | Identifier(path) {
8 | path.node.name = path.node.name.split('').reverse().join('');
9 | }
10 | }
11 | };
12 | }
13 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/babel7/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default function (babel) {
2 | const { types: t } = babel;
3 |
4 | return {
5 | name: "ast-transform", // not required
6 | visitor: {
7 | Identifier(path) {
8 | path.node.name = path.node.name.split('').reverse().join('');
9 | }
10 | }
11 | };
12 | }
13 |
--------------------------------------------------------------------------------
/website/packages/eslint4/index.js:
--------------------------------------------------------------------------------
1 | // Explicitly require just the stuff we care about to avoid loading
2 | // RuleTester and CLIEngine, which are unnecessary and bloat out the
3 | // package size.
4 | const Linter = require('eslint/lib/linter');
5 |
6 | module.exports = {
7 | eslint: new Linter(),
8 | sourceCode: require('eslint/lib/util/source-code')
9 | };
10 |
--------------------------------------------------------------------------------
/website/src/parsers/css/codeExample.txt:
--------------------------------------------------------------------------------
1 | /**
2 | * Paste or drop some CSS here and explore
3 | * the syntax tree created by chosen parser.
4 | * Enjoy!
5 | */
6 |
7 | @media screen and (min-width: 480px) {
8 | body {
9 | background-color: lightgreen;
10 | }
11 | }
12 |
13 | #main {
14 | border: 1px solid black;
15 | }
16 |
17 | ul li {
18 | padding: 5px;
19 | }
20 |
--------------------------------------------------------------------------------
/website/src/containers/LoadingIndicatorContainer.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux';
2 | import LoadingIndicator from '../components/LoadingIndicator';
3 | import {isLoadingSnippet} from '../store/selectors';
4 |
5 | function mapStateToProps(state) {
6 | return {
7 | visible: isLoadingSnippet(state),
8 | };
9 | }
10 |
11 | export default connect(mapStateToProps)(LoadingIndicator);
12 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astexplorer-server",
3 | "version": "2.0.0",
4 | "main": "index.js",
5 | "private": true,
6 | "author": "Felix Kling",
7 | "dependencies": {
8 | "body-parser": "^1.15.2",
9 | "express": "^4.14.0",
10 | "github-api": "https://github.com/fkling/github.git"
11 | },
12 | "scripts": {
13 | "start": "STATIC=../out node index.js"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/website/src/utils/debounce.js:
--------------------------------------------------------------------------------
1 | export default function debounce(f, timeout=100) {
2 | let timer;
3 | let lastArgs;
4 | let lastThis;
5 |
6 | return function(...args) {
7 | lastThis = this;
8 | lastArgs = args;
9 | if (timer) {
10 | return;
11 | }
12 | timer = setTimeout(() => {
13 | timer = null;
14 | f.apply(lastThis, lastArgs);
15 | }, timeout);
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/jscodeshift/codeExample.txt:
--------------------------------------------------------------------------------
1 | // Press ctrl+space for code completion
2 | export default function transformer(file, api) {
3 | const j = api.jscodeshift;
4 |
5 | return j(file.source)
6 | .find(j.Identifier)
7 | .forEach(path => {
8 | j(path).replaceWith(
9 | j.identifier(path.node.name.split('').reverse().join(''))
10 | );
11 | })
12 | .toSource();
13 | }
14 |
--------------------------------------------------------------------------------
/website/src/parsers/utils/compileModule.js:
--------------------------------------------------------------------------------
1 | export default function compileModule(code, globals = {}) {
2 | let exports = {};
3 | let module = { exports };
4 | let globalNames = Object.keys(globals);
5 | let keys = ['module', 'exports', ...globalNames];
6 | let values = [module, exports, ...globalNames.map(key => globals[key])];
7 | new Function(keys.join(), code).apply(exports, values);
8 | return module.exports;
9 | }
10 |
--------------------------------------------------------------------------------
/website/src/parsers/php/codeExample.txt:
--------------------------------------------------------------------------------
1 | $tip) {
15 | echo "Tip $i: " . $tip;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/scripts/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | REMOTE=${1:-"server"}
6 | BRANCH=${2:-"master"}
7 |
8 | if ! git diff --quiet && git diff --cached --quiet; then
9 | echo >&2 "You have uncommitted changes, you probably don't want to update the server."
10 | exit 1
11 | fi
12 |
13 | for i in {5..1}; do
14 | printf "\rPushing '$BRANCH' to '$REMOTE' in $i ..." && sleep 1;
15 | done
16 |
17 | echo "\nPushing..."
18 | git push -f $REMOTE $BRANCH
19 |
--------------------------------------------------------------------------------
/website/src/components/LoadingIndicator.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | export default function LoadingIndicator(props) {
5 | return props.visible ?
6 | this.container = c}/>
62 | );
63 | }
64 | }
65 |
66 | Editor.propTypes = {
67 | value: PropTypes.string,
68 | className: PropTypes.string,
69 | };
70 |
--------------------------------------------------------------------------------
/server/handlers/gist/saveAnonymousGist.js:
--------------------------------------------------------------------------------
1 | const {AUTH_TOKEN, SETTINGS_FORMAT} = require('../../constants');
2 | const GitHub = require('github-api');
3 |
4 | const gh = new GitHub({token: AUTH_TOKEN});
5 |
6 | /**
7 | * Expects an array of the form [[filename, content], [filename, content], ...]
8 | */
9 | function makeFiles(files) {
10 | return files.reduce(
11 | (obj, [filename, content]) => (obj[filename] = (content ? {content} : content), obj),
12 | {}
13 | );
14 | }
15 |
16 | function getDataFromBody(body, additionalData={}) {
17 | const files = [
18 | [
19 | 'astexplorer.json',
20 | JSON.stringify(
21 | Object.assign(
22 | {
23 | v: SETTINGS_FORMAT,
24 | parserID: body.parserID,
25 | toolID: body.toolID,
26 | settings: body.settings,
27 | versions: body.versions,
28 | },
29 | additionalData
30 | ),
31 | null,
32 | 2
33 | ),
34 | ],
35 | [body.filename, body.code],
36 | ];
37 |
38 | // null value indicates deletion
39 | if (body.transform || body.transform === null) {
40 | files.push(['transform.js', body.transform]);
41 | }
42 |
43 | return {
44 | files: makeFiles(files),
45 | description: body.description,
46 | public: Boolean(body.public),
47 | };
48 | }
49 |
50 | exports.create = (req, res, next) => {
51 | gh.getGist()
52 | .create(getDataFromBody(req.body))
53 | .then(response => res.json(response.data))
54 | .catch(next);
55 | };
56 |
57 | exports.update = (req, res, next) => {
58 | gh.getGist(req.params.snippetid)
59 | .update(getDataFromBody(req.body))
60 | .then(response => res.json(response.data))
61 | .catch(next);
62 | };
63 |
64 | exports.fork = (req, res, next) => {
65 | // We cannot really "fork" an "anonymous" snippet because a user (astexplorer)
66 | // cannot fork it's own gist.
67 | const data = getDataFromBody(req.body);
68 |
69 | gh.getGist()
70 | .create(data)
71 | .then(response => res.json(response.data))
72 | .catch(next);
73 | };
74 |
--------------------------------------------------------------------------------
/website/src/parsers/glsl/glsl-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'glsl-parser/package.json';
3 |
4 | const ID = 'glsl-parser';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage,
13 | locationProps: new Set(['loc']),
14 | _ignoredProperties: new Set([
15 | 'loc', // we ignore the loc itself because it's actually a locally enhanced (not in the actual parser data)
16 | 'parent', // it's pointless to display the parent node in the tree browser
17 | 'stage', // same
18 | ]),
19 |
20 | loadParser(callback) {
21 | require(['glsl-tokenizer/string', 'glsl-parser/direct'], (
22 | tokenize,
23 | parse
24 | ) => {
25 | callback({ tokenize, parse });
26 | });
27 | },
28 |
29 | parse({ tokenize, parse }, code) {
30 | const tokens = tokenize(code);
31 | const ast = parse(tokens);
32 | // the parser does not yet provide the "end" so this is a workaround https://github.com/stackgl/glsl-parser/issues/17
33 | function decoratePosition(node, end) {
34 | node.loc = {
35 | start: node.token.position || 0,
36 | end,
37 | };
38 | node.children.forEach((child, i) => {
39 | const nextSibling = node.children[i + 1];
40 | decoratePosition(
41 | child,
42 | nextSibling && nextSibling.token && 'position' in nextSibling.token
43 | ? nextSibling.token.position -
44 | (nextSibling.token.preceding || [])
45 | .reduce((s, n) => s + (n.data || '').length, 0)
46 | : end
47 | );
48 | });
49 | }
50 | decoratePosition(ast, code.length);
51 | return ast;
52 | },
53 |
54 | nodeToRange({ loc }) {
55 | if (loc) {
56 | return [loc.start, loc.end];
57 | }
58 | },
59 |
60 | getNodeName(node) {
61 | return node.type;
62 | },
63 |
64 | opensByDefault(node, key) {
65 | return key === 'children' && node.type === '(program)';
66 | },
67 | };
68 |
--------------------------------------------------------------------------------
/website/src/containers/ToolbarContainer.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux';
2 | import {
3 | save,
4 | selectCategory,
5 | openSettingsDialog,
6 | openShareDialog,
7 | selectTransformer,
8 | hideTransformer,
9 | setParser,
10 | reset,
11 | } from '../store/actions';
12 | import Toolbar from '../components/Toolbar';
13 | import * as selectors from '../store/selectors';
14 | import {logEvent} from '../utils/logger';
15 |
16 | function mapStateToProps(state) {
17 | const parser = selectors.getParser(state);
18 |
19 | return {
20 | forking: selectors.isForking(state),
21 | saving: selectors.isSaving(state),
22 | canSave: selectors.canSave(state),
23 | canFork: selectors.canFork(state),
24 | category: parser.category,
25 | parser,
26 | transformer: selectors.getTransformer(state),
27 | showTransformer: selectors.showTransformer(state),
28 | snippet: selectors.getRevision(state),
29 | };
30 | }
31 |
32 | function mapDispatchToProps(dispatch) {
33 | return {
34 | onParserChange: parser => {
35 | dispatch(setParser(parser));
36 | logEvent('parser', 'select', parser.id);
37 | },
38 | onCategoryChange: category => {
39 | dispatch(selectCategory(category));
40 | logEvent('category', 'select', category.id);
41 | },
42 | onParserSettingsButtonClick: () => {
43 | dispatch(openSettingsDialog());
44 | logEvent('parser', 'open_settings');
45 | },
46 | onShareButtonClick: () => {
47 | dispatch(openShareDialog());
48 | logEvent('ui', 'open_share');
49 | },
50 | onTransformChange: transformer => {
51 | dispatch(transformer ? selectTransformer(transformer) : hideTransformer());
52 | if (transformer) {
53 | logEvent('tool', 'select', transformer.id);
54 | }
55 | },
56 | onSave: () => dispatch(save(false)),
57 | onFork: () => dispatch(save(true)),
58 | onNew: () => {
59 | if (global.location.hash) {
60 | global.location.hash = '';
61 | } else {
62 | dispatch(reset());
63 | }
64 | },
65 | };
66 | }
67 |
68 | export default connect(mapStateToProps, mapDispatchToProps)(Toolbar);
69 |
70 |
--------------------------------------------------------------------------------
/website/src/parsers/html/parse5.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaultParserInterface from '../utils/defaultParserInterface';
3 | import pkg from 'parse5/package.json';
4 | import SettingsRenderer from '../utils/SettingsRenderer';
5 |
6 | const ID = 'parse5';
7 | const defaultOptions = {
8 | treeAdapter: 'default',
9 | };
10 |
11 | const parserSettingsConfiguration = {
12 | fields : [
13 | ['treeAdapter', ['default', 'htmlparser2']],
14 | ],
15 | };
16 |
17 | export default {
18 | ...defaultParserInterface,
19 |
20 | id: ID,
21 | displayName: ID,
22 | version: pkg.version,
23 | homepage: pkg.homepage,
24 | locationProps: new Set(['__location']),
25 |
26 | loadParser(callback) {
27 | require([
28 | 'parse5/lib/parser',
29 | 'parse5/lib/tree_adapters/default',
30 | 'parse5/lib/tree_adapters/htmlparser2',
31 | ], (Parser, defaultAdapter, htmlparser2Adapter) => {
32 | callback({
33 | Parser,
34 | TreeAdapters: {
35 | default: defaultAdapter,
36 | htmlparser2: htmlparser2Adapter,
37 | },
38 | });
39 | });
40 | },
41 |
42 | parse({ Parser, TreeAdapters }, code, options) {
43 | this.options = {...defaultOptions, ...options};
44 | return new Parser({
45 | treeAdapter: TreeAdapters[this.options.treeAdapter],
46 | locationInfo: true,
47 | }).parse(code);
48 | },
49 |
50 | getNodeName(node) {
51 | if (this.options.treeAdapter === 'htmlparser2') {
52 | return node.type + (node.name && node.type !== 'root' ? `(${node.name})` : '');
53 | } else {
54 | return node.nodeName;
55 | }
56 | },
57 |
58 | nodeToRange({ __location: loc }) {
59 | if (loc) {
60 | return [loc.startOffset, loc.endOffset];
61 | }
62 | },
63 |
64 | opensByDefault(node, key) {
65 | return key === 'children' || key === 'childNodes';
66 | },
67 |
68 | renderSettings(parserSettings, onChange) {
69 | return (
70 |
75 | );
76 | },
77 |
78 | _ignoredProperties: new Set(['parentNode', 'prev', 'next', 'parent', 'firstChild', 'lastChild']),
79 | };
80 |
--------------------------------------------------------------------------------
/website/src/parsers/js/espree.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
3 | import pkg from 'espree/package.json';
4 | import SettingsRenderer from '../utils/SettingsRenderer';
5 |
6 | const ID = 'espree';
7 | const defaultOptions = {
8 | range: true,
9 | loc: false,
10 | comment: false,
11 | attachComment: false,
12 | tokens: false,
13 | tolerant: false,
14 | ecmaVersion: 6,
15 | sourceType: 'module',
16 |
17 | ecmaFeatures: {
18 | jsx: true,
19 | globalReturn: true,
20 | experimentalObjectRestSpread: true,
21 | },
22 | };
23 | const parserSettingsConfiguration = {
24 | fields: [
25 | ['ecmaVersion', [3, 5, 6, 7], value => Number(value)],
26 | ['sourceType', ['script', 'module']],
27 | 'range',
28 | 'loc',
29 | 'comment',
30 | 'attachComment',
31 | 'tokens',
32 | 'tolerant',
33 | {
34 | key: 'ecmaFeatures',
35 | title: 'ecmaFeatures',
36 | fields: Object.keys(defaultOptions.ecmaFeatures),
37 | settings:
38 | settings => settings.ecmaFeatures || {...defaultOptions.ecmaFeatures},
39 | },
40 | ],
41 | };
42 |
43 | export default {
44 | ...defaultParserInterface,
45 |
46 | id: ID,
47 | displayName: ID,
48 | version: pkg.version,
49 | homepage: pkg.homepage,
50 | locationProps: new Set(['range', 'loc', 'start', 'end']),
51 |
52 | loadParser(callback) {
53 | require(['espree'], callback);
54 | },
55 |
56 | parse(espree, code, options) {
57 | return espree.parse(code, {...defaultOptions, ...options});
58 | },
59 |
60 | nodeToRange(node) {
61 | if (typeof node.start === 'number') {
62 | return [node.start, node.end];
63 | }
64 | },
65 |
66 | renderSettings(parserSettings, onChange) {
67 | return (
68 |
82 | );
83 | },
84 | };
85 |
--------------------------------------------------------------------------------
/website/src/components/dialogs/SettingsDialog.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | export default class SettingsDialog extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this._outerClick = this._outerClick.bind(this);
8 | this._onChange = this._onChange.bind(this);
9 | this._reset = this._reset.bind(this);
10 | this._saveAndClose = this._saveAndClose.bind(this);
11 | this.state = {
12 | parserSettings: this.props.parserSettings,
13 | };
14 | }
15 |
16 | componentWillReceiveProps(nextProps) {
17 | this.setState({parserSettings: nextProps.parserSettings});
18 | }
19 |
20 | _outerClick(event) {
21 | if (event.target === document.getElementById('SettingsDialog')) {
22 | this._saveAndClose();
23 | }
24 | }
25 |
26 | _onChange(newSettings) {
27 | this.setState({parserSettings: newSettings});
28 | }
29 |
30 | _saveAndClose() {
31 | this.props.onSave(this.props.parser, this.state.parserSettings);
32 | this.props.onWantToClose();
33 | }
34 |
35 | _reset() {
36 | this.setState({parserSettings: {}});
37 | }
38 |
39 | render() {
40 | if (this.props.visible && this.props.parser.renderSettings) {
41 | return (
42 |
43 |
44 |
45 |
{this.props.parser.displayName} Settings
46 |
47 |
48 | {this.props.parser.renderSettings(
49 | this.state.parserSettings,
50 | this._onChange
51 | )}
52 |
53 |
54 |
57 |
58 |
59 |
60 |
61 | );
62 | }
63 | return null;
64 | }
65 | }
66 |
67 | SettingsDialog.propTypes = {
68 | onSave: PropTypes.func,
69 | onWantToClose: PropTypes.func,
70 | visible: PropTypes.bool,
71 | parser: PropTypes.object.isRequired,
72 | parserSettings: PropTypes.object,
73 | };
74 |
--------------------------------------------------------------------------------
/website/src/components/Toolbar.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import CategoryButton from './buttons/CategoryButton';
4 | import ParserButton from './buttons/ParserButton';
5 | import SnippetButton from './buttons/SnippetButton';
6 | import TransformButton from './buttons/TransformButton';
7 |
8 | export default function Toolbar(props) {
9 | let {parser, transformer, showTransformer} = props;
10 | let parserInfo = parser.id;
11 | let transformerInfo = '';
12 | if (parser) {
13 | if (parser.version) {
14 | parserInfo += '-' + parser.version;
15 | }
16 | if (parser.homepage) {
17 | parserInfo =
18 |
{parserInfo};
19 | }
20 | }
21 | if (showTransformer) {
22 | transformerInfo = transformer.displayName;
23 | if (transformer.version) {
24 | transformerInfo += '-' + transformer.version;
25 | }
26 | if (transformer.homepage) {
27 | transformerInfo =
28 |
{transformerInfo};
29 | }
30 | transformerInfo =
Transformer: {transformerInfo};
31 | }
32 |
33 | return (
34 |
52 | );
53 | }
54 |
55 | Toolbar.propTypes = {
56 | saving: PropTypes.bool,
57 | forking: PropTypes.bool,
58 | onSave: PropTypes.func,
59 | onFork: PropTypes.func,
60 | onParserChange: PropTypes.func,
61 | onParserSettingsButtonClick: PropTypes.func,
62 | onShareButtonClick: PropTypes.func,
63 | onTransformChange: PropTypes.func,
64 | parser: PropTypes.object,
65 | transformer: PropTypes.object,
66 | showTransformer: PropTypes.bool,
67 | canSave: PropTypes.bool,
68 | canFork: PropTypes.bool,
69 | };
70 |
--------------------------------------------------------------------------------
/website/src/components/buttons/TransformButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import cx from 'classnames';
4 | import {getTransformerByID} from '../../parsers';
5 |
6 | export default class TransformButton extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this._onClick = this._onClick.bind(this);
10 | this._onToggle = this._onToggle.bind(this);
11 | }
12 |
13 | _onClick({target}) {
14 | let transformID;
15 | if (target.nodeName.toLowerCase() === 'li') {
16 | transformID = target.children[0].value;
17 | } else {
18 | transformID = target.value;
19 | }
20 | this.props.onTransformChange(getTransformerByID(transformID));
21 | }
22 |
23 | _onToggle() {
24 | if (this.props.transformer) {
25 | this.props.onTransformChange(null);
26 | }
27 | }
28 |
29 | render() {
30 | return (
31 |
36 |
51 | {!!this.props.category.transformers.length &&
52 | {this.props.category.transformers.map(transformer => (
53 | -
60 |
63 |
64 | ))}
65 |
}
66 |
67 | );
68 | }
69 | }
70 |
71 | TransformButton.propTypes = {
72 | category: PropTypes.object,
73 | transformer: PropTypes.object,
74 | showTransformer: PropTypes.bool,
75 | onTransformChange: PropTypes.func,
76 | };
77 |
--------------------------------------------------------------------------------
/website/src/parsers/index.js:
--------------------------------------------------------------------------------
1 | const localRequire = require.context('./', true, /^\.\/(?!utils)[^/]+\/(transformers\/([^/]+)\/)?(codeExample\.txt|[^/]+?\.js)$/);
2 |
3 | const files =
4 | localRequire.keys()
5 | .map(name => name.split('/').slice(1));
6 |
7 | const categoryByID = {};
8 | const parserByID = {};
9 | const transformerByID = {};
10 |
11 | const restrictedParserNames = new Set([
12 | 'index.js',
13 | 'codeExample.txt',
14 | 'transformers',
15 | 'utils',
16 | ]);
17 |
18 | export const categories =
19 | files
20 | .filter(name => name[1] === 'index.js')
21 | .map(([catName]) => {
22 | let category = localRequire(`./${catName}/index.js`);
23 |
24 | categoryByID[category.id] = category;
25 |
26 | category.codeExample = localRequire(`./${catName}/codeExample.txt`);
27 |
28 | let catFiles =
29 | files
30 | .filter(([curCatName]) => curCatName === catName)
31 | .map(name => name.slice(1));
32 |
33 | category.parsers =
34 | catFiles
35 | .filter(([parserName]) => !restrictedParserNames.has(parserName))
36 | .map(([parserName]) => {
37 | let parser = localRequire(`./${catName}/${parserName}`);
38 | parser = parser.__esModule ? parser.default : parser;
39 | parserByID[parser.id] = parser;
40 | parser.category = category;
41 | return parser;
42 | });
43 |
44 | category.transformers =
45 | catFiles
46 | .filter(([dirName, , fileName]) => dirName === 'transformers' && fileName === 'index.js')
47 | .map(([, transformerName]) => {
48 | let transformerDir = `./${catName}/transformers/${transformerName}`;
49 | let transformer = localRequire(`${transformerDir}/index.js`);
50 | transformer = transformer.__esModule ? transformer.default : transformer;
51 | transformerByID[transformer.id] = transformer;
52 | transformer.defaultTransform = localRequire(`${transformerDir}/codeExample.txt`);
53 | return transformer;
54 | });
55 |
56 | return category;
57 | });
58 |
59 | export function getDefaultCategory() {
60 | return categoryByID.javascript;
61 | }
62 |
63 | export function getDefaultParser(category = getDefaultCategory()) {
64 | return category.parsers[0];
65 | }
66 |
67 | export function getCategoryByID(id) {
68 | return categoryByID[id];
69 | }
70 |
71 | export function getParserByID(id) {
72 | return parserByID[id];
73 | }
74 |
75 | export function getTransformerByID(id) {
76 | return transformerByID[id];
77 | }
78 |
--------------------------------------------------------------------------------
/website/src/parsers/scala/scalameta.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import pkg from 'scalameta-parsers/package.json';
3 | import defaultParserInterface from '../utils/defaultParserInterface';
4 | import SettingsRenderer from '../utils/SettingsRenderer';
5 |
6 | const ID = 'scalameta';
7 |
8 | const dialects = {
9 | 'Scala 2.10': 'Scala210',
10 | 'Scala 2.11': 'Scala211',
11 | 'Scala 2.12': 'Scala212',
12 | 'Sbt 0.13.6': 'Sbt0136',
13 | 'Sbt 0.13.7': 'Sbt0137',
14 | 'Dotty': 'Dotty',
15 | 'Typelevel 2.11': 'Typelevel211',
16 | 'Typelevel 2.12': 'Typelevel212',
17 | 'Paradise 2.11': 'Paradise211',
18 | 'Paradise 2.12': 'Paradise212',
19 | 'Paradise Typelevel 2.11': 'ParadiseTypelevel211',
20 | 'Paradise Typelevel 2.12': 'ParadiseTypelevel212',
21 | }
22 |
23 | const defaultOptions = {
24 | dialect: 'Scala 2.11',
25 | }
26 |
27 | const settingsConfiguration = {
28 | fields: [
29 | ['dialect', Object.keys(dialects)],
30 | ],
31 | required: new Set('dialect'),
32 | }
33 |
34 | export default {
35 | ...defaultParserInterface,
36 |
37 | id: ID,
38 | displayName: ID,
39 | version: pkg.version,
40 | homepage: pkg.homepage || 'https://github.com/scalameta/scalameta',
41 | locationProps: new Set(['pos']),
42 |
43 | loadParser(callback) {
44 | require(['scalameta-parsers'], callback);
45 | },
46 |
47 | parse(scalametaParser, code, options) {
48 | const parsed = scalametaParser.parseSource(code, {
49 | ...defaultOptions,
50 | ...options,
51 | dialect: dialects[defaultOptions.dialect || options.dialect],
52 | });
53 | const { error, lineNumber, columnNumber } = parsed;
54 | if (error) {
55 | const e = new SyntaxError(parsed.error);
56 | e.lineNumber = lineNumber + 1;
57 | e.columnNumber = columnNumber + 1;
58 | throw e;
59 | }
60 | return parsed;
61 | },
62 |
63 | nodeToRange(node) {
64 | if (node.pos) {
65 | return [node.pos.start, node.pos.end];
66 | }
67 | },
68 |
69 | getNodeName(node) {
70 | return node.type;
71 | },
72 |
73 | opensByDefault(node, key) {
74 | return node.type === 'Program'
75 | || key === 'body'
76 | || key === 'self'
77 | || key === 'stats';
78 | },
79 |
80 | renderSettings(parserSettings, onChange) {
81 | return (
82 |
87 | )
88 | },
89 |
90 | };
91 |
92 |
--------------------------------------------------------------------------------
/website/src/components/visualization/Tree.js:
--------------------------------------------------------------------------------
1 | import Element from './tree/Element';
2 | import PropTypes from 'prop-types';
3 | import React from 'react';
4 | import PubSub from 'pubsub-js';
5 | import {logEvent} from '../../utils/logger';
6 |
7 | import './css/tree.css'
8 |
9 | export default class Tree extends React.Component {
10 | constructor(props) {
11 | super(props);
12 |
13 | this.state = {autofocus: true, hideFunctions: true};
14 | }
15 |
16 | _setOption(name, event) {
17 | this.setState({[name]: event.target.checked});
18 | logEvent(
19 | 'tree_view_settings',
20 | event.target.checked ? 'enabled' : 'disabled',
21 | name
22 | );
23 | }
24 |
25 | render() {
26 | return (
27 |
72 | );
73 | }
74 | }
75 |
76 | Tree.propTypes = {
77 | focusPath: PropTypes.array,
78 | ast: PropTypes.oneOfType([
79 | PropTypes.array,
80 | PropTypes.object,
81 | ]),
82 | parser: PropTypes.object,
83 | };
84 |
--------------------------------------------------------------------------------
/website/src/components/visualization/tree/RecursiveTreeElement.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | function shouldAutoFocus({value, settings, focusPath}) {
5 | return !!settings.autofocus && focusPath.indexOf(value) > -1;
6 | }
7 |
8 |
9 | /**
10 | * This is a higher order component the prevents infinite recursion when opening
11 | * the element tree.
12 | */
13 | export default function RecursiveTreeElement(Element) {
14 | const openValues = new WeakMap();
15 |
16 | function addValue(value) {
17 | if (openValues.has(value)) {
18 | openValues.set(value, openValues.get(value) + 1);
19 | } else {
20 | openValues.set(value, 1);
21 | }
22 | }
23 |
24 | function removeValue(value) {
25 | let n = openValues.get(value) - 1;
26 | if (n === 0) {
27 | openValues.delete(value);
28 | } else {
29 | openValues.set(value, n);
30 | }
31 | }
32 |
33 | class RecursiveElement extends React.Component {
34 | constructor(props) {
35 | super(props);
36 | let {deepOpen} = props;
37 | let open = shouldAutoFocus(props);
38 | if (props.value && typeof props.value === 'object') {
39 | if (openValues.has(props.value)) {
40 | deepOpen = false;
41 | open = false;
42 | }
43 | addValue(props.value);
44 | }
45 | this.state = {deepOpen, open};
46 | }
47 |
48 | componentWillUnmount() {
49 | const {value} = this.props;
50 | if (value && typeof value === 'object') {
51 | removeValue(value);
52 | }
53 | }
54 |
55 | componentWillReceiveProps(props) {
56 | let {deepOpen} = props;
57 | let open = shouldAutoFocus(props);
58 | if (!this.props.value !== props.value) {
59 | if (this.props.value && typeof this.props.value === 'object') {
60 | removeValue(this.props.value);
61 | }
62 | if (props.value && typeof props.value === 'object') {
63 | if (openValues.has(props.value)) {
64 | deepOpen = false;
65 | open = false;
66 | }
67 | addValue(props.value);
68 | }
69 | }
70 | this.setState({deepOpen, open});
71 | }
72 |
73 | render() {
74 | const {props} = this;
75 | return (
76 |
81 | );
82 | }
83 | }
84 |
85 | RecursiveElement.propTypes = {
86 | deepOpen: PropTypes.bool,
87 | value: PropTypes.any,
88 | };
89 |
90 | return RecursiveElement;
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/website/src/parsers/js/acorn.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
3 | import pkg from 'acorn/package.json';
4 | import SettingsRenderer from '../utils/SettingsRenderer';
5 |
6 | const ID = 'acorn';
7 | const defaultOptions = {
8 | ecmaVersion: 7,
9 | sourceType: 'module',
10 | allowReserved: false,
11 | allowReturnOutsideFunction: false,
12 | allowImportExportEverywhere: false,
13 | allowHashBang: false,
14 | locations: false,
15 | loose: false,
16 | ranges: false,
17 | preserveParens: false,
18 | 'plugins.jsx': true,
19 | };
20 |
21 | const settingsConfiguration = {
22 | fields: [
23 | ['ecmaVersion', [3, 5, 6, 7, 8], x => Number(x)],
24 | ['sourceType', ['script', 'module']],
25 | 'allowReserved',
26 | 'allowReturnOutsideFunction',
27 | 'allowImportExportEverywhere',
28 | 'allowHashBang',
29 | 'locations',
30 | 'loose',
31 | 'ranges',
32 | 'preserveParens',
33 | 'plugins.jsx',
34 | ],
35 | };
36 |
37 | export default {
38 | ...defaultParserInterface,
39 |
40 | id: ID,
41 | displayName: ID,
42 | version: `${pkg.version}`,
43 | homepage: pkg.homepage,
44 | locationProps: new Set(['range', 'loc', 'start', 'end']),
45 |
46 | loadParser(callback) {
47 | require(['acorn', 'acorn/dist/acorn_loose', 'acorn-jsx/inject'], (acorn, acornLoose, jsxInject) => {
48 | acorn = jsxInject(acorn);
49 | callback({
50 | acorn,
51 | acornLoose,
52 | });
53 | });
54 | },
55 |
56 | parse(parsers, code, options={}) {
57 | options = Object.assign({}, defaultOptions, options);
58 | const parser = options.loose ?
59 | parsers.acornLoose.parse_dammit :
60 | parsers.acorn.parse;
61 |
62 | // put deep option into correspondent place
63 | return parser(code, {
64 | ...options,
65 | plugins: options['plugins.jsx'] && !options.loose ? { jsx: true } : {},
66 | });
67 | },
68 |
69 | nodeToRange(node) {
70 | if (typeof node.start === 'number') {
71 | return [node.start, node.end];
72 | }
73 | },
74 |
75 | renderSettings(parserSettings, onChange) {
76 | return (
77 |
91 | );
92 | },
93 | };
94 |
--------------------------------------------------------------------------------
/website/src/parsers/html/htmlparser2.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaultParserInterface from '../utils/defaultParserInterface';
3 | import pkg from 'htmlparser2/package.json';
4 | import SettingsRenderer from '../utils/SettingsRenderer';
5 |
6 | const ID = 'htmlparser2';
7 | const defaultOptions = {
8 | xmlMode: false,
9 | lowerCaseAttributeNames: true,
10 | lowerCaseTags: true,
11 | };
12 |
13 | const parserSettingsConfiguration = {
14 | fields: Object.keys(defaultOptions),
15 | };
16 |
17 | export default {
18 | ...defaultParserInterface,
19 |
20 | id: ID,
21 | displayName: ID,
22 | version: pkg.version,
23 | homepage: pkg.homepage || 'https://github.com/fb55/htmlparser2',
24 | locationProps: new Set(['startIndex']),
25 |
26 | loadParser(callback) {
27 | require(['htmlparser2/lib/Parser', 'domhandler'], (Parser, DomHandler) => {
28 | class Handler extends DomHandler {
29 | constructor() {
30 | super({ withStartIndices: true });
31 | }
32 |
33 | _setEnd(elem) {
34 | elem.endIndex = this._parser.endIndex + 1;
35 | }
36 |
37 | onprocessinginstruction(name, data) {
38 | this._parser.endIndex = this._parser._tokenizer._index;
39 | super.onprocessinginstruction(name, data);
40 | }
41 |
42 | _addDomElement(elem) {
43 | super._addDomElement(elem);
44 | this._setEnd(elem);
45 | }
46 | }
47 |
48 | Handler.prototype.onclosetag =
49 | Handler.prototype.oncommentend =
50 | Handler.prototype.oncdataend =
51 | function onElemEnd() {
52 | this._setEnd(this._tagStack.pop());
53 | };
54 |
55 | callback({ Parser, Handler });
56 | });
57 | },
58 |
59 | parse({ Parser, Handler }, code, options) {
60 | let handler = new Handler();
61 | new Parser(handler, {...defaultOptions, ...options}).end(code);
62 | return handler.dom;
63 | },
64 |
65 | nodeToRange(node) {
66 | if (node.type) {
67 | return [node.startIndex, node.endIndex];
68 | }
69 | },
70 |
71 | opensByDefault(node, key) {
72 | return key === 'children';
73 | },
74 |
75 | getNodeName(node) {
76 | let nodeName = node.type;
77 | if (nodeName && node.name) {
78 | nodeName += `(${node.name})`;
79 | }
80 | return nodeName;
81 | },
82 |
83 | renderSettings(parserSettings, onChange) {
84 | return (
85 |
90 | );
91 | },
92 |
93 | _ignoredProperties: new Set(['prev', 'next', 'parent', 'endIndex']),
94 | };
95 |
--------------------------------------------------------------------------------
/website/src/parsers/js/babylon6.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
3 | import pkg from 'babylon6/babylon-package';
4 | import SettingsRenderer from '../utils/SettingsRenderer';
5 |
6 | const availablePlugins = [
7 | 'asyncGenerators',
8 | 'classConstructorCall',
9 | 'classProperties',
10 | 'decorators',
11 | 'doExpressions',
12 | 'estree',
13 | 'exportExtensions',
14 | 'flow',
15 | 'functionSent',
16 | 'functionBind',
17 | 'jsx',
18 | 'objectRestSpread',
19 | 'dynamicImport',
20 | ];
21 |
22 | const ID = 'babylon6';
23 | export const defaultOptions = {
24 | sourceType: 'module',
25 | allowImportExportEverywhere: false,
26 | allowReturnOutsideFunction: false,
27 | plugins: [
28 | 'asyncGenerators',
29 | 'classConstructorCall',
30 | 'classProperties',
31 | 'decorators',
32 | 'doExpressions',
33 | 'exportExtensions',
34 | 'flow',
35 | 'functionSent',
36 | 'functionBind',
37 | 'jsx',
38 | 'objectRestSpread',
39 | 'dynamicImport',
40 | ],
41 | };
42 |
43 | export const parserSettingsConfiguration = {
44 | fields: [
45 | ['sourceType', ['module', 'script']],
46 | 'allowReturnOutsideFunction',
47 | 'allowImportExportEverywhere',
48 | {
49 | key: 'plugins',
50 | title: 'Plugins',
51 | fields: availablePlugins,
52 | settings: settings => settings.plugins || defaultOptions.plugins,
53 | values: plugins => availablePlugins.reduce(
54 | (obj, name) => ((obj[name] = plugins.indexOf(name) > -1), obj),
55 | {}
56 | ),
57 | },
58 | ],
59 | };
60 |
61 | export default {
62 | ...defaultParserInterface,
63 |
64 | id: ID,
65 | displayName: ID,
66 | version: pkg.version,
67 | homepage: pkg.homepage,
68 | locationProps: new Set(['loc', 'start', 'end']),
69 |
70 | loadParser(callback) {
71 | require(['babylon6'], callback);
72 | },
73 |
74 | parse(babylon, code, options) {
75 | return babylon.parse(code, {...defaultOptions, ...options});
76 | },
77 |
78 | getNodeName(node) {
79 | switch (typeof node.type) {
80 | case 'string':
81 | return node.type;
82 | case 'object':
83 | return `Token (${node.type.label})`;
84 | }
85 | },
86 |
87 | nodeToRange(node) {
88 | if (typeof node.start !== 'undefined') {
89 | return [node.start, node.end];
90 | }
91 | },
92 |
93 | renderSettings(parserSettings, onChange) {
94 | return (
95 |
100 | );
101 | },
102 | };
103 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/jscodeshift/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'jscodeshift/package.json';
3 |
4 | const ID = 'jscodeshift';
5 |
6 | const sessionMethods = new Set();
7 |
8 | export default {
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/facebook/jscodeshift',
13 |
14 | defaultParserID: 'recast',
15 |
16 | loadTransformer(callback) {
17 | require(['jscodeshift'], jscodeshift => {
18 | const { registerMethods } = jscodeshift;
19 |
20 | let origMethods;
21 |
22 | jscodeshift.registerMethods({
23 | hasOwnProperty(name) {
24 | // compare only against current-session & very original methods
25 | if (!origMethods) {
26 | origMethods = new Set(Object.getOwnPropertyNames(this));
27 | }
28 | return origMethods.has(name) || sessionMethods.has(name);
29 | },
30 | });
31 |
32 | // patch in order to collect user-defined method names
33 | jscodeshift.registerMethods = function (methods) {
34 | registerMethods.apply(this, arguments);
35 | for (let name in methods) {
36 | sessionMethods.add(name);
37 | }
38 | };
39 |
40 | callback({jscodeshift});
41 | }
42 | );
43 | },
44 |
45 | transform(
46 | {jscodeshift},
47 | transformCode,
48 | code
49 | ) {
50 | sessionMethods.clear();
51 | const transformModule = compileModule( // eslint-disable-line no-shadow
52 | transformCode
53 | );
54 | const transform = transformModule.__esModule ?
55 | transformModule.default :
56 | transformModule;
57 |
58 | const counter = Object.create(null);
59 | let statsWasCalled = false;
60 |
61 | const result = transform(
62 | {
63 | path: 'Live.js',
64 | source: code,
65 | },
66 | {
67 | jscodeshift: transformModule.parser ?
68 | jscodeshift.withParser(transformModule.parser) :
69 | jscodeshift,
70 | stats: (value, quantity=1) => {
71 | statsWasCalled = true;
72 | counter[value] = (counter[value] ? counter[value] : 0) + quantity;
73 | },
74 | },
75 | {}
76 | );
77 | if (statsWasCalled) {
78 | console.log(JSON.stringify(counter, null, 4)); // eslint-disable-line no-console
79 | }
80 | if (result == null) {
81 | // If null is returned, the jscodeshift runner won't touch the original
82 | // code, so we just return that.
83 | return code;
84 | } else if (typeof result !== 'string') {
85 | throw new Error(
86 | 'Transformers must either return undefined, null or a string, not ' +
87 | `"${typeof result}".`
88 | );
89 | }
90 | return result;
91 | },
92 | };
93 |
--------------------------------------------------------------------------------
/website/src/parsers/js/babylon7.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
3 | import pkg from 'babylon7/babylon-package';
4 | import SettingsRenderer from '../utils/SettingsRenderer';
5 |
6 | const availablePlugins = [
7 | 'asyncGenerators',
8 | 'classProperties',
9 | 'classPrivateProperties',
10 | 'decorators',
11 | 'doExpressions',
12 | 'estree',
13 | 'exportExtensions',
14 | 'flow',
15 | 'functionSent',
16 | 'functionBind',
17 | 'jsx',
18 | 'objectRestSpread',
19 | 'dynamicImport',
20 | 'numericSeparator',
21 | 'importMeta',
22 | ];
23 |
24 | const ID = 'babylon7';
25 | export const defaultOptions = {
26 | sourceType: 'module',
27 | allowImportExportEverywhere: false,
28 | allowReturnOutsideFunction: false,
29 | ranges: false,
30 | plugins: [
31 | 'asyncGenerators',
32 | 'classProperties',
33 | 'decorators',
34 | 'doExpressions',
35 | 'exportExtensions',
36 | 'flow',
37 | 'functionSent',
38 | 'functionBind',
39 | 'jsx',
40 | 'objectRestSpread',
41 | 'dynamicImport',
42 | ],
43 | };
44 |
45 | export const parserSettingsConfiguration = {
46 | fields: [
47 | ['sourceType', ['module', 'script']],
48 | 'allowReturnOutsideFunction',
49 | 'allowImportExportEverywhere',
50 | 'ranges',
51 | {
52 | key: 'plugins',
53 | title: 'Plugins',
54 | fields: availablePlugins,
55 | settings: settings => settings.plugins || defaultOptions.plugins,
56 | values: plugins => availablePlugins.reduce(
57 | (obj, name) => ((obj[name] = plugins.indexOf(name) > -1), obj),
58 | {}
59 | ),
60 | },
61 | ],
62 | };
63 |
64 | export default {
65 | ...defaultParserInterface,
66 |
67 | id: ID,
68 | displayName: ID,
69 | version: pkg.version,
70 | homepage: pkg.homepage,
71 | locationProps: new Set(['range', 'loc', 'start', 'end']),
72 |
73 | loadParser(callback) {
74 | require(['babylon7'], callback);
75 | },
76 |
77 | parse(babylon, code, options) {
78 | return babylon.parse(code, {...defaultOptions, ...options});
79 | },
80 |
81 | getNodeName(node) {
82 | switch (typeof node.type) {
83 | case 'string':
84 | return node.type;
85 | case 'object':
86 | return `Token (${node.type.label})`;
87 | }
88 | },
89 |
90 | nodeToRange(node) {
91 | if (typeof node.start !== 'undefined') {
92 | return [node.start, node.end];
93 | }
94 | },
95 |
96 | renderSettings(parserSettings, onChange) {
97 | return (
98 |
103 | );
104 | },
105 | };
106 |
--------------------------------------------------------------------------------
/website/fontcustom/input-svg/GraphQL_Logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/website/src/components/JSCodeshiftEditor.js:
--------------------------------------------------------------------------------
1 | import CodeMirror from 'codemirror';
2 | import PropTypes from 'prop-types';
3 | import Editor from './Editor';
4 |
5 | import 'codemirror/addon/hint/show-hint.css';
6 | import 'codemirror/addon/tern/tern.css';
7 |
8 | let server;
9 |
10 | export default class JSCodeshiftEditor extends Editor {
11 | constructor(props) {
12 | super(props);
13 | loadTern();
14 | }
15 |
16 | componentDidMount() {
17 | super.componentDidMount();
18 |
19 | this.codeMirror.setOption('extraKeys', {
20 | 'Ctrl-Space': cm => server && server.complete(cm),
21 | 'Ctrl-I': cm => server && server.showType(cm),
22 | 'Ctrl-O': cm => server && server.showDocs(cm),
23 | });
24 |
25 | this._bindCMHandler('cursorActivity', cm => {
26 | server && server.updateArgHints(cm);
27 | });
28 | }
29 | }
30 |
31 | function loadTern() {
32 | require(
33 | [
34 | 'codemirror/addon/hint/show-hint',
35 | 'codemirror/addon/tern/tern',
36 | 'acorn',
37 | ],
38 | (_1, _2, acorn) => {
39 | global.acorn = acorn;
40 | require(
41 | [
42 | 'tern',
43 | 'tern/plugin/doc_comment',
44 | 'tern/lib/infer',
45 | '../defs/jscodeshift.json',
46 | 'tern/defs/ecmascript.json',
47 | ],
48 | (tern, _, infer, jscs_def, ecmascript) => {
49 | global.tern = tern;
50 | tern.registerPlugin('transformer', server => {
51 | server.on('afterLoad', file => {
52 | const fnVal = file.scope.props.transformer;
53 | if (fnVal) {
54 | const fnType = fnVal.getFunctionType();
55 | const cx = infer.cx();
56 | fnType.propagate(new infer.IsCallee(
57 | infer.cx().topScope,
58 | [
59 | cx.definitions.jscodeshift.file,
60 | cx.definitions.jscodeshift.apiObject,
61 | ],
62 | null,
63 | infer.ANull
64 | ));
65 | }
66 | });
67 | });
68 |
69 | server = new CodeMirror.TernServer({
70 | defs: [jscs_def, ecmascript],
71 | plugins: {
72 | transformer: {strong: true},
73 | },
74 | });
75 | }
76 | );
77 | }
78 | );
79 | }
80 |
81 | JSCodeshiftEditor.propTypes = {
82 | value: PropTypes.string,
83 | highlight: PropTypes.bool,
84 | lineNumbers: PropTypes.bool,
85 | readOnly: PropTypes.bool,
86 | onContentChange: PropTypes.func,
87 | onActivity: PropTypes.func,
88 | posFromIndex: PropTypes.func,
89 | error: PropTypes.object,
90 | mode: PropTypes.string,
91 | };
92 |
93 | JSCodeshiftEditor.defaultProps = Object.assign(
94 | {},
95 | Editor.defaultProps,
96 | {
97 | highlight: false,
98 | }
99 | );
100 |
--------------------------------------------------------------------------------
/website/src/parsers/webidl/codeExample.txt:
--------------------------------------------------------------------------------
1 | [
2 | Constructor(ArrayBuffer buffer,
3 | optional unsigned long byteOffset,
4 | optional unsigned long byteLength)
5 | ]
6 | interface DataView {
7 | // Gets the value of the given type at the specified byte offset
8 | // from the start of the view. There is no alignment constraint;
9 | // multi-byte values may be fetched from any offset.
10 | //
11 | // For multi-byte values, the optional littleEndian argument
12 | // indicates whether a big-endian or little-endian value should be
13 | // read. If false or undefined, a big-endian value is read.
14 | //
15 | // These methods raise an exception if they would read
16 | // beyond the end of the view.
17 | byte getInt8(unsigned long byteOffset);
18 | octet getUint8(unsigned long byteOffset);
19 | short getInt16(unsigned long byteOffset,
20 | optional boolean littleEndian);
21 | unsigned short getUint16(unsigned long byteOffset,
22 | optional boolean littleEndian);
23 | long getInt32(unsigned long byteOffset,
24 | optional boolean littleEndian);
25 | unsigned long getUint32(unsigned long byteOffset,
26 | optional boolean littleEndian);
27 | float getFloat32(unsigned long byteOffset,
28 | optional boolean littleEndian);
29 | double getFloat64(unsigned long byteOffset,
30 | optional boolean littleEndian);
31 |
32 | // Stores a value of the given type at the specified byte offset
33 | // from the start of the view. There is no alignment constraint;
34 | // multi-byte values may be stored at any offset.
35 | //
36 | // For multi-byte values, the optional littleEndian argument
37 | // indicates whether the value should be stored in big-endian or
38 | // little-endian byte order. If false or undefined, the value is
39 | // stored in big-endian byte order.
40 | //
41 | // These methods raise an exception if they would write
42 | // beyond the end of the view.
43 | void setInt8(unsigned long byteOffset,
44 | byte value);
45 | void setUint8(unsigned long byteOffset,
46 | octet value);
47 | void setInt16(unsigned long byteOffset,
48 | short value,
49 | optional boolean littleEndian);
50 | void setUint16(unsigned long byteOffset,
51 | unsigned short value,
52 | optional boolean littleEndian);
53 | void setInt32(unsigned long byteOffset,
54 | long value,
55 | optional boolean littleEndian);
56 | void setUint32(unsigned long byteOffset,
57 | unsigned long value,
58 | optional boolean littleEndian);
59 | void setFloat32(unsigned long byteOffset,
60 | float value,
61 | optional boolean littleEndian);
62 | void setFloat64(unsigned long byteOffset,
63 | double value,
64 | optional boolean littleEndian);
65 | };
66 | DataView implements ArrayBufferView;
67 |
--------------------------------------------------------------------------------
/website/src/parsers/js/babylon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
3 | import pkg from 'babylon5/babylon-package';
4 | import SettingsRenderer from '../utils/SettingsRenderer';
5 |
6 | const ID = 'babylon';
7 | const defaultOptions = {
8 | sourceType: 'module',
9 | allowReserved: false,
10 | allowReturnOutsideFunction: false,
11 | strictMode: false,
12 |
13 | features: {
14 | 'es7.asyncFunctions': true,
15 | 'es7.classProperties': true,
16 | 'es7.comprehensions': true,
17 | 'es7.decorators': true,
18 | 'es7.exportExtensions': true,
19 | 'es7.functionBind': true,
20 | 'es7.objectRestSpread': true,
21 | 'es7.trailingFunctionCommas': true,
22 | },
23 |
24 | plugins: { jsx: true, flow: true },
25 | };
26 |
27 | const parserSettingsConfiguration = {
28 | fields: [
29 | ['sourceType', ['module', 'script']],
30 | 'allowReserved',
31 | 'allowReturnOutsideFunction',
32 | 'strictMode',
33 | {
34 | key: 'features',
35 | title: 'Features',
36 | fields: Object.keys(defaultOptions.features),
37 | settings: settings => settings.features || {...defaultOptions.features},
38 | },
39 | {
40 | key: 'plugins',
41 | title: 'Plugins',
42 | fields: Object.keys(defaultOptions.plugins),
43 | settings: settings => settings.plugins || {...defaultOptions.plugins},
44 | values: plugins => Object.keys(defaultOptions.plugins).reduce(
45 | (obj, name) => ((obj[name] = name in plugins), obj),
46 | {}
47 | ),
48 | update: (plugins, name, value) => {
49 | if (value) {
50 | return {...plugins, [name]: true};
51 | }
52 | plugins = {...plugins};
53 | delete plugins[name];
54 | return plugins;
55 | },
56 | },
57 | ],
58 | };
59 |
60 | export default {
61 | ...defaultParserInterface,
62 |
63 | id: ID,
64 | displayName: ID,
65 | version: pkg.version,
66 | homepage: pkg.homepage,
67 | locationProps: new Set(['loc', 'start', 'end']),
68 |
69 | loadParser(callback) {
70 | require(['babylon5'], callback);
71 | },
72 |
73 | parse(babylon, code, parserSettings) {
74 | return babylon.parse(
75 | code,
76 | {...defaultOptions, ...parserSettings}
77 | );
78 | },
79 |
80 | getNodeName(node) {
81 | switch (typeof node.type) {
82 | case 'string':
83 | return node.type;
84 | case 'object':
85 | return `Token (${node.type.label})`;
86 | }
87 | },
88 |
89 | nodeToRange(node) {
90 | if (typeof node.start !== 'undefined') {
91 | return [node.start, node.end];
92 | }
93 | },
94 |
95 | _ignoredProperties: new Set([
96 | '__clone',
97 | ]),
98 |
99 | renderSettings(parserSettings, onChange) {
100 | return (
101 |
102 |
107 |
108 | );
109 | },
110 | };
111 |
--------------------------------------------------------------------------------
/website/fontcustom/config.yml:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # Font Custom Configuration
3 | # This file should live in the directory where you run `fontcustom compile`.
4 | # For more info, visit
.
5 | # =============================================================================
6 |
7 |
8 | # -----------------------------------------------------------------------------
9 | # Project Info
10 | # -----------------------------------------------------------------------------
11 |
12 | # The font's name. Also determines the file names of generated templates.
13 | #font_name: icons
14 |
15 | # Format of CSS selectors. {{glyph}} is substituted for the glyph name.
16 | #css_selector: .i-{{glyph}}
17 |
18 | # Generate fonts without asset-busting hashes.
19 | #no_hash: true
20 |
21 | # Encode WOFF fonts into the generated CSS.
22 | #base64: true
23 |
24 | # Forces compilation, even if inputs have not changed
25 | #force: true
26 |
27 | # Display (possibly useful) debugging messages.
28 | #debug: true
29 |
30 | # Hide status messages.
31 | #quiet: true
32 |
33 |
34 | # -----------------------------------------------------------------------------
35 | # Input / Output Locations
36 | # You can save generated fonts, CSS, and other files to different locations
37 | # here. Font Custom can also read input vectors and templates from different
38 | # places.
39 | #
40 | # NOTE:
41 | # - Be sure to preserve the whitespace in these YAML hashes.
42 | # - INPUT[:vectors] and OUTPUT[:fonts] are required. Everything else is
43 | # optional.
44 | # - Specify output locations for custom templates by including their file
45 | # names as the key.
46 | # -----------------------------------------------------------------------------
47 |
48 | #input:
49 | # vectors: my/vectors
50 | # templates: my/templates
51 |
52 | #output:
53 | # fonts: app/assets/fonts
54 | # css: app/assets/stylesheets
55 | # preview: app/views/styleguide
56 | # my-custom-template.yml: path/to/template/output
57 |
58 |
59 | # -----------------------------------------------------------------------------
60 | # Templates
61 | # A YAML array of templates and files to generate alongside fonts. Custom
62 | # templates should be saved in the INPUT[:templates] directory and referenced
63 | # by their base file name.
64 | #
65 | # For Rails and Compass templates, set `preprocessor_path` as the relative
66 | # path from OUTPUT[:css] to OUTPUT[:fonts]. By default, these are the same
67 | # directory.
68 | #
69 | # Included in Font Custom: preview, css, scss, scss-rails
70 | # Default: css, preview
71 | # -----------------------------------------------------------------------------
72 |
73 | #templates:
74 | #- scss-rails
75 | #- preview
76 | #- my-custom-template.yml
77 |
78 | #preprocessor_path: ../fonts/
79 |
80 |
81 | # -----------------------------------------------------------------------------
82 | # Font Settings (defaults shown)
83 | # -----------------------------------------------------------------------------
84 |
85 | # Size (in pica points) for which your font is designed.
86 | #font_design_size: 16
87 |
88 | # The em size. Setting this will scale the entire font to the given size.
89 | #font_em: 512
90 |
91 | # The font's ascent and descent. Used to calculate the baseline.
92 | #font_ascent: 448
93 | #font_descent: 64
94 |
95 | # Horizontally fit glyphs to their individual vector widths.
96 | #autowidth: false
97 |
--------------------------------------------------------------------------------
/website/src/store/selectors.js:
--------------------------------------------------------------------------------
1 | import {createSelector} from 'reselect';
2 | import isEqual from 'lodash.isequal';
3 | import {getParserByID, getTransformerByID} from '../parsers';
4 |
5 | // UI related
6 |
7 | export function getFormattingState(state) {
8 | return state.enableFormatting;
9 | }
10 |
11 | export function getCursor(state) {
12 | return state.cursor;
13 | }
14 |
15 | export function getError(state) {
16 | return state.error;
17 | }
18 |
19 | export function isLoadingSnippet(state) {
20 | return state.loadingSnippet;
21 | }
22 |
23 | export function showSettingsDialog(state) {
24 | return state.showSettingsDialog;
25 | }
26 |
27 | export function showShareDialog(state) {
28 | return state.showShareDialog;
29 | }
30 |
31 | export function isForking(state) {
32 | return state.forking;
33 | }
34 |
35 | export function isSaving(state) {
36 | return state.saving;
37 | }
38 |
39 | // Parser related
40 |
41 | export function getParser(state) {
42 | return getParserByID(state.workbench.parser);
43 | }
44 |
45 | export function getParserSettings(state) {
46 | return state.workbench.parserSettings;
47 | }
48 |
49 | export function getParseError(state) {
50 | return state.workbench.parseError;
51 | }
52 |
53 | // Code related
54 | export function getRevision(state) {
55 | return state.activeRevision;
56 | }
57 |
58 | export function getCode(state) {
59 | return state.workbench.code;
60 | }
61 |
62 | export function getInitialCode(state) {
63 | return state.workbench.initialCode;
64 | }
65 |
66 | const isCodeDirty = createSelector(
67 | [getCode, getInitialCode],
68 | (code, initialCode) => code !== initialCode
69 | );
70 |
71 | // Transform related
72 |
73 | export function getTransformCode(state) {
74 | return state.workbench.transform.code;
75 | }
76 |
77 | export function getInitialTransformCode(state) {
78 | return state.workbench.transform.initialCode;
79 | }
80 |
81 | export function getTransformer(state) {
82 | return getTransformerByID(state.workbench.transform.transformer);
83 | }
84 |
85 | export function showTransformer(state) {
86 | return state.showTransformPanel;
87 | }
88 |
89 | const isTransformDirty = createSelector(
90 | [getTransformCode, getInitialTransformCode],
91 | (code, initialCode) => code !== initialCode
92 | );
93 |
94 | export const canFork = createSelector(
95 | [getRevision],
96 | (revision) => !!revision
97 | );
98 |
99 | const canSaveCode = createSelector(
100 | [getRevision, isCodeDirty],
101 | (revision, dirty) => (
102 | !revision || // can always save if there is no revision
103 | dirty
104 | )
105 | );
106 |
107 | export const canSaveTransform = createSelector(
108 | [showTransformer, isTransformDirty],
109 | (showTransformer, dirty) => showTransformer && dirty
110 | );
111 |
112 | const didParserSettingsChange = createSelector(
113 | [getParserSettings, getRevision, getParser],
114 | (parserSettings, revision, parser) => {
115 | const savedParserSettings = revision && revision.getParserSettings();
116 | return (
117 | !!revision &&
118 | (
119 | parser.id !== revision.getParserID() ||
120 | !!savedParserSettings && !isEqual(parserSettings, savedParserSettings)
121 | )
122 | )
123 |
124 | }
125 | );
126 |
127 | export const canSave = createSelector(
128 | [getRevision, canSaveCode, canSaveTransform, didParserSettingsChange],
129 | (revision, canSaveCode, canSaveTransform, didParserSettingsChange) => (
130 | (canSaveCode || canSaveTransform || didParserSettingsChange) &&
131 | (!revision || revision.canSave())
132 | )
133 | );
134 |
--------------------------------------------------------------------------------
/website/fontcustom/input-svg/icu.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/website/fontcustom/input-svg/handlebars.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/website/src/parsers/js/recast.js:
--------------------------------------------------------------------------------
1 | import React from 'react'; // eslint-disable-line no-unused-vars
2 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
3 | import pkg from 'recast/package.json';
4 | import SettingsRenderer from '../utils/SettingsRenderer';
5 |
6 | import flowParser, * as flowSettings from './flow';
7 | import babylonParser, * as babylonSettings from './babylon6';
8 |
9 | const ID = 'recast';
10 | const defaultOptions = {
11 | tolerant: false,
12 | range: true,
13 | parser: 'esprima',
14 | flow: flowSettings.defaultOptions,
15 | babylon: babylonSettings.defaultOptions,
16 | };
17 |
18 | const parserSettingsConfiguration = {
19 | fields: [
20 | ['parser', ['esprima', 'babel5', 'babylon6', 'flow']],
21 | 'range',
22 | 'tolerant',
23 | {
24 | key: 'flow',
25 | title: 'Flow Settings',
26 | fields: flowSettings.parserSettingsConfiguration.fields,
27 | settings: settings => settings.flow || defaultOptions.flow,
28 | },
29 | {
30 | key: 'babylon',
31 | title: 'Babylon 6 Settings',
32 | fields: babylonSettings.parserSettingsConfiguration.fields,
33 | settings: settings => settings.babylon || defaultOptions.babylon,
34 | },
35 | ],
36 | required: new Set(['range']),
37 | };
38 |
39 | export default {
40 | ...defaultParserInterface,
41 |
42 | id: ID,
43 | displayName: ID,
44 | version: pkg.version,
45 | homepage: pkg.homepage,
46 | locationProps: new Set(['range', 'loc', 'start', 'end']),
47 |
48 | loadParser(callback) {
49 | require(
50 | ['recast', 'babel5', 'babylon6', 'flow-parser'],
51 | (recast, babelCore, babylon6, flow) => {
52 | callback({
53 | recast,
54 | parsers: {
55 | 'babel5': babelCore,
56 | babylon6,
57 | flow,
58 | },
59 | });
60 | }
61 | );
62 | },
63 |
64 | parse({ recast, parsers }, code, options) {
65 | options = {...defaultOptions, ...options};
66 | const flowOptions = options.flow;
67 | const babylonOptions = options.babylon;
68 | delete options.flow;
69 | delete options.babylon;
70 |
71 | switch (options.parser) {
72 | case 'esprima':
73 | delete options.parser; // default parser
74 | break;
75 | case 'flow':
76 | options.parser = {
77 | parse(code) {
78 | return flowParser.parse(parsers.flow, code, flowOptions);
79 | },
80 | };
81 | break;
82 | case 'babylon6':
83 | options.parser = {
84 | parse(code) {
85 | return babylonParser.parse(parsers.babylon6, code, babylonOptions);
86 | },
87 | };
88 | break;
89 | default:
90 | options.parser = parsers[options.parser];
91 | }
92 | return recast.parse(code, options);
93 | },
94 |
95 | _ignoredProperties: new Set(['__clone']),
96 |
97 | *forEachProperty(node) {
98 | for (let prop in node) {
99 | if (
100 | this._ignoredProperties.has(prop) || typeof node[prop] === 'function'
101 | ) {
102 | continue;
103 | }
104 | yield {
105 | value: node[prop],
106 | key: prop,
107 | computed: false,
108 | };
109 | }
110 | },
111 |
112 | nodeToRange(node) {
113 | if (typeof node.start === 'number') {
114 | return [node.start, node.end];
115 | }
116 | return node.range;
117 | },
118 |
119 | renderSettings(parserSettings, onChange) {
120 | return (
121 |
126 | );
127 | },
128 | };
129 |
--------------------------------------------------------------------------------
/scripts/definition-generator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const astTypes = require('ast-types');
4 | const fs = require('fs');
5 | const path = require('path');
6 | const t = require('ast-types/lib/types');
7 |
8 | const types = {};
9 | const builders = {};
10 | const typeCheckers = {};
11 |
12 | function sanitizeTypeName(typeName, fieldName, type) {
13 | if (type === 'boolean') {
14 | return 'bool';
15 | }
16 |
17 | switch(fieldName) {
18 | case 'operator':
19 | case 'kind':
20 | return 'string';
21 | case 'value':
22 | if (typeName === 'TemplateElement') {
23 | return 'TemplateElementValue';
24 | }
25 | default:
26 | if (/number [><=]+ \d+/.test(type)) {
27 | return 'number';
28 | }
29 | return type;
30 | }
31 | }
32 |
33 | function typeNameToString(name) {
34 | return typeof name === 'function' ? name().replace(/\s+/g, '') : name;
35 | }
36 |
37 | for (const typeName in astTypes.namedTypes) {
38 | const typeDef = astTypes.Type.def(typeName);
39 | const definition = {
40 | '!proto': 'ASTNode',
41 | };
42 | const builder = {};
43 |
44 | // Type check function
45 | typeCheckers[typeName] = 'TypeDefinition';
46 |
47 | // Type definition
48 | typeDef.fieldNames.forEach(fieldName => {
49 | definition[fieldName] = sanitizeTypeName(
50 | typeNameToString(typeName, fieldName, typeDef.allFields[fieldName].type.name)
51 | );
52 | });
53 |
54 | // Builder
55 | if (t.getBuilderName(typeName) in astTypes.builders) {
56 | let additionalDocs = '';
57 |
58 | const args = typeDef.buildParams.map(name => {
59 | let type = typeNameToString(typeDef.allFields[name].type.name);
60 | switch(name) {
61 | case 'operator':
62 | case 'kind':
63 | additionalDocs += `${name} (string) one of: ${type}\n`;
64 | type = 'string';
65 | break;
66 | case 'value':
67 | if (typeName === 'TemplateElement') {
68 | additionalDocs += `${name} (object) has form {cooked: string, raw: string}`;
69 | type = 'TemplateElementValue';
70 | }
71 | default:
72 | let match;
73 | if ((match = type.match(/number ([><=]+ \d+)/))) {
74 | additionalDocs += '${name} (number) must be ' + match[1];
75 | type = 'number';
76 | break;
77 | }
78 | }
79 | return `${name}: ${type}`;
80 | });
81 | builders[t.getBuilderName(typeName)] = Object.assign(builder, {
82 | '!type': `fn(${args.join(', ')}) -> ${typeName}`,
83 | '!doc': `Builds an AST node of type '${typeName}'.`,
84 | });
85 | if (typeDef.supertypeList.length > 1) {
86 | builder['!doc'] += '\nSuper types: ' + typeDef.supertypeList.slice(1).join(', ');
87 | }
88 | if (additionalDocs) {
89 | builder['!doc'] += '\n\n ' + additionalDocs;
90 | }
91 | }
92 |
93 | types[typeName] = definition;
94 | }
95 |
96 | const extraTypes = {
97 | TemplateElementValue: {
98 | cooked: 'string',
99 | raw: 'string',
100 | },
101 | TypeDefinition: {
102 | name: 'string',
103 | check: 'fn(node: Node, deep: ?) -> bool',
104 | },
105 | };
106 |
107 | var ternDefinition = require('js-yaml').safeLoad(
108 | fs.readFileSync(path.join(__dirname, './defs/jscodeshift.yaml'), 'utf-8')
109 | );
110 | Object.assign(ternDefinition['!define'], types, extraTypes);
111 | Object.assign(
112 | ternDefinition['!define'].apiObject.jscodeshift,
113 | typeCheckers,
114 | builders
115 | );
116 |
117 | const target = path.resolve(__dirname, '../src/defs/jscodeshift.json');
118 | fs.writeFileSync(
119 | target,
120 | JSON.stringify(ternDefinition, null, 2)
121 | );
122 | process.stdout.write(`Written to "${path.relative(process.cwd(), target)}"...`);
123 |
--------------------------------------------------------------------------------
/website/src/store/actions.js:
--------------------------------------------------------------------------------
1 | export const SET_ERROR = 'SET_ERROR';
2 | export const CLEAR_ERROR = 'CLEAR_ERROR';
3 | export const LOAD_SNIPPET = 'LOAD_SNIPPET';
4 | export const START_LOADING_SNIPPET = 'START_LOADING_SNIPPET';
5 | export const DONE_LOADING_SNIPPET = 'DONE_LOADING_SNIPPET';
6 | export const CLEAR_SNIPPET = 'CLEAR_SNIPPET';
7 | export const SELECT_CATEGORY = 'CHANGE_CATEGORY';
8 | export const SELECT_TRANSFORMER = 'SELECT_TRANSFORMER';
9 | export const HIDE_TRANSFORMER = 'HIDE_TRANSFORMER';
10 | export const SET_TRANSFORM = 'SET_TRANSFORM';
11 | export const SET_PARSER = 'SET_PARSER';
12 | export const SET_PARSER_SETTINGS = 'SET_PARSER_SETTINGS';
13 | export const SET_PARSE_ERROR = 'SET_PARSE_ERROR';
14 | export const SET_SNIPPET = 'SET_SNIPPET';
15 | export const OPEN_SETTINGS_DIALOG = 'OPEN_SETTINGS_DIALOG';
16 | export const CLOSE_SETTINGS_DIALOG = 'CLOSE_SETTINGS_DIALOG';
17 | export const OPEN_SHARE_DIALOG = 'OPEN_SHARE_DIALOG';
18 | export const CLOSE_SHARE_DIALOG = 'CLOSE_SHARE_DIALOG';
19 | export const SET_CODE = 'SET_CODE';
20 | export const SET_CURSOR = 'SET_CURSOR';
21 | export const DROP_TEXT = 'DROP_TEXT';
22 | export const SAVE = 'SAVE';
23 | export const START_SAVE = 'START_SAVE';
24 | export const END_SAVE = 'END_SAVE';
25 | export const RESET = 'RESET';
26 | export const TOGGLE_FORMATTING = 'TOGGLE_FORMATTING';
27 |
28 | export function setParser(parser) {
29 | return {type: SET_PARSER, parser};
30 | }
31 |
32 | export function setParserSettings(settings) {
33 | return {type: SET_PARSER_SETTINGS, settings};
34 | }
35 |
36 | export function save(fork=false) {
37 | return {type: SAVE, fork};
38 | }
39 |
40 | export function startSave(fork) {
41 | return {type: START_SAVE, fork};
42 | }
43 |
44 | export function endSave(fork) {
45 | return {type: END_SAVE, fork};
46 | }
47 |
48 | export function setSnippet(revision) {
49 | return {type: SET_SNIPPET, revision};
50 | }
51 |
52 | export function setParseError(error) {
53 | return {type: SET_PARSE_ERROR, error};
54 | }
55 |
56 | export function selectCategory(category) {
57 | return {type: SELECT_CATEGORY, category};
58 | }
59 |
60 | export function clearSnippet() {
61 | return {type: CLEAR_SNIPPET};
62 | }
63 |
64 | export function startLoadingSnippet() {
65 | return {type: START_LOADING_SNIPPET};
66 | }
67 |
68 | export function doneLoadingSnippet() {
69 | return {type: DONE_LOADING_SNIPPET};
70 | }
71 |
72 | export function loadSnippet() {
73 | return {type: LOAD_SNIPPET};
74 | }
75 |
76 | export function openSettingsDialog() {
77 | return {type: OPEN_SETTINGS_DIALOG};
78 | }
79 |
80 | export function closeSettingsDialog() {
81 | return {type: CLOSE_SETTINGS_DIALOG};
82 | }
83 |
84 | export function openShareDialog() {
85 | return {type: OPEN_SHARE_DIALOG};
86 | }
87 |
88 | export function closeShareDialog() {
89 | return {type: CLOSE_SHARE_DIALOG};
90 | }
91 |
92 | export function setError(error) {
93 | return {type: SET_ERROR, error};
94 | }
95 |
96 | export function clearError() {
97 | return {type: CLEAR_ERROR};
98 | }
99 |
100 | export function selectTransformer(transformer) {
101 | return {type: SELECT_TRANSFORMER, transformer};
102 | }
103 |
104 | export function hideTransformer() {
105 | return {type: HIDE_TRANSFORMER};
106 | }
107 |
108 | export function setTransformState(state) {
109 | return {type: SET_TRANSFORM, ...state};
110 | }
111 |
112 | export function setCode(state) {
113 | return {type: SET_CODE, ...state};
114 | }
115 |
116 | export function setCursor(cursor) {
117 | return {type: SET_CURSOR, cursor};
118 | }
119 |
120 | export function dropText(text, categoryId) {
121 | return {type: DROP_TEXT, text, categoryId};
122 | }
123 |
124 | export function reset() {
125 | return {type: RESET};
126 | }
127 |
128 | export function toggleFormatting() {
129 | return {type: TOGGLE_FORMATTING};
130 | }
131 |
--------------------------------------------------------------------------------
/website/src/parsers/utils/SettingsRenderer.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | const identity = v => v;
5 |
6 | function valuesFromArray(settings) {
7 | return settings.reduce(
8 | (obj, name) => (
9 | (obj[name] = settings.indexOf(name) > -1),
10 | obj
11 | ),
12 | {}
13 | );
14 | }
15 |
16 | function getValuesFromSettings(settings) {
17 | if (Array.isArray(settings)) {
18 | return valuesFromArray(settings);
19 | }
20 | return settings;
21 | }
22 |
23 | function defaultUpdater(settings, name, value) {
24 | return {...settings, [name]: value};
25 | }
26 |
27 | function arrayUpdater(settings, name, value) {
28 | settings = new Set(settings);
29 | if (value) {
30 | settings.add(name);
31 | } else {
32 | settings.delete(name);
33 | }
34 | return Array.from(settings);
35 | }
36 |
37 | function getUpdateStrategy(settings) {
38 | if (Array.isArray(settings)) {
39 | return arrayUpdater;
40 | }
41 | return defaultUpdater;
42 | }
43 |
44 | export default function SettingsRenderer(props) {
45 | const {settingsConfiguration, parserSettings, onChange} = props;
46 | const {
47 | title,
48 | fields,
49 | required = new Set(),
50 | update=getUpdateStrategy(parserSettings),
51 | } = settingsConfiguration;
52 | const values =
53 | (settingsConfiguration.values || getValuesFromSettings)(parserSettings);
54 |
55 | return (
56 |
57 | {title ?
{title}
: null}
58 |
115 |
116 | );
117 | }
118 |
119 | SettingsRenderer.propTypes = {
120 | settingsConfiguration: PropTypes.object.isRequired,
121 | parserSettings: PropTypes.oneOfType([
122 | PropTypes.object,
123 | PropTypes.array,
124 | ]).isRequired,
125 | onChange: PropTypes.func.isRequired,
126 | };
127 |
--------------------------------------------------------------------------------