├── .editorconfig
├── .eslintrc
├── .github
└── ISSUE_TEMPLATE
│ └── bug_report.md
├── .gitignore
├── .gitlab-ci.yml
├── .gitpod.yml
├── .tool-versions
├── .travis.yml
├── CNAME
├── LICENSE.txt
├── README.md
├── assets
├── ast.png
└── source.png
├── scripts
├── build-ci.sh
├── build-site.sh
├── check-conflicts.sh
├── definition-generator.js
├── defs
│ └── jscodeshift.yaml
├── deploy.sh
├── inject-rev.sh
└── publish-latest.sh
├── server
├── constants.js
├── handlers
│ ├── gist
│ │ ├── index.js
│ │ ├── loadGist.js
│ │ └── saveAnonymousGist.js
│ └── parse.js
├── index.js
├── package.json
└── yarn.lock
└── website
├── .fontcustom-manifest.json
├── .npmrc
├── CACHE_BREAKER
├── css
├── highlight.css
└── style.css
├── favicon.png
├── fontcustom
├── README.md
├── config.yml
├── fontcustom-preview.html
├── fontcustom.css
├── fontcustom_45cd59da2a1bc422647cab7f53639319.eot
├── fontcustom_45cd59da2a1bc422647cab7f53639319.svg
├── fontcustom_45cd59da2a1bc422647cab7f53639319.ttf
├── fontcustom_45cd59da2a1bc422647cab7f53639319.woff
├── fontcustom_45cd59da2a1bc422647cab7f53639319.woff2
└── input-svg
│ ├── GraphQL_Logo.svg
│ ├── handlebars.svg
│ ├── icu.svg
│ ├── java.svg
│ ├── ocaml.svg
│ ├── reason.svg
│ ├── rust.svg
│ └── scala.svg
├── index.ejs
├── package.json
├── postcss.config.js
├── src
├── app.js
├── components
│ ├── ASTOutput.js
│ ├── Editor.js
│ ├── ErrorMessage.js
│ ├── GistBanner.js
│ ├── JSCodeshiftEditor.js
│ ├── JSONEditor.js
│ ├── LoadingIndicator.js
│ ├── LocalStorage.js
│ ├── PasteDropTarget.js
│ ├── SettingsDrawer.js
│ ├── SplitPane.js
│ ├── Toolbar.js
│ ├── TransformOutput.js
│ ├── Transformer.js
│ ├── buttons
│ │ ├── CategoryButton.js
│ │ ├── ForkButton.js
│ │ ├── KeyMapButton.js
│ │ ├── NewButton.js
│ │ ├── ParserButton.js
│ │ ├── PrettierButton.js
│ │ ├── SaveButton.js
│ │ ├── ShareButton.js
│ │ ├── SnippetButton.js
│ │ └── TransformButton.js
│ ├── dialogs
│ │ ├── SettingsDialog.js
│ │ └── ShareDialog.js
│ └── visualization
│ │ ├── JSON.js
│ │ ├── SelectedNodeContext.js
│ │ ├── Tree.js
│ │ ├── css
│ │ └── tree.css
│ │ ├── focusNodes.js
│ │ ├── index.js
│ │ └── tree
│ │ ├── CompactArrayView.js
│ │ ├── CompactObjectView.js
│ │ └── Element.js
├── containers
│ ├── ASTOutputContainer.js
│ ├── CodeEditorContainer.js
│ ├── ErrorMessageContainer.js
│ ├── LoadingIndicatorContainer.js
│ ├── PasteDropTargetContainer.js
│ ├── SettingsDialogContainer.js
│ ├── SettingsDrawerContainer.js
│ ├── ShareDialogContainer.js
│ ├── ToolbarContainer.js
│ └── TransformerContainer.js
├── core
│ ├── ParseResult.js
│ └── TreeAdapter.js
├── defs
│ └── jscodeshift.json
├── parsers
│ ├── css
│ │ ├── codeExample.txt
│ │ ├── cssom.js
│ │ ├── csstree.js
│ │ ├── index.js
│ │ ├── postcss.js
│ │ ├── rework.js
│ │ ├── transformers
│ │ │ └── postcss
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ └── utils
│ │ │ └── defaultCSSParserInterface.js
│ ├── glsl
│ │ ├── codeExample.txt
│ │ ├── codemirror-mode
│ │ │ └── glsl.js
│ │ ├── glsl-parser.js
│ │ └── index.js
│ ├── go
│ │ ├── codeExample.txt
│ │ ├── go.js
│ │ └── index.js
│ ├── graphql
│ │ ├── codeExample.txt
│ │ ├── graphql-js.js
│ │ └── index.js
│ ├── graphviz
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── redot.js
│ ├── handlebars
│ │ ├── codeExample.txt
│ │ ├── ember-template-recast.js
│ │ ├── glimmer.js
│ │ ├── handlebars.js
│ │ ├── index.js
│ │ ├── transformers
│ │ │ ├── ember-template-recast
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── glimmer-compiler
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ └── glimmer
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ └── utils
│ │ │ └── defaultHandlebarsParserInterface.js
│ ├── html
│ │ ├── angular-eslint.js
│ │ ├── angular.js
│ │ ├── codeExample.txt
│ │ ├── htmlparser2.js
│ │ ├── hyntax.js
│ │ ├── index.js
│ │ ├── parse5.js
│ │ ├── posthtml.js
│ │ ├── svelte.js
│ │ └── transformers
│ │ │ ├── posthtml
│ │ │ ├── codeExample.txt
│ │ │ └── index.js
│ │ │ └── svelte
│ │ │ ├── codeExample.txt
│ │ │ └── index.js
│ ├── icu
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── intl-messageformat-parser.js
│ ├── index.js
│ ├── java
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── java-parser.js
│ ├── js
│ │ ├── acorn-to-esprima.js
│ │ ├── acorn.js
│ │ ├── babel-eslint-parser.js
│ │ ├── babel-eslint.js
│ │ ├── babel-eslint8.js
│ │ ├── babel-eslint9.js
│ │ ├── babylon.js
│ │ ├── babylon6.js
│ │ ├── babylon7.js
│ │ ├── codeExample.txt
│ │ ├── esformatter.js
│ │ ├── espree.js
│ │ ├── esprima.js
│ │ ├── flow.js
│ │ ├── hermes.js
│ │ ├── hermes
│ │ │ ├── HermesWorkerClient.js
│ │ │ └── hermes-worker.js
│ │ ├── index.js
│ │ ├── meriyah.js
│ │ ├── recast.js
│ │ ├── seafox.js
│ │ ├── shift.js
│ │ ├── swc.js
│ │ ├── tenko.js
│ │ ├── traceur.js
│ │ ├── transformers
│ │ │ ├── babel-plugin-macros
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── babel
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── babel6
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── babel7
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── eslint1
│ │ │ │ ├── codeExample.txt
│ │ │ │ ├── index.js
│ │ │ │ └── loadRulesShim.js
│ │ │ ├── eslint2
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── eslint3
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── eslint4
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── eslint8
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── jscodeshift
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── prettier
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── recast
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ ├── tslint
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ │ └── typescript
│ │ │ │ ├── codeExample.txt
│ │ │ │ └── index.js
│ │ ├── typescript-eslint-parser.js
│ │ ├── typescript.js
│ │ ├── uglify.js
│ │ └── utils
│ │ │ ├── defaultESTreeParserInterface.js
│ │ │ ├── eslint4Utils.js
│ │ │ └── eslintUtils.js
│ ├── json
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ ├── json-to-ast.js
│ │ └── momoa.js
│ ├── lua
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── luaparse.js
│ ├── lucene
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── lucene.js
│ ├── markdown
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ ├── remark.js
│ │ └── transformers
│ │ │ └── remark
│ │ │ ├── codeExample.txt
│ │ │ └── index.js
│ ├── mathjs
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── mathjs.js
│ ├── mdx
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ ├── mdxhast.js
│ │ └── transformers
│ │ │ └── mdx
│ │ │ ├── codeExample.txt
│ │ │ └── index.js
│ ├── monkey
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── monkey.js
│ ├── ocaml
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── refmt-ml.js
│ ├── php
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── php-parser.js
│ ├── protobuf
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── pbkit.js
│ ├── pug
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── pug.js
│ ├── python
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── python.js
│ ├── reason
│ │ ├── codeExample.txt
│ │ ├── codeMirrorMode.js
│ │ ├── index.js
│ │ └── refmt.js
│ ├── regexp
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ ├── regexp-tree.js
│ │ ├── regexpp.js
│ │ ├── regjsparser.js
│ │ └── transformers
│ │ │ └── regexp-tree
│ │ │ ├── codeExample.txt
│ │ │ └── index.js
│ ├── rust
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── syn.js
│ ├── san
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── san-template-parser.js
│ ├── scala
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── scalameta.js
│ ├── solididy
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ ├── solidity-parser-antlr.js
│ │ └── solidity-parser-diligence.js
│ ├── sql
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ ├── sql-parser-cst.js
│ │ └── sqlite-parser.js
│ ├── svelte
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── svelte-parser.js
│ ├── thrift
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── thrift-parser.js
│ ├── transpilers
│ │ ├── babel.js
│ │ └── typescript.js
│ ├── utils
│ │ ├── SettingsRenderer.js
│ │ ├── compileModule.js
│ │ ├── defaultParserInterface.js
│ │ └── protectFromLoops.js
│ ├── vue
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ ├── vue-compiler-dom.js
│ │ ├── vue-eslint-parser.js
│ │ └── vue-template-compiler.js
│ ├── wat
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── wat-parser.js
│ ├── webidl
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ └── webidl2.js
│ └── yaml
│ │ ├── codeExample.txt
│ │ ├── index.js
│ │ ├── yaml-ast-parser.js
│ │ └── yaml.js
├── shims
│ └── jest-validate.js
├── storage
│ ├── api.js
│ ├── gist.js
│ ├── index.js
│ └── parse.js
├── store
│ ├── actions.js
│ ├── parserMiddleware.js
│ ├── reducers.js
│ ├── selectors.js
│ ├── snippetMiddleware.js
│ └── transformerMiddleware.js
└── utils
│ ├── classnames.js
│ ├── debounce.js
│ ├── pubsub.js
│ └── stringify.js
├── webpack.config.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.js]
2 | quote_type = single
3 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | extends:
2 | - eslint:recommended
3 | - plugin:react/recommended
4 | - plugin:import/errors
5 | - plugin:import/warnings
6 |
7 | parserOptions:
8 | ecmaVersion: 2018
9 | sourceType: module
10 | ecmaFeatures:
11 | jsx: true
12 | experimentalObjectRestSpread: true
13 |
14 | plugins:
15 | - react
16 | - import
17 | - require-in-package
18 |
19 | rules:
20 | comma-dangle: ["error", "always-multiline"]
21 | new-cap: "off"
22 | no-path-concat: "off"
23 | no-undef: "error"
24 | no-underscore-dangle: "off"
25 | no-unused-vars:
26 | - "warn"
27 | - varsIgnorePattern: "^_"
28 | argsIgnorePattern: "^_"
29 | no-use-before-define: "off"
30 | quotes: ["error", "single", "avoid-escape"]
31 | strict: "off"
32 | import/no-unresolved: ["error", {commonjs: true, amd: true}]
33 | import/named: "error"
34 | import/default: "error"
35 | import/namespace: "error"
36 | import/export: "error"
37 | require-in-package/require-in-package: "error"
38 | react/display-name: off
39 |
40 | settings:
41 | import/resolver: "webpack"
42 | import/ignore:
43 | - node_modules
44 | - \.json
45 |
46 | env:
47 | browser: true
48 | node: true
49 |
50 | globals:
51 | loadjs: true
52 | Promise: true
53 | Map: true
54 | Set: true
55 | WeakMap: true
56 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior:
12 | 1. Go to '...'
13 | 2. Click on '....'
14 | 3. Scroll down to '....'
15 | 4. See error
16 |
17 | **Expected behavior**
18 | A clear and concise description of what you expected to happen.
19 |
20 | **Screenshots**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **Browser (please complete the following information):**
24 | - OS: [e.g. iOS]
25 | - Browser [e.g. chrome, safari]
26 | - Version [e.g. 22]
27 |
28 | **astexplorer settings:**
29 | - Selected parser: [e.g. acorn]
30 | - Selected transformer (if applicable): [e.g. jscodeshift]
31 | - Contents of the local storage key `explorerSettingsV1` (code can be removed if you don't want it to be public)
32 |
33 | **Additional context**
34 | Add any other context about the problem here.
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /out
2 | node_modules
3 | .idea
4 | package-lock.json
5 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 |
2 | tasks:
3 | - init: cd website && yarn
4 | command: yarn dev
5 | - init: fish
6 |
7 | ports:
8 | - port: 8080
9 | onOpen: open-preview
10 | visibility: public
11 |
12 |
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | nodejs lts-gallium
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - node
5 | cache:
6 | yarn: true
7 | directories:
8 | - website/node_modules
9 | before_install:
10 | - curl -o- -L https://yarnpkg.com/install.sh | bash
11 | - export PATH=$HOME/.yarn/bin:$PATH
12 | install:
13 | - cd website
14 | - yarn install --production=false
15 | before_script:
16 | - yarn lint
17 | script:
18 | - yarn watch -- --no-watch
19 | env:
20 | - NODE_ENV=development
21 | - NODE_ENV=production
22 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | astexplorer.net
2 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2014-2021 Felix Kling and astexplorer contributors https://astexplorer.net
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the “Software”), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 | of the Software, and to permit persons to whom the Software is furnished to do
10 | so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/assets/ast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fkling/astexplorer/8888701e97c2efebe6fb118484e67cfc0077d08c/assets/ast.png
--------------------------------------------------------------------------------
/assets/source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fkling/astexplorer/8888701e97c2efebe6fb118484e67cfc0077d08c/assets/source.png
--------------------------------------------------------------------------------
/scripts/build-ci.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | rm -rf out/*
6 | (
7 | cd website/
8 | yarn
9 | if [ "$1" = "--dev" ]; then
10 | yarn build-dev
11 | else
12 | yarn build
13 | fi
14 | )
15 |
--------------------------------------------------------------------------------
/scripts/check-conflicts.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | SOURCE_DIR=$1
4 | TARGET_DIR=$2
5 |
6 | for source_file in $(ls $1); do
7 | target_path=$TARGET_DIR/$source_file
8 | source_path=$SOURCE_DIR/$source_file
9 |
10 | if ! [ -f $target_path ]; then
11 | # If a file with the same name doesn't exist in the target directory, all is
12 | # good.
13 | continue
14 | fi
15 |
16 | case $source_file in
17 | # These files are allowed to differ since the are
18 | # not cached
19 | index.html|favicon.png)
20 | continue
21 | ;;
22 | esac
23 |
24 | if ! diff --brief $target_path $source_path > /dev/null; then
25 | echo "File '$source_file' already exists but has different content."
26 | conflict=1
27 | fi
28 | done
29 |
30 | if [ -n "$conflict" ]; then
31 | echo "Bump the cache breaker."
32 | exit 1
33 | fi
34 |
--------------------------------------------------------------------------------
/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 $REMOTE $BRANCH
19 |
--------------------------------------------------------------------------------
/scripts/inject-rev.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # This script replaces the special character sequence @@COMMIT@@ in a file with
4 | # a link to the commit on GitHub. The file path is passed as argument but is
5 | # likely just out/index.html
6 |
7 | rev=$(git rev-parse --short HEAD)
8 | sed -i "s%@@COMMIT@@%Build: $rev%" "$1"
9 |
--------------------------------------------------------------------------------
/scripts/publish-latest.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | REMOTE=${1:-"server"}
6 | LATEST_BRANCH=${2:-"website-latest"}
7 | STABLE_BRANCH=${3:-"website-stable"}
8 |
9 | TARGETPATH="../$(basename $(pwd))_$STABLE_BRANCH"
10 | WORKING_DIR=$(pwd)
11 |
12 | trap cleanup EXIT
13 |
14 | function cleanup {
15 | if [ -d $TARGETPATH ]; then
16 | echo "Cleaning up worktree"
17 | git worktree remove -f $TARGETPATH
18 | fi
19 | cd $WORKING_DIR
20 | }
21 |
22 | echo "Creating worktree for $STABLE_BRANCH..."
23 | # Initialize worktree
24 | git worktree add $TARGETPATH $STABLE_BRANCH || exit 1
25 |
26 | cd $TARGETPATH
27 |
28 | echo "Merging $LATEST_BRANCH into $STABLE_BRANCH..."
29 | git merge --squash --strategy-option=theirs $LATEST_BRANCH
30 |
31 | if ! git diff --cached --quiet; then
32 | git commit -m"Publish"
33 | $WORKING_DIR/scripts/deploy.sh $REMOTE $STABLE_BRANCH
34 | else
35 | echo "Nothing to do"
36 | fi
37 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/server/handlers/gist/index.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const loadGist = require('./loadGist');
3 | const saveAnonymousGist = require('./saveAnonymousGist');
4 |
5 | module.exports = express.Router()
6 | // Load snippet
7 | .get('/:snippetid/:revisionid', loadGist)
8 | // Create new "anonymous" snippet
9 | .post('/', saveAnonymousGist.create)
10 | // Update "anonymous" snippet
11 | .patch('/:snippetid', saveAnonymousGist.update)
12 | // Fork "anonymous" snippet
13 | .post('/:snippetid/:revisionid', saveAnonymousGist.fork);
14 |
--------------------------------------------------------------------------------
/server/handlers/gist/loadGist.js:
--------------------------------------------------------------------------------
1 | const {AUTH_TOKEN} = require('../../constants');
2 | const GitHub = require('github-api');
3 |
4 | module.exports = function loadGist(req, res, next) {
5 | const gh = new GitHub({token: AUTH_TOKEN});
6 | const gist = gh.getGist(req.params.snippetid);
7 | const latest = req.params.revisionid === 'latest';
8 | (latest ?
9 | gist.read() :
10 | gist.getRevision(req.params.revisionid)
11 | )
12 | .then(response => res.json(response.data))
13 | .catch(next);
14 | };
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/server/handlers/parse.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const path = require('path');
3 | const snippets = prepareData(require(process.env.SNIPPET_FILE));
4 | const snippetRevisions = prepareData(require(process.env.REVISION_FILE));
5 |
6 | function notFound(req, res) {
7 | console.error(`Not found: ${req.path}`);
8 | res.sendStatus(404);
9 | }
10 |
11 | module.exports = express.Router()
12 | // Load snippet
13 | .get('/:snippetid/:revisionid', load);
14 |
15 | function prepareData(data) {
16 | // Array of objects -> Map index by object ID
17 | const m = new Map();
18 | data.forEach(obj => m.set(obj._id, obj));
19 | return m;
20 | }
21 |
22 | function load(req, res, next) {
23 | const snippet = snippets.get(req.params.snippetid);
24 | let revisionID = req.params.revisionid;
25 |
26 | if (!snippet) {
27 | return notFound(req, res);
28 | }
29 |
30 | if (revisionID === 'latest') {
31 | revisionID = snippet.revisions.length - 1;
32 | }
33 |
34 | if (+revisionID != revisionID || revisionID >= snippet.revisions.length) {
35 | return notFound(req, res);
36 | }
37 |
38 | const revision = snippetRevisions.get(snippet.revisions[revisionID].objectId);
39 |
40 | if (!revision) {
41 | return notFound(req, res);
42 | }
43 |
44 | const copy = Object.assign(
45 | {
46 | revisionID: +revisionID,
47 | snippetID: snippet._id,
48 | },
49 | revision
50 | );
51 | delete copy._id;
52 |
53 | // The data will never change but we don't want to keep it in caches
54 | // unnecessarily
55 | // res.append('Cache-Control', 'max-age=86400, public'); // 24h
56 | res.json(copy);
57 | }
58 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | const bodyParser = require('body-parser');
2 | const express = require('express');
3 | const path = require('path');
4 |
5 | const app = express();
6 | app.use(bodyParser.json());
7 |
8 | app.use('/api/v1/gist', require('./handlers/gist'));
9 |
10 | if (process.env.SNIPPET_FILE && process.env.REVISION_FILE) {
11 | console.log('Serving Parse snippets enabled.');
12 | app.use('/api/v1/parse', require('./handlers/parse'));
13 | }
14 |
15 | // `next` is needed here to mark this as an error handler
16 | // eslint-disable-next-line no-unused-vars
17 | app.use((err, req, res, next) => {
18 | console.error((new Date()).toLocaleString(), err);
19 | if (err.response) {
20 | res.status(err.response.status).send(err.response.statusText);
21 | return;
22 | }
23 | // eslint-disable-next-line no-console
24 | res.status(500).send('Something went wrong');
25 | });
26 |
27 | if (process.env.STATIC) {
28 | app.use(express.static(path.join(__dirname, process.env.STATIC)));
29 | }
30 |
31 | const PORT = process.env.PORT || 8080;
32 | app.listen(
33 | PORT,
34 | 'localhost',
35 | () => {
36 | console.log(`Server listening on port ${PORT}!`);
37 | }
38 | );
39 |
--------------------------------------------------------------------------------
/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/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/website/CACHE_BREAKER:
--------------------------------------------------------------------------------
1 | 27
2 |
--------------------------------------------------------------------------------
/website/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fkling/astexplorer/8888701e97c2efebe6fb118484e67cfc0077d08c/website/favicon.png
--------------------------------------------------------------------------------
/website/fontcustom/README.md:
--------------------------------------------------------------------------------
1 | # Custom Fonts
2 |
3 | There's not a great way to customize font-awesome at the moment
4 | (see: https://github.com/FortAwesome/Font-Awesome/wiki/Customize-Font-Awesome).
5 |
6 | So we are using [fontcustom](https://github.com/FontCustom/fontcustom) to add
7 | custom logos / fonts to the app.
8 |
9 | ## Build Instructions
10 |
11 | - install fontcustom: https://github.com/FontCustom/fontcustom#installation
12 | - add the svgs you want to convert to the `./fontcustom/input-svg/` directory
13 | - in the root of the astexplorer project, run:
14 | ```bash
15 | yarn run fontcustom
16 | ```
17 | - you can then confirm things worked by running
18 | `open ./fontcustom/fontcustom-preview.html`
19 | - now you can reference your icons in a very similar manner to font-awesome,
20 | for example:
21 | - font-awesome: ``
22 | - fontcustom: ``
23 | (if you added `./fontcustom/input-svg/myfoo.svg`)
24 |
--------------------------------------------------------------------------------
/website/fontcustom/fontcustom.css:
--------------------------------------------------------------------------------
1 | /*
2 | Icon Font: fontcustom
3 | */
4 |
5 | @font-face {
6 | font-family: "fontcustom";
7 | src: url("./fontcustom_45cd59da2a1bc422647cab7f53639319.eot");
8 | src: url("./fontcustom_45cd59da2a1bc422647cab7f53639319.eot?#iefix") format("embedded-opentype"),
9 | url("./fontcustom_45cd59da2a1bc422647cab7f53639319.woff2") format("woff2"),
10 | url("./fontcustom_45cd59da2a1bc422647cab7f53639319.woff") format("woff"),
11 | url("./fontcustom_45cd59da2a1bc422647cab7f53639319.ttf") format("truetype"),
12 | url("./fontcustom_45cd59da2a1bc422647cab7f53639319.svg#fontcustom") format("svg");
13 | font-weight: normal;
14 | font-style: normal;
15 | }
16 |
17 | @media screen and (-webkit-min-device-pixel-ratio:0) {
18 | @font-face {
19 | font-family: "fontcustom";
20 | src: url("./fontcustom_45cd59da2a1bc422647cab7f53639319.svg#fontcustom") format("svg");
21 | }
22 | }
23 |
24 | [data-icon]:before { content: attr(data-icon); }
25 |
26 | [data-icon]:before,
27 | .icon-GraphQL_Logo:before,
28 | .icon-handlebars:before,
29 | .icon-icu:before,
30 | .icon-java:before,
31 | .icon-ocaml:before,
32 | .icon-reason:before,
33 | .icon-rust:before,
34 | .icon-scala:before {
35 | display: inline-block;
36 | font-family: "fontcustom";
37 | font-style: normal;
38 | font-weight: normal;
39 | font-variant: normal;
40 | line-height: 1;
41 | text-decoration: inherit;
42 | text-rendering: optimizeLegibility;
43 | text-transform: none;
44 | -moz-osx-font-smoothing: grayscale;
45 | -webkit-font-smoothing: antialiased;
46 | font-smoothing: antialiased;
47 | }
48 |
49 | .icon-GraphQL_Logo:before { content: "\f100"; }
50 | .icon-handlebars:before { content: "\f101"; }
51 | .icon-icu:before { content: "\f102"; }
52 | .icon-java:before { content: "\f107"; }
53 | .icon-ocaml:before { content: "\f106"; }
54 | .icon-reason:before { content: "\f105"; }
55 | .icon-rust:before { content: "\f104"; }
56 | .icon-scala:before { content: "\f103"; }
57 |
--------------------------------------------------------------------------------
/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fkling/astexplorer/8888701e97c2efebe6fb118484e67cfc0077d08c/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.eot
--------------------------------------------------------------------------------
/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fkling/astexplorer/8888701e97c2efebe6fb118484e67cfc0077d08c/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.ttf
--------------------------------------------------------------------------------
/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fkling/astexplorer/8888701e97c2efebe6fb118484e67cfc0077d08c/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.woff
--------------------------------------------------------------------------------
/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fkling/astexplorer/8888701e97c2efebe6fb118484e67cfc0077d08c/website/fontcustom/fontcustom_45cd59da2a1bc422647cab7f53639319.woff2
--------------------------------------------------------------------------------
/website/fontcustom/input-svg/reason.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/website/fontcustom/input-svg/scala.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/website/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | this.container = c}/>
62 | );
63 | }
64 | }
65 |
66 | Editor.propTypes = {
67 | value: PropTypes.string,
68 | className: PropTypes.string,
69 | };
70 |
--------------------------------------------------------------------------------
/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 |
:
12 | null;
13 | }
14 |
15 | LoadingIndicator.propTypes = {
16 | visible: PropTypes.bool,
17 | };
18 |
--------------------------------------------------------------------------------
/website/src/components/LocalStorage.js:
--------------------------------------------------------------------------------
1 | const storage = global.localStorage;
2 | const key = 'explorerSettingsV1';
3 | const noop = () => {};
4 |
5 | export const writeState = storage ?
6 | state => {
7 | try {
8 | storage.setItem(key, JSON.stringify(state));
9 | } catch(e) {
10 | // eslint-disable-next-line no-console
11 | console.warn('Unable to write to local storage.');
12 | }
13 | } :
14 | noop;
15 |
16 | export const readState = storage ?
17 | () => {
18 | try {
19 | const state = storage.getItem(key);
20 | if (state) {
21 | return JSON.parse(state);
22 | }
23 | } catch(e) {
24 | // eslint-disable-next-line no-console
25 | console.warn('Unable to read from local storage.');
26 | }
27 | } :
28 | noop;
29 |
--------------------------------------------------------------------------------
/website/src/components/SettingsDrawer.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | export default class SettingsDrawer extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this._expand = this._expand.bind(this);
8 | this._collapse = this._collapse.bind(this);
9 | }
10 |
11 | _expand() {
12 | this.props.onWantToExpand();
13 | }
14 |
15 | _collapse() {
16 | this.props.onWantToCollapse();
17 | }
18 |
19 | render() {
20 | return (
21 | this.props.isOpen ?
22 |
23 |
Settings
24 |
25 |
26 | :
27 |
28 | );
29 | }
30 | }
31 |
32 | SettingsDrawer.propTypes = {
33 | onWantToExpand: PropTypes.func,
34 | onWantToCollapse: PropTypes.func,
35 | isOpen: PropTypes.bool,
36 | };
37 |
--------------------------------------------------------------------------------
/website/src/components/Transformer.js:
--------------------------------------------------------------------------------
1 | import Editor from './Editor';
2 | import JSCodeshiftEditor from './JSCodeshiftEditor';
3 | import PropTypes from 'prop-types';
4 | import {publish} from '../utils/pubsub.js';
5 | import * as React from 'react';
6 | import SplitPane from './SplitPane';
7 | import TransformOutput from './TransformOutput';
8 | import PrettierButton from './buttons/PrettierButton';
9 |
10 | function resize() {
11 | publish('PANEL_RESIZE');
12 | }
13 |
14 | export default function Transformer(props) {
15 | const plainEditor = React.createElement(
16 | props.transformer.id === 'jscodeshift' ? JSCodeshiftEditor : Editor,
17 | {
18 | highlight: false,
19 | value: props.transformCode,
20 | onContentChange: props.onContentChange,
21 | enableFormatting: props.enableFormatting,
22 | keyMap: props.keyMap,
23 | },
24 | );
25 |
26 | const formattingEditor = (
27 |
28 | {plainEditor}
29 | )
30 |
31 | return (
32 |
35 | {formattingEditor}
36 |
40 |
41 | );
42 | }
43 |
44 | Transformer.propTypes = {
45 | defaultTransformCode: PropTypes.string,
46 | transformCode: PropTypes.string,
47 | transformer: PropTypes.object,
48 | mode: PropTypes.string,
49 | keyMap: PropTypes.string,
50 | onContentChange: PropTypes.func,
51 | toggleFormatting: PropTypes.func,
52 | enableFormatting: PropTypes.bool,
53 | transformResult: PropTypes.object,
54 | };
55 |
--------------------------------------------------------------------------------
/website/src/components/buttons/ForkButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import cx from '../../utils/classnames.js';
4 |
5 | export default class ForkButton extends React.Component {
6 | render() {
7 | const { canFork, saving, forking, onFork } = this.props;
8 | return (
9 |
25 | );
26 | }
27 | }
28 |
29 | ForkButton.propTypes = {
30 | canFork: PropTypes.bool,
31 | saving: PropTypes.bool,
32 | forking: PropTypes.bool,
33 | onFork: PropTypes.func,
34 | };
35 |
--------------------------------------------------------------------------------
/website/src/components/buttons/KeyMapButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import cx from '../../utils/classnames.js';
4 |
5 | const keyMappings = ['default', 'vim', 'emacs', 'sublime']
6 |
7 | class KeyMapButton extends React.Component {
8 | render() {
9 | return (
10 |
14 |
25 | {
26 | {keyMappings.map(keyMap => (
27 | - this.props.onKeyMapChange(keyMap)}>
31 |
34 |
35 | ))}
36 |
}
37 |
38 | );
39 | }
40 | }
41 |
42 | KeyMapButton.propTypes = {
43 | onKeyMapChange: PropTypes.func,
44 | keyMap: PropTypes.string,
45 | }
46 |
47 | export default KeyMapButton
48 |
--------------------------------------------------------------------------------
/website/src/components/buttons/NewButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | export default function SaveButton({saving, forking, onNew}) {
5 | return (
6 |
12 | );
13 | }
14 |
15 | SaveButton.propTypes = {
16 | saving: PropTypes.bool,
17 | forking: PropTypes.bool,
18 | onNew: PropTypes.func,
19 | };
20 |
21 |
--------------------------------------------------------------------------------
/website/src/components/buttons/ParserButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import {getParserByID} from '../../parsers';
4 |
5 | export default class ParserButton extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this._onClick = this._onClick.bind(this);
9 | }
10 |
11 | _onClick({currentTarget}) {
12 | let parserID = currentTarget.getAttribute('data-id');
13 | this.props.onParserChange(getParserByID(parserID));
14 | }
15 |
16 | render() {
17 | const parsers = this.props.category.parsers.filter(p => p.showInMenu);
18 | return (
19 |
20 |
21 |
22 | {this.props.parser.displayName}
23 |
24 |
25 | {parsers.map(parser => (
26 | -
27 |
30 |
31 | ))}
32 |
33 |
41 |
42 | );
43 | }
44 | }
45 |
46 | ParserButton.propTypes = {
47 | onParserChange: PropTypes.func,
48 | onParserSettingsButtonClick: PropTypes.func,
49 | parser: PropTypes.object,
50 | category: PropTypes.object,
51 | };
52 |
--------------------------------------------------------------------------------
/website/src/components/buttons/PrettierButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import cx from '../../utils/classnames.js';
4 |
5 | export default function PrettierButton(props) {
6 | return (
);
20 | }
21 |
22 | PrettierButton.propTypes = {
23 | toggleFormatting: PropTypes.func,
24 | enableFormatting: PropTypes.bool,
25 | }
26 |
--------------------------------------------------------------------------------
/website/src/components/buttons/SaveButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import cx from '../../utils/classnames.js';
4 |
5 | export default function SaveButton({canSave, saving, forking, onSave}) {
6 | return (
7 |
23 | );
24 | }
25 |
26 | SaveButton.propTypes = {
27 | canSave: PropTypes.bool,
28 | saving: PropTypes.bool,
29 | forking: PropTypes.bool,
30 | onSave: PropTypes.func,
31 | };
32 |
--------------------------------------------------------------------------------
/website/src/components/buttons/ShareButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | export default function ShareButton({onShareButtonClick, snippet}) {
5 | return (
6 |
12 | );
13 | }
14 |
15 | ShareButton.propTypes = {
16 | onShareButtonClick: PropTypes.func.isRequired,
17 | snippet: PropTypes.object,
18 | };
19 |
--------------------------------------------------------------------------------
/website/src/components/buttons/SnippetButton.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import ForkButton from './ForkButton';
4 | import NewButton from './NewButton';
5 | import SaveButton from './SaveButton';
6 | import ShareButton from './ShareButton';
7 | import cx from '../../utils/classnames.js';
8 |
9 | export default function SnippetButton(props) {
10 | const canForkAndNotSave = props.canFork && !props.canSave;
11 | const savingOrForking = props.saving || props.forking;
12 |
13 | return (
14 |
15 |
16 |
17 | Snippet
18 |
19 |
25 |
44 |
45 | );
46 | }
47 |
48 | SnippetButton.propTypes = {
49 | canFork: PropTypes.bool,
50 | canSave: PropTypes.bool,
51 | forking: PropTypes.bool,
52 | onFork: PropTypes.func,
53 | onSave: PropTypes.func,
54 | saving: PropTypes.bool,
55 | };
56 |
--------------------------------------------------------------------------------
/website/src/components/dialogs/ShareDialog.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | export default class ShareDialog extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this._outerClick = this._outerClick.bind(this);
8 | }
9 |
10 | _outerClick(event) {
11 | if (event.target === document.getElementById('ShareDialog')) {
12 | this.props.onWantToClose();
13 | }
14 | }
15 |
16 | render() {
17 | if (this.props.visible) {
18 | return (
19 |
20 |
21 |
22 | {this.props.snippet.getShareInfo()}
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 | }
31 | return null;
32 | }
33 | }
34 |
35 | ShareDialog.propTypes = {
36 | onWantToClose: PropTypes.func.isRequired,
37 | visible: PropTypes.bool.isRequired,
38 | snippet: PropTypes.object,
39 | };
40 |
--------------------------------------------------------------------------------
/website/src/components/visualization/JSON.js:
--------------------------------------------------------------------------------
1 | import JSONEditor from '../JSONEditor';
2 | import PropTypes from 'prop-types';
3 | import React from 'react';
4 |
5 | import stringify from 'json-stringify-safe';
6 |
7 | export default function JSON({parseResult}) {
8 | return (
9 |
13 | );
14 | }
15 |
16 | JSON.propTypes = {
17 | parseResult: PropTypes.object,
18 | };
19 |
--------------------------------------------------------------------------------
/website/src/components/visualization/SelectedNodeContext.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const SelectedNodeContext = React.createContext();
4 |
5 | function useSelectedNode() {
6 | const context = React.useContext(SelectedNodeContext);
7 | if (!context) {
8 | throw new Error('useSelectedNode must be used within a SelectedNodeContext');
9 | }
10 | return context;
11 | }
12 |
13 | let unselectCallback;
14 |
15 | function setSelectedNode(node, cb) {
16 | if (unselectCallback) {
17 | unselectCallback();
18 | }
19 | if (node) {
20 | global.$node = node;
21 | unselectCallback = cb;
22 | } else {
23 | unselectCallback = null;
24 | delete global.$node;
25 | }
26 | }
27 |
28 | function SelectedNodeProvider(props) {
29 | return
;
30 | }
31 |
32 | export {SelectedNodeProvider, useSelectedNode};
33 |
--------------------------------------------------------------------------------
/website/src/components/visualization/css/tree.css:
--------------------------------------------------------------------------------
1 | .tree-visualization {
2 | display: flex;
3 | flex-direction: column;
4 | }
5 |
6 | .tree-visualization > .toolbar {
7 | padding: 5px;
8 | flex-shrink: 0;
9 | }
10 |
11 | .tree-visualization > .toolbar label {
12 | cursor: pointer;
13 | margin-right: 5px;
14 | -webkit-touch-callout: none;
15 | user-select: none;
16 | white-space: nowrap;
17 | }
18 |
19 | .tree-visualization ul {
20 | margin: 0;
21 | padding-left: 20px;
22 | overflow: auto;
23 | }
24 |
25 | .tree-visualization > ul {
26 | cursor: default;
27 | box-sizing: border-box;
28 | font-family: monospace;
29 | -webkit-touch-callout: none;
30 | user-select: none;
31 | flex: 1;
32 | }
33 |
34 | .tree-visualization .value-body {
35 | min-width: 300px;
36 | width: fit-content;
37 | }
38 |
--------------------------------------------------------------------------------
/website/src/components/visualization/index.js:
--------------------------------------------------------------------------------
1 | import JSON from './JSON';
2 | import Tree from './Tree';
3 |
4 | export default [
5 | Tree,
6 | JSON,
7 | ];
8 |
--------------------------------------------------------------------------------
/website/src/components/visualization/tree/CompactArrayView.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | export default class CompactArrayView extends React.Component {
5 | shouldComponentUpdate(nextProps) {
6 | return nextProps.array.length !== this.props.array.length;
7 | }
8 |
9 | render() {
10 | let {array} = this.props;
11 | let count = array.length;
12 |
13 | if (count === 0) {
14 | return
{'[ ]'};
15 | }
16 | else {
17 | return (
18 |
19 | {'['}
20 |
21 | {count + ' element' + (count > 1 ? 's' : '')}
22 |
23 | {']'}
24 |
25 | );
26 | }
27 | }
28 | }
29 |
30 | CompactArrayView.propTypes = {
31 | /**
32 | * The array of elements to represent.
33 | */
34 | array: PropTypes.oneOfType([
35 | PropTypes.array,
36 | PropTypes.shape({ length: PropTypes.number }),
37 | ]).isRequired,
38 | onClick: PropTypes.func,
39 | };
40 |
--------------------------------------------------------------------------------
/website/src/components/visualization/tree/CompactObjectView.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 |
4 | export default function CompactObjectView({keys, onClick}) {
5 | if (keys.length === 0) {
6 | return
{'{ }'};
7 | } else {
8 | if (keys.length > 5) {
9 | keys = keys.slice(0, 5).concat([`... +${keys.length - 5}`]);
10 | }
11 | return (
12 |
13 | {'{'}
14 |
15 | {keys.join(', ')}
16 |
17 | {'}'}
18 |
19 | );
20 | }
21 | }
22 |
23 | CompactObjectView.propTypes = {
24 | keys: PropTypes.arrayOf(PropTypes.string).isRequired,
25 | onClick: PropTypes.func,
26 | };
27 |
--------------------------------------------------------------------------------
/website/src/containers/ASTOutputContainer.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux';
2 | import ASTOutput from '../components/ASTOutput';
3 | import * as selectors from '../store/selectors';
4 |
5 | function mapStateToProps(state) {
6 | return {
7 | parseResult: selectors.getParseResult(state),
8 | position: selectors.getCursor(state),
9 | };
10 | }
11 |
12 | export default connect(mapStateToProps)(ASTOutput);
13 |
--------------------------------------------------------------------------------
/website/src/containers/CodeEditorContainer.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux';
2 | import {setCode, setCursor} from '../store/actions';
3 | import Editor from '../components/Editor';
4 | import {getCode, getParser, getParseResult, getKeyMap} from '../store/selectors';
5 |
6 | function mapStateToProps(state) {
7 | return {
8 | keyMap: getKeyMap(state),
9 | value: getCode(state),
10 | mode: getParser(state).category.editorMode || getParser(state).category.id,
11 | error: (getParseResult(state) || {}).error,
12 | };
13 | }
14 |
15 | function mapDispatchToProps(dispatch) {
16 | return {
17 | onContentChange: ({value, cursor}) => {
18 | dispatch(setCode({code: value, cursor}));
19 | },
20 | onActivity: cursor => dispatch(setCursor(cursor)),
21 | };
22 | }
23 |
24 | export default connect(mapStateToProps, mapDispatchToProps)(Editor);
25 |
--------------------------------------------------------------------------------
/website/src/containers/ErrorMessageContainer.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux';
2 | import ErrorMessage from '../components/ErrorMessage';
3 | import {clearError} from '../store/actions';
4 | import {getError} from '../store/selectors';
5 |
6 | function mapStateToProps(state) {
7 | return {
8 | error: getError(state),
9 | };
10 | }
11 |
12 |
13 | function mapDispatchToProps(dispatch) {
14 | return {
15 | onWantToClose: () => dispatch(clearError()),
16 | };
17 | }
18 |
19 | export default connect(mapStateToProps, mapDispatchToProps)(ErrorMessage);
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 |
--------------------------------------------------------------------------------
/website/src/containers/PasteDropTargetContainer.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux';
2 | import PasteDropTarget from '../components/PasteDropTarget';
3 | import {setError, dropText} from '../store/actions';
4 |
5 | function mapDispatchToProps(dispatch) {
6 | return {
7 | onText: (type, event, code, categoryId) => {
8 | dispatch(dropText(code, categoryId));
9 | },
10 | onError: error => dispatch(setError(error)),
11 | };
12 | }
13 |
14 | export default connect(null, mapDispatchToProps)(PasteDropTarget);
15 |
--------------------------------------------------------------------------------
/website/src/containers/SettingsDialogContainer.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux';
2 | import {closeSettingsDialog, setParserSettings} from '../store/actions';
3 | import {showSettingsDialog, getParser, getParserSettings} from '../store/selectors';
4 | import SettingsDialog from '../components/dialogs/SettingsDialog';
5 |
6 | function mapStateToProps(state) {
7 | return {
8 | visible: showSettingsDialog(state),
9 | parser: getParser(state),
10 | parserSettings: getParserSettings(state),
11 | };
12 | }
13 |
14 | function mapDispatchToProps(dispatch) {
15 | return {
16 | onSave: (parser, newSettings) => dispatch(setParserSettings(newSettings)),
17 | onWantToClose: () => dispatch(closeSettingsDialog()),
18 | };
19 | }
20 |
21 | export default connect(mapStateToProps, mapDispatchToProps)(SettingsDialog);
22 |
--------------------------------------------------------------------------------
/website/src/containers/SettingsDrawerContainer.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux';
2 | import { expandSettingsDrawer, collapseSettingsDrawer } from '../store/actions';
3 | import { showSettingsDrawer } from '../store/selectors';
4 | import SettingsDrawer from '../components/SettingsDrawer';
5 |
6 | function mapStateToProps(state) {
7 | return {
8 | isOpen: showSettingsDrawer(state),
9 | };
10 | }
11 |
12 | function mapDispatchToProps(dispatch) {
13 | return {
14 | onWantToExpand: () => dispatch(expandSettingsDrawer()),
15 | onWantToCollapse: () => dispatch(collapseSettingsDrawer()),
16 | };
17 | }
18 |
19 | export default connect(
20 | mapStateToProps,
21 | mapDispatchToProps,
22 | )(SettingsDrawer);
23 |
--------------------------------------------------------------------------------
/website/src/containers/ShareDialogContainer.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux';
2 | import {closeShareDialog} from '../store/actions';
3 | import {showShareDialog, getRevision} from '../store/selectors';
4 | import ShareDialog from '../components/dialogs/ShareDialog';
5 |
6 | function mapStateToProps(state) {
7 | return {
8 | visible: showShareDialog(state),
9 | snippet: getRevision(state),
10 | };
11 | }
12 |
13 | function mapDispatchToProps(dispatch) {
14 | return {
15 | onWantToClose: () => dispatch(closeShareDialog()),
16 | };
17 | }
18 |
19 | export default connect(mapStateToProps, mapDispatchToProps)(ShareDialog);
20 |
--------------------------------------------------------------------------------
/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 | setKeyMap,
12 | } from '../store/actions';
13 | import Toolbar from '../components/Toolbar';
14 | import * as selectors from '../store/selectors';
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 | keyMap: selectors.getKeyMap(state),
28 | showTransformer: selectors.showTransformer(state),
29 | snippet: selectors.getRevision(state),
30 | };
31 | }
32 |
33 | function mapDispatchToProps(dispatch) {
34 | return {
35 | onParserChange: parser => {
36 | dispatch(setParser(parser));
37 | },
38 | onCategoryChange: category => {
39 | dispatch(selectCategory(category));
40 | },
41 | onParserSettingsButtonClick: () => {
42 | dispatch(openSettingsDialog());
43 | },
44 | onShareButtonClick: () => {
45 | dispatch(openShareDialog());
46 | },
47 | onTransformChange: transformer => {
48 | dispatch(transformer ? selectTransformer(transformer) : hideTransformer());
49 | },
50 | onKeyMapChange: keyMap => {
51 | dispatch(setKeyMap(keyMap))
52 | },
53 | onSave: () => dispatch(save(false)),
54 | onFork: () => dispatch(save(true)),
55 | onNew: () => {
56 | if (global.location.hash) {
57 | global.location.hash = '';
58 | } else {
59 | dispatch(reset());
60 | }
61 | },
62 | };
63 | }
64 |
65 | export default connect(mapStateToProps, mapDispatchToProps)(Toolbar);
66 |
67 |
--------------------------------------------------------------------------------
/website/src/containers/TransformerContainer.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux';
2 | import Transformer from '../components/Transformer';
3 | import {setTransformState, toggleFormatting} from '../store/actions';
4 | import * as selectors from '../store/selectors';
5 |
6 | function mapStateToProps(state) {
7 | return {
8 | transformer: selectors.getTransformer(state),
9 | // Either the transform example or the transform code from the current
10 | // revision. This is what we compare against to determine whether something
11 | // changed and we can save.
12 | defaultTransformCode: selectors.getInitialTransformCode(state),
13 | transformCode: selectors.getTransformCode(state),
14 | mode:
15 | selectors.getParser(state).category.editorMode ||
16 | selectors.getParser(state).category.id,
17 | enableFormatting: selectors.getFormattingState(state),
18 | keyMap: selectors.getKeyMap(state),
19 | transformResult: selectors.getTransformResult(state),
20 | };
21 | }
22 |
23 | function mapDispatchToProps(dispatch) {
24 | return {
25 | onContentChange: ({value, cursor}) => {
26 | dispatch(setTransformState({code: value, cursor}));
27 | },
28 | toggleFormatting: () => {
29 | dispatch(toggleFormatting());
30 | },
31 | };
32 | }
33 |
34 | export default connect(mapStateToProps, mapDispatchToProps)(Transformer);
35 |
--------------------------------------------------------------------------------
/website/src/core/ParseResult.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Describes the result of a parse process. Only exists here for documentation
3 | * purposes.
4 | */
5 | // eslint-disable-next-line no-unused-vars
6 | const ParseResult = {
7 | /**
8 | * The generated AST
9 | */
10 | ast: 'any',
11 |
12 | /**
13 | * An error object, if parsing resulted in an error
14 | */
15 | error: 'Object',
16 |
17 | /**
18 | * How long it took to generate the AST
19 | */
20 | time: 'number',
21 |
22 | treeAdapter: {
23 | /**
24 | * The type of the adapter to use, as defined in TreeAdapters.js
25 | */
26 | type: 'string',
27 | /**
28 | * Override the default options with these values
29 | */
30 | options: 'Object',
31 | },
32 | };
33 |
--------------------------------------------------------------------------------
/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/parsers/css/cssom.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'cssom/package.json';
3 |
4 | const ID = 'cssom';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/NV/CSSOM',
13 | locationProps: new Set(['__starts', '__ends']),
14 | typeProps: new Set(),
15 |
16 | loadParser(callback) {
17 | require(['cssom/lib/parse'], callback);
18 | },
19 |
20 | parse(CSSOM, code) {
21 | return CSSOM.parse(code);
22 | },
23 |
24 | getNodeName(node) {
25 | return node.constructor.name;
26 | },
27 |
28 | nodeToRange(node) {
29 | let { __starts, __ends } = node;
30 | if (__ends === undefined && node.parentRule) {
31 | ({ __ends } = node.parentRule);
32 | }
33 | if (__ends !== undefined) {
34 | return [__starts, __ends];
35 | }
36 | },
37 |
38 | opensByDefault(node, key) {
39 | return key === 'cssRules' || key === 'style';
40 | },
41 |
42 | _ignoredProperties: new Set(['parentRule', 'parentStyleSheet', '_importants']),
43 | };
44 |
--------------------------------------------------------------------------------
/website/src/parsers/css/csstree.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'css-tree/package.json';
3 |
4 | const ID = 'csstree';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/csstree/csstree',
13 | locationProps: new Set(['loc']),
14 |
15 | loadParser(callback) {
16 | require(['css-tree'], callback);
17 | },
18 |
19 | parse(csstree, code, options) {
20 | return csstree.toPlainObject(csstree.parse(code, {
21 | positions: true,
22 | ...options,
23 | }));
24 | },
25 |
26 | nodeToRange({ loc }) {
27 | if (loc && loc.start && loc.end) {
28 | return [loc.start.offset, loc.end.offset];
29 | }
30 | },
31 |
32 | opensByDefault(node, key) {
33 | return key === 'children';
34 | },
35 |
36 | getDefaultOptions() {
37 | return {
38 | context: 'stylesheet',
39 | parseValue: true,
40 | parseRulePrelude: true,
41 | parseAtrulePrelude: true,
42 | parseCustomProperty: false,
43 | };
44 | },
45 |
46 | _getSettingsConfiguration() {
47 | return {
48 | fields: [
49 | ['context', [
50 | 'stylesheet',
51 | 'atrule',
52 | 'atrulePrelude',
53 | 'mediaQueryList',
54 | 'mediaQuery',
55 | 'rule',
56 | 'selectorList',
57 | 'selector',
58 | 'block',
59 | 'declarationList',
60 | 'declaration',
61 | 'value',
62 | ]],
63 | 'parseValue',
64 | 'parseRulePrelude',
65 | 'parseAtrulePrelude',
66 | 'parseCustomProperty',
67 | ],
68 | };
69 | },
70 | };
71 |
--------------------------------------------------------------------------------
/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/css/postcss.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultCSSParserInterface';
2 | import pkg from 'postcss/package.json';
3 |
4 | const ID = 'postcss';
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(['source']),
14 |
15 | loadParser(callback) {
16 | require(['postcss/lib/parse', 'postcss-scss/lib/scss-parse', 'postcss-less/lib/', 'postcss-safe-parser'], (builtIn, scss, less, safe) => {
17 | callback({
18 | 'built-in': builtIn,
19 | scss,
20 | less: less.parse,
21 | 'safe-parser': safe,
22 | });
23 | });
24 | },
25 |
26 | parse(parsers, code, options) {
27 | return defaultParserInterface.parse.call(
28 | this,
29 | parsers[options.parser],
30 | code,
31 | );
32 | },
33 |
34 | nodeToRange({ source: range }) {
35 | if (!range || !range.end) return;
36 | return [
37 | this.getOffset(range.start),
38 | this.getOffset(range.end) + 1,
39 | ];
40 | },
41 |
42 | opensByDefault(node, key) {
43 | return key === 'nodes';
44 | },
45 |
46 | _ignoredProperties: new Set(['parent', 'input']),
47 |
48 | getDefaultOptions() {
49 | return {
50 | parser: 'built-in',
51 | };
52 | },
53 |
54 | _getSettingsConfiguration() {
55 | return {
56 | fields: [
57 | ['parser', ['built-in', 'scss', 'less', 'safe-parser']],
58 | ],
59 | };
60 | },
61 | };
62 |
--------------------------------------------------------------------------------
/website/src/parsers/css/rework.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultCSSParserInterface';
2 | import pkg from 'css/package.json';
3 |
4 | const ID = 'rework';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/reworkcss/rework',
13 | locationProps: new Set(['position']),
14 |
15 | loadParser(callback) {
16 | require(['css/lib/parse'], callback);
17 | },
18 |
19 | nodeToRange({ position: range }) {
20 | if (!range) return;
21 | return [range.start, range.end].map(pos => this.getOffset(pos));
22 | },
23 |
24 | opensByDefault(node, key) {
25 | return key === 'rules';
26 | },
27 |
28 | _ignoredProperties: new Set(['parsingErrors', 'source', 'content']),
29 | };
30 |
--------------------------------------------------------------------------------
/website/src/parsers/css/transformers/postcss/codeExample.txt:
--------------------------------------------------------------------------------
1 | const plugin = () => ({
2 | postcssPlugin: 'postcss-reverse-props',
3 | Once(root) {
4 | // Transform CSS AST here
5 | root.walkRules(rule => {
6 | // Transform each rule here
7 | rule.walkDecls(decl => {
8 | // Transform each property declaration here
9 | decl.prop = decl.prop.split('').reverse().join('');
10 | });
11 | });
12 | }
13 | });
14 |
15 | plugin.postcss = true;
16 |
17 | export default plugin;
18 |
--------------------------------------------------------------------------------
/website/src/parsers/css/transformers/postcss/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'postcss/package.json';
3 |
4 | const ID = 'postcss';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 |
12 | defaultParserID: 'postcss',
13 |
14 | loadTransformer(callback) {
15 | require(['../../../transpilers/babel', 'postcss'], (transpile, postcss) => {
16 | callback({ transpile: transpile.default, postcss });
17 | });
18 | },
19 |
20 | transform({ transpile, postcss }, transformCode, code) {
21 | transformCode = transpile( transformCode);
22 | let transform = compileModule( // eslint-disable-line no-shadow
23 | transformCode,
24 | {
25 | require(name) {
26 | switch (name) {
27 | case 'postcss': return postcss;
28 | default: throw new Error(`Cannot find module '${name}'`);
29 | }
30 | },
31 | },
32 | );
33 | return postcss([ (transform.default || transform)() ]).process(code).css;
34 | },
35 | };
36 |
--------------------------------------------------------------------------------
/website/src/parsers/css/utils/defaultCSSParserInterface.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../../utils/defaultParserInterface';
2 |
3 | export default {
4 | ...defaultParserInterface,
5 |
6 | getOffset({ line, column }) {
7 | return this.lineOffsets[line - 1] + column - 1;
8 | },
9 |
10 | parse(parseCSS, code) {
11 | this.lineOffsets = [];
12 | let index = 0;
13 | do {
14 | this.lineOffsets.push(index);
15 | } while (index = code.indexOf('\n', index) + 1); // eslint-disable-line no-cond-assign
16 | return parseCSS(code);
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/website/src/parsers/glsl/codeExample.txt:
--------------------------------------------------------------------------------
1 | // Game Of Life ( https://gl-react-cookbook.surge.sh/gol )
2 | precision highp float;
3 | varying vec2 uv;
4 | uniform float size;
5 | uniform sampler2D t; // the previous world state
6 | void main() {
7 | float prev = step(0.5, texture2D(t, uv).r);
8 | float c = 1.0 / size;
9 | float sum =
10 | step(0.5, texture2D(t, uv + vec2(-1.0, -1.0)*c).r) +
11 | step(0.5, texture2D(t, uv + vec2(-1.0, 0.0)*c).r) +
12 | step(0.5, texture2D(t, uv + vec2(-1.0, 1.0)*c).r) +
13 | step(0.5, texture2D(t, uv + vec2( 0.0, 1.0)*c).r) +
14 | step(0.5, texture2D(t, uv + vec2( 1.0, 1.0)*c).r) +
15 | step(0.5, texture2D(t, uv + vec2( 1.0, 0.0)*c).r) +
16 | step(0.5, texture2D(t, uv + vec2( 1.0, -1.0)*c).r) +
17 | step(0.5, texture2D(t, uv + vec2( 0.0, -1.0)*c).r);
18 | float next = prev==1.0 && sum >= 2.0 && sum <= 3.0 || sum == 3.0 ? 1.0 : 0.0;
19 | gl_FragColor = vec4(vec3(next), 1.0);
20 | }
21 |
--------------------------------------------------------------------------------
/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 | opensByDefault(node, key) {
61 | return key === 'children' && node.type === '(program)';
62 | },
63 | };
64 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/website/src/parsers/go/codeExample.txt:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | const TIPS = `
6 | Click on any AST node with a '+' to expand it
7 | Hovering over a node highlights the corresponding location in the source code
8 | Shift click on an AST node to expand the whole subtree
9 | `;
10 |
11 | func PrintTips() {
12 | fmt.Println(TIPS)
13 | }
14 |
--------------------------------------------------------------------------------
/website/src/parsers/go/go.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface'
2 |
3 | const ID = 'go'
4 |
5 | export default {
6 | ...defaultParserInterface,
7 |
8 | id: ID,
9 | displayName: ID,
10 | version: '1.13.4',
11 | homepage: 'https://golang.org/pkg/go/',
12 | _ignoredProperties: new Set(['_type']),
13 | locationProps: new Set(['Loc']),
14 |
15 | async loadParser(callback) {
16 | require(['astexplorer-go'], async parser => {
17 | await parser.init()
18 | callback(parser)
19 | })
20 | },
21 |
22 | parse(parser, code) {
23 | return parser.parseFile(code)
24 | },
25 |
26 | getNodeName(node) {
27 | return node._type
28 | },
29 |
30 | nodeToRange(node) {
31 | if (node.Loc) {
32 | return [node.Loc.Start, node.Loc.End].map(({ Offset }) => Offset)
33 | }
34 | },
35 | }
36 |
--------------------------------------------------------------------------------
/website/src/parsers/go/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/go/go';
2 |
3 | export const id = 'go';
4 | export const displayName = 'Go';
5 | export const mimeTypes = [];
6 | export const fileExtension = 'go';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/graphql/codeExample.txt:
--------------------------------------------------------------------------------
1 | # Paste or drop some GraphQL queries or schema
2 | # definitions here and explore the syntax tree
3 | # created by the GraphQL parser.
4 |
5 | query GetUser($userId: ID!) {
6 | user(id: $userId) {
7 | id,
8 | name,
9 | isViewerFriend,
10 | profilePicture(size: 50) {
11 | ...PictureFragment
12 | }
13 | }
14 | }
15 |
16 | fragment PictureFragment on Picture {
17 | uri,
18 | width,
19 | height
20 | }
21 |
--------------------------------------------------------------------------------
/website/src/parsers/graphql/graphql-js.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'graphql/package.json';
3 |
4 | const ID = 'graphql-js';
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 | typeProps: new Set(['kind']),
15 |
16 | loadParser(callback) {
17 | require(['graphql/language'], ({ parse }) => {
18 | callback({ parse });
19 | });
20 | },
21 |
22 | parse({ parse }, code, options) {
23 | return parse(code, options);
24 | },
25 |
26 | nodeToRange(node) {
27 | if (node.loc) {
28 | return [node.loc.start, node.loc.end];
29 | }
30 | },
31 |
32 | getNodeName(node) {
33 | return node.kind;
34 | },
35 |
36 | opensByDefault(node, key) {
37 | return key === 'definitions';
38 | },
39 |
40 | getDefaultOptions() {
41 | return {
42 | noLocation: false,
43 | noSource: false,
44 | };
45 | },
46 | };
47 |
--------------------------------------------------------------------------------
/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/graphviz/codeExample.txt:
--------------------------------------------------------------------------------
1 | /**
2 | * Copy paste in a GraphViz dot file to explore the syntax tree
3 | */
4 |
5 | digraph {
6 | rankdir=LR
7 | a [fillcolor=green]
8 | c [fillcolor=red]
9 | a -> b
10 | c -> a [dir="back"]
11 | }
12 |
--------------------------------------------------------------------------------
/website/src/parsers/graphviz/index.js:
--------------------------------------------------------------------------------
1 | export const id = 'graphviz';
2 | export const displayName = 'Graphviz';
3 | export const mimeTypes = ['text/vnd.graphviz'];
4 | export const fileExtension = 'gv';
5 |
--------------------------------------------------------------------------------
/website/src/parsers/graphviz/redot.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'redot/package.json';
3 |
4 | const ID = 'redot';
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(['position']),
14 |
15 | loadParser(callback) {
16 | require(['redot'], callback);
17 | },
18 |
19 | parse(redot, code) {
20 | return redot().parse(code);
21 | },
22 |
23 | nodeToRange({ position }) {
24 | if (position) {
25 | return [position.start.offset, position.end.offset];
26 | }
27 | },
28 |
29 | opensByDefault(node, key) {
30 | return key === 'children';
31 | },
32 | };
33 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/codeExample.txt:
--------------------------------------------------------------------------------
1 |
2 |
{{title}}
3 |
4 | {{body}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/ember-template-recast.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultHandlebarsParserInterface';
2 | import pkg from 'ember-template-recast/package.json';
3 |
4 | const ID = 'ember-template-recast';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage,
13 |
14 | loadParser(callback) {
15 | require(['ember-template-recast'], (recast) => callback(recast.parse));
16 | },
17 |
18 | opensByDefault(node, key) {
19 | return key === 'body';
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/glimmer.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultHandlebarsParserInterface';
2 | import pkg from '@glimmer/syntax/package.json';
3 |
4 | const ID = 'glimmer';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/glimmerjs/glimmer-vm',
13 |
14 | loadParser(callback) {
15 | require(['@glimmer/syntax'], (glimmer) => callback(glimmer.preprocess));
16 | },
17 |
18 | opensByDefault(node, key) {
19 | return key === 'body';
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/handlebars.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultHandlebarsParserInterface';
2 | import pkg from 'handlebars/package.json';
3 |
4 | const ID = 'handlebars';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage,
13 |
14 | loadParser(callback) {
15 | require(['handlebars'], (handlebars) => callback(handlebars.parse));
16 | },
17 |
18 | opensByDefault(node, key) {
19 | return key === 'body';
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/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/parsers/handlebars/transformers/ember-template-recast/codeExample.txt:
--------------------------------------------------------------------------------
1 | module.exports = function(env) {
2 | let b = env.syntax.builders;
3 |
4 | return {
5 | ElementNode(node) {
6 | node.tag = node.tag.split('').reverse().join('');
7 | }
8 | };
9 | };
10 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/transformers/ember-template-recast/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'ember-template-recast/package.json';
3 |
4 | const ID = 'ember-template-recast';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage || 'https://github.com/ember-template-lint/ember-template-recast',
11 |
12 | defaultParserID: 'ember-template-recast',
13 |
14 | loadTransformer(callback) {
15 | require(
16 | ['../../../transpilers/babel', 'ember-template-recast'],
17 | (transpile, recast) => callback({ transpile: transpile.default, recast }),
18 | );
19 | },
20 |
21 | transform({ transpile, recast }, transformCode, code) {
22 | transformCode = transpile(transformCode);
23 | const transformModule = compileModule(transformCode);
24 |
25 | // allow "export default" instead of "module.exports = "
26 | const transform = transformModule.__esModule ?
27 | transformModule.default :
28 | transformModule;
29 |
30 | return recast.transform(code, transform).code;
31 | },
32 | };
33 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/transformers/glimmer-compiler/codeExample.txt:
--------------------------------------------------------------------------------
1 | module.exports = function() {
2 | return {
3 | name: 'ast-transform',
4 |
5 | visitor: {
6 | ElementNode(node) {
7 | node.tag = node.tag.split('').reverse().join('');
8 | }
9 | }
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/transformers/glimmer-compiler/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from '@glimmer/compiler/package.json';
3 |
4 | const ID = 'glimmer-compiler';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage || 'https://github.com/glimmerjs/glimmer-vm',
11 |
12 | defaultParserID: 'glimmer',
13 |
14 | loadTransformer(callback) {
15 | require(
16 | ['../../../transpilers/babel', '@glimmer/compiler'],
17 | (transpile, glimmer) => callback({ transpile: transpile.default, glimmer }),
18 | );
19 | },
20 |
21 | transform({ transpile, glimmer }, transformCode, code) {
22 | transformCode = transpile(transformCode);
23 | const transformModule = compileModule(transformCode);
24 |
25 | // allow "export default" instead of "module.exports = "
26 | const transform = transformModule.__esModule ?
27 | transformModule.default :
28 | transformModule;
29 |
30 | // compile template to wireformat
31 | let result = glimmer.precompile(code, {
32 | plugins: {
33 | ast: [transform],
34 | },
35 | });
36 |
37 | // parse wireformat into JSON
38 | let json = JSON.parse(JSON.parse(result).block);
39 |
40 | // pretty print JSON
41 | return { code: json };
42 | },
43 | };
44 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/transformers/glimmer/codeExample.txt:
--------------------------------------------------------------------------------
1 | module.exports = function() {
2 | return {
3 | name: 'ast-transform',
4 |
5 | visitor: {
6 | ElementNode(node) {
7 | node.tag = node.tag.split('').reverse().join('');
8 | }
9 | }
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/transformers/glimmer/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from '@glimmer/syntax/package.json';
3 |
4 | const ID = 'glimmer';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage || 'https://github.com/glimmerjs/glimmer-vm',
11 |
12 | defaultParserID: 'glimmer',
13 |
14 | loadTransformer(callback) {
15 | require(
16 | ['../../../transpilers/babel', '@glimmer/syntax'],
17 | (transpile, glimmer) => callback({ transpile: transpile.default, glimmer }),
18 | );
19 | },
20 |
21 | transform({ transpile, glimmer }, transformCode, code) {
22 | transformCode = transpile(transformCode);
23 | const transformModule = compileModule(transformCode);
24 |
25 | // allow "export default" instead of "module.exports = "
26 | const transform = transformModule.__esModule ?
27 | transformModule.default :
28 | transformModule;
29 |
30 | let ast = glimmer.preprocess(code, {
31 | plugins: {
32 | ast: [transform],
33 | },
34 | });
35 |
36 | return glimmer.print(ast);
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/website/src/parsers/handlebars/utils/defaultHandlebarsParserInterface.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../../utils/defaultParserInterface';
2 |
3 | export default {
4 | ...defaultParserInterface,
5 |
6 | locationProps: new Set(['loc']),
7 |
8 | parse(parseHandlebars, code) {
9 | this.lineOffsets = [];
10 | let index = 0;
11 | do {
12 | this.lineOffsets.push(index);
13 | } while (index = code.indexOf('\n', index) + 1); // eslint-disable-line no-cond-assign
14 | return parseHandlebars(code);
15 | },
16 |
17 | getOffset({ line, column }) {
18 | return this.lineOffsets[line - 1] + column;
19 | },
20 |
21 | nodeToRange({ loc }) {
22 | if (!loc) return;
23 | const serializedLoc = 'toJSON' in loc ? loc.toJSON() : loc;
24 | return [serializedLoc.start, serializedLoc.end].map(pos => this.getOffset(pos));
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/website/src/parsers/html/codeExample.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
My First Heading
6 |
My first paragraph.
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/website/src/parsers/html/htmlparser2.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'htmlparser2/package.json';
3 |
4 | const ID = 'htmlparser2';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/fb55/htmlparser2',
13 | locationProps: new Set(['startIndex', 'endIndex']),
14 | typeProps: new Set(['type', 'name']),
15 |
16 | loadParser(callback) {
17 | require(['htmlparser2/lib/Parser', 'domhandler'], (Parser, {DomHandler}) => {
18 | class Handler extends DomHandler {
19 | constructor() {
20 | super({ withStartIndices: true, withEndIndices: true });
21 | }
22 |
23 | // It appears that htmlparser2 doesn't correctly process
24 | // ProcessingInstructions. Their "endIndex" isn't set properly.
25 | onprocessinginstruction(name, data) {
26 | this.parser.endIndex = this.parser.tokenizer._index;
27 | super.onprocessinginstruction(name, data);
28 | }
29 |
30 | }
31 |
32 | callback({ Parser, Handler });
33 | });
34 | },
35 |
36 | parse({ Parser: {Parser}, Handler }, code, options) {
37 | let handler = new Handler();
38 | new Parser(handler, options).end(code);
39 | return handler.root;
40 | },
41 |
42 | nodeToRange(node) {
43 | if (node.type) {
44 | return [node.startIndex, node.endIndex+1];
45 | }
46 | },
47 |
48 | opensByDefault(node, key) {
49 | return key === 'children';
50 | },
51 |
52 | getNodeName(node) {
53 | let nodeName = node.type;
54 | if (nodeName && node.name) {
55 | nodeName += `(${node.name})`;
56 | }
57 | return nodeName;
58 | },
59 |
60 | getDefaultOptions() {
61 | return {
62 | xmlMode: false,
63 | lowerCaseAttributeNames: true,
64 | lowerCaseTags: true,
65 | };
66 | },
67 |
68 | _ignoredProperties: new Set(['prev', 'next', 'parent', 'parentNode']),
69 | };
70 |
--------------------------------------------------------------------------------
/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/src/parsers/html/posthtml.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'posthtml-parser/package.json';
3 |
4 | const ID = 'posthtml-parser';
5 | const name = 'posthtml-parser';
6 |
7 | export default {
8 | ...defaultParserInterface,
9 |
10 | id: ID,
11 | displayName: name,
12 | version: pkg.version,
13 | homepage: pkg.homepage || 'https://github.com/fb55/htmlparser2',
14 |
15 | loadParser(callback) {
16 | require(['posthtml-parser'], callback);
17 | },
18 |
19 | parse(posthtmlParser, code, options) {
20 | return posthtmlParser(code, options);
21 | },
22 |
23 | opensByDefault(node, key) {
24 | return key === 'content';
25 | },
26 |
27 | getDefaultOptions() {
28 | return { lowerCaseTags: false, lowerCaseAttributeNames: false };
29 | },
30 |
31 | typeProps: new Set(['tag']),
32 | };
33 |
--------------------------------------------------------------------------------
/website/src/parsers/html/svelte.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'svelte/package.json';
3 |
4 | const ID = 'svelte';
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(['start', 'end']),
14 | typeProps: new Set(['tag']),
15 |
16 | loadParser(callback) {
17 | require(['svelte/compiler'], callback);
18 | },
19 |
20 | parse(parser, code, options) {
21 | return parser.compile(code, options).ast;
22 | },
23 |
24 | nodeToRange(node) {
25 | if (node.type || node.name) {
26 | return [node.start, node.end];
27 | }
28 | },
29 |
30 | opensByDefault(node, key) {
31 | return key === 'children';
32 | },
33 |
34 | getNodeName(node) {
35 | return node.tag;
36 | },
37 |
38 | getDefaultOptions() {
39 | return {
40 | preserveWhitespace: true,
41 | preserveComments: true,
42 | };
43 | },
44 | _ignoredProperties: new Set(['parent']),
45 | };
46 |
--------------------------------------------------------------------------------
/website/src/parsers/html/transformers/posthtml/codeExample.txt:
--------------------------------------------------------------------------------
1 | const reverse = str =>
2 | str
3 | .split("")
4 | .reverse()
5 | .join("");
6 |
7 | export default function(tree) {
8 | tree.match({ tag: "h1" }, node => {
9 |
10 | node.content[0] = reverse(node.content[0]);
11 |
12 | return node;
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/website/src/parsers/html/transformers/posthtml/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'posthtml/package.json';
3 |
4 | const ID = 'posthtml';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage || 'https://github.com/posthtml/posthtml',
11 |
12 | defaultParserID: 'posthtml-parser',
13 |
14 | loadTransformer(callback) {
15 | require(['../../../transpilers/babel', 'posthtml'], (transpile, posthtml) =>
16 | callback({ transpile: transpile.default, posthtml }));
17 | },
18 |
19 | transform({ transpile, posthtml }, transformCode, code) {
20 | // transpile with babel for es6+ support
21 | transformCode = transpile(transformCode);
22 | // compile to turn from string into a module
23 | let transform = compileModule(
24 | // eslint-disable-line no-shadow
25 | transformCode,
26 | );
27 | return posthtml()
28 | .use(transform.default || transform)
29 | .process(code, { sync: true }).html;
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/website/src/parsers/html/transformers/svelte/codeExample.txt:
--------------------------------------------------------------------------------
1 | module.exports = function() {
2 | return {
3 | name: 'svelte-transform',
4 |
5 | // transform function for entire markup
6 | markup: function(content) {
7 | return content;
8 | },
9 |
10 | // transform function for script tag
11 | script:function(content, attributes) {
12 | return content.replace(/foo/g, 'baz');
13 | },
14 |
15 | // transform function for style tag
16 | style: function(content, attributes) {
17 | return content;
18 | }
19 | };
20 | };
21 |
--------------------------------------------------------------------------------
/website/src/parsers/html/transformers/svelte/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'svelte/package.json';
3 |
4 | const ID = 'svelte';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage || 'https://sveltejs/svelte',
11 |
12 | defaultParserID: 'svelte',
13 |
14 | loadTransformer(callback) {
15 | require(
16 | ['svelte/compiler'],
17 | callback,
18 | );
19 | },
20 |
21 | transform({ preprocess }, transformCode, code) {
22 | const transform = compileModule(transformCode);
23 |
24 | // Identity functions in case of missing transforms
25 | const _markupIdentity = (content, _filename) => content;
26 | const _scriptIdentity = (content, _attributes, _filename) => content;
27 | const _styleIdentity = (content, _attributes, _filename) => content;
28 |
29 | // Check if there is a transform
30 | // If Yes, set the appropriate transform or else use identity functions
31 | const markupTransform = transform().markup || _markupIdentity;
32 | const scriptTransform = transform().script || _scriptIdentity;
33 | const styleTransform = transform().style || _styleIdentity;
34 |
35 | const result = preprocess(code, {
36 | markup:({ content, _filename}) => {
37 | return {
38 | code: markupTransform(content),
39 | };
40 | },
41 | script: ({content, attributes, _filename}) => {
42 | return {
43 | code: scriptTransform(content, attributes),
44 | };
45 | },
46 | style: ({content, attributes, _filename}) => {
47 | return {
48 | code: styleTransform(content, attributes),
49 | };
50 | },
51 | });
52 | return result;
53 | },
54 | }
55 |
--------------------------------------------------------------------------------
/website/src/parsers/icu/codeExample.txt:
--------------------------------------------------------------------------------
1 | On {takenDate, date, short} {name} took {numPhotos, plural,
2 | =0 {no photos.}
3 | =1 {one photo.}
4 | other {# photos.}
5 | }
--------------------------------------------------------------------------------
/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/icu/intl-messageformat-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'intl-messageformat-parser/package.json';
3 |
4 | const ID = 'intl-messageformat-parser';
5 | const TYPES = {};
6 |
7 | export const parserSettingsConfiguration = {
8 | fields: [
9 | 'captureLocation',
10 | 'ignoreTag',
11 | 'normalizeHashtagInPlural',
12 | 'shouldParseSkeletons',
13 | ],
14 | };
15 |
16 | const defaultOptions = {
17 | captureLocation: true,
18 | normalizeHashtagInPlural: true,
19 | };
20 |
21 | export default {
22 | ...defaultParserInterface,
23 |
24 | id: ID,
25 | displayName: ID,
26 | version: pkg.version,
27 | homepage:
28 | pkg.homepage || 'https://formatjs.io/docs/intl-messageformat-parser/',
29 | locationProps: new Set(['location']),
30 |
31 | loadParser(callback) {
32 | require(['intl-messageformat-parser'], (all) => {
33 | Object.keys(all.TYPE).forEach((k) => {
34 | TYPES[k] = all.TYPE[k];
35 | });
36 | callback(all);
37 | });
38 | },
39 |
40 | parse(parser, code, opts) {
41 | return parser.parse(code, opts);
42 | },
43 |
44 | _getSettingsConfiguration() {
45 | return parserSettingsConfiguration;
46 | },
47 |
48 | getDefaultOptions() {
49 | return defaultOptions;
50 | },
51 |
52 | getNodeName(node) {
53 | return node.type != null && TYPES[node.type];
54 | },
55 |
56 | nodeToRange({ location }) {
57 | if (location && location.start && location.end) {
58 | return [location.start.offset, location.end.offset];
59 | }
60 | },
61 | };
62 |
--------------------------------------------------------------------------------
/website/src/parsers/java/codeExample.txt:
--------------------------------------------------------------------------------
1 | package example;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class Example {
7 | private ArrayList
names;
8 |
9 | public Example() {
10 | names = new ArrayList<>();
11 | }
12 |
13 | public void addName(String name) {
14 | names.add(name);
15 | }
16 |
17 | public List getNames() {
18 | return new ArrayList<>(names);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/website/src/parsers/java/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/clike/clike';
2 |
3 | export const id = 'java';
4 | export const displayName = 'Java';
5 | export const mimeTypes = ['text/x-java-source'];
6 | export const fileExtension = 'java';
7 | export const editorMode = 'text/x-java';
8 |
--------------------------------------------------------------------------------
/website/src/parsers/java/java-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'java-parser/package.json';
3 |
4 | const ID = 'java-parser';
5 |
6 | export const parserSettingsConfiguration = {
7 | fields: [],
8 | };
9 |
10 | export default {
11 | ...defaultParserInterface,
12 |
13 | id: ID,
14 | displayName: ID,
15 | version: pkg.version,
16 | homepage:
17 | pkg.homepage ||
18 | 'https://github.com/jhipster/prettier-java/tree/master/packages/java-parser',
19 |
20 | locationProps: new Set(['location']),
21 | typeProps: new Set(['name']),
22 |
23 | loadParser(callback) {
24 | require(['java-parser'], callback);
25 | },
26 |
27 | parse(parser, code) {
28 | return parser.parse(code);
29 | },
30 |
31 | _ignoredProperties: new Set(['tokenType']),
32 |
33 | getDefaultOptions() {
34 | return {};
35 | },
36 |
37 | getNodeName({ name }) {
38 | return name;
39 | },
40 |
41 | nodeToRange({ location }) {
42 | if (!location) {
43 | return;
44 | }
45 | return [location.startOffset, location.endOffset + 1];
46 | },
47 | };
48 |
--------------------------------------------------------------------------------
/website/src/parsers/js/acorn-to-esprima.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from 'acorn-to-esprima/package.json';
3 |
4 | const ID = 'acorn-to-esprima';
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', 'start', 'end', 'range']),
14 | showInMenu: false,
15 |
16 | loadParser(callback) {
17 | require(['acorn-to-esprima', 'babel5'], (acornToEsprima, {acorn: {tokTypes}, traverse, parse}) => {
18 | callback({
19 | ...acornToEsprima,
20 | tokTypes,
21 | traverse,
22 | parse,
23 | });
24 | });
25 | },
26 |
27 | parse(parser, code) {
28 | const opts = {
29 | locations: true,
30 | ranges: true,
31 | };
32 |
33 | const comments = opts.onComment = [];
34 | const tokens = opts.onToken = [];
35 |
36 | let ast = parser.parse(code, opts);
37 |
38 | ast.tokens = parser.toTokens(tokens, parser.tokTypes, code);
39 | parser.convertComments(comments);
40 | ast.comments = comments;
41 | parser.attachComments(ast, comments, ast.tokens);
42 | parser.toAST(ast, parser.traverse);
43 |
44 | return ast;
45 | },
46 |
47 | nodeToRange(node) {
48 | if (typeof node.start !== 'undefined') {
49 | return [node.start, node.end];
50 | }
51 | },
52 |
53 | _ignoredProperties: new Set([
54 | '_paths',
55 | '_babelType',
56 | '__clone',
57 | ]),
58 | };
59 |
--------------------------------------------------------------------------------
/website/src/parsers/js/babel-eslint-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from '@babel/eslint-parser/package.json';
3 |
4 | const ID = '@babel/eslint-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', 'start', 'end', 'range']),
14 |
15 | loadParser(callback) {
16 | require(['@babel/eslint-parser'], callback);
17 | },
18 |
19 | parse(parser, code) {
20 | const opts = {
21 | sourceType: 'module',
22 | requireConfigFile: false,
23 | babelOptions: {
24 | parserOpts: {
25 | plugins: ['jsx'],
26 | },
27 | },
28 | };
29 |
30 | const ast = parser.parse(code, opts);
31 | delete ast.tokens;
32 | return ast;
33 | },
34 |
35 | nodeToRange(node) {
36 | if (typeof node.start !== 'undefined') {
37 | return [node.start, node.end];
38 | }
39 | },
40 |
41 | _ignoredProperties: new Set([
42 | '_paths',
43 | '_babelType',
44 | '__clone',
45 | ]),
46 | };
47 |
--------------------------------------------------------------------------------
/website/src/parsers/js/babel-eslint.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from 'babel-eslint/package.json';
3 |
4 | const ID = 'babel-eslint';
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', 'start', 'end', 'range']),
14 | showInMenu: false,
15 |
16 | loadParser(callback) {
17 | require(['babel-eslint'], callback);
18 | },
19 |
20 | parse(parser, code) {
21 | const opts = {
22 | sourceType: 'module',
23 | };
24 |
25 | const ast = parser.parseNoPatch(code, opts);
26 | delete ast.tokens;
27 | return ast;
28 | },
29 |
30 | nodeToRange(node) {
31 | if (typeof node.start !== 'undefined') {
32 | return [node.start, node.end];
33 | }
34 | },
35 |
36 | _ignoredProperties: new Set([
37 | '_paths',
38 | '_babelType',
39 | '__clone',
40 | ]),
41 | };
42 |
--------------------------------------------------------------------------------
/website/src/parsers/js/babel-eslint8.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from 'babel-eslint8/package.json';
3 |
4 | const ID = 'babel-eslint8';
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', 'start', 'end', 'range']),
14 | showInMenu: false,
15 |
16 | loadParser(callback) {
17 | require(['babel-eslint8'], callback);
18 | },
19 |
20 | parse(parser, code) {
21 | const opts = {
22 | sourceType: 'module',
23 | };
24 |
25 | const ast = parser.parseNoPatch(code, opts);
26 | delete ast.tokens;
27 | return ast;
28 | },
29 |
30 | nodeToRange(node) {
31 | if (typeof node.start !== 'undefined') {
32 | return [node.start, node.end];
33 | }
34 | },
35 |
36 | _ignoredProperties: new Set([
37 | '_paths',
38 | '_babelType',
39 | '__clone',
40 | ]),
41 | };
42 |
--------------------------------------------------------------------------------
/website/src/parsers/js/babel-eslint9.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from 'babel-eslint9/package.json';
3 |
4 | const ID = 'babel-eslint9';
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', 'start', 'end', 'range']),
14 |
15 | loadParser(callback) {
16 | require(['babel-eslint9'], callback);
17 | },
18 |
19 | parse(parser, code) {
20 | const opts = {
21 | sourceType: 'module',
22 | };
23 |
24 | const ast = parser.parseNoPatch(code, opts);
25 | delete ast.tokens;
26 | return ast;
27 | },
28 |
29 | nodeToRange(node) {
30 | if (typeof node.start !== 'undefined') {
31 | return [node.start, node.end];
32 | }
33 | },
34 |
35 | _ignoredProperties: new Set([
36 | '_paths',
37 | '_babelType',
38 | '__clone',
39 | ]),
40 | };
41 |
--------------------------------------------------------------------------------
/website/src/parsers/js/codeExample.txt:
--------------------------------------------------------------------------------
1 | /**
2 | * Paste or drop some JavaScript here and explore
3 | * the syntax tree created by chosen parser.
4 | * You can use all the cool new features from ES6
5 | * and even more. Enjoy!
6 | */
7 |
8 | let tips = [
9 | "Click on any AST node with a '+' to expand it",
10 |
11 | "Hovering over a node highlights the \
12 | corresponding location in the source code",
13 |
14 | "Shift click on an AST node to expand the whole subtree"
15 | ];
16 |
17 | function printTips() {
18 | tips.forEach((tip, i) => console.log(`Tip ${i}:` + tip));
19 | }
20 |
--------------------------------------------------------------------------------
/website/src/parsers/js/esformatter.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from 'esformatter-parser/package.json';
3 |
4 | const ID = 'esformatter-parser';
5 | const name = 'esformatter';
6 |
7 | export default {
8 | ...defaultParserInterface,
9 |
10 | id: ID,
11 | displayName: name,
12 | version: pkg.version,
13 | homepage: pkg.homepage,
14 | locationProps: new Set(['loc', 'start', 'end', 'range']),
15 |
16 | loadParser(callback) {
17 | require(['esformatter-parser'], (parser) => {
18 | callback(parser);
19 | });
20 | },
21 |
22 | parse(parser, code) {
23 | return parser.parse(code);
24 | },
25 |
26 | *forEachProperty(node) {
27 | if (node && typeof node === 'object') {
28 | for (let prop in node) {
29 | if (this._ignoredProperties.has(prop)) {
30 | continue;
31 | }
32 |
33 | let value = node[prop];
34 |
35 | if (node.type !== 'Program' && prop === 'parent') {
36 | value = '[Circular]';
37 | }
38 |
39 | yield {
40 | value,
41 | key: prop,
42 | computed: false,
43 | }
44 | }
45 | }
46 | },
47 |
48 | _ignoredProperties: new Set([
49 | '_paths',
50 | '_babelType',
51 | '__clone',
52 | // hide some extra properties to reduce noise
53 | 'comments',
54 | 'directives',
55 | 'extra',
56 | 'leadingComments',
57 | 'root',
58 | 'sourceType',
59 | 'tokens',
60 | 'trailingComments',
61 | ]),
62 | };
63 |
--------------------------------------------------------------------------------
/website/src/parsers/js/esprima.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from 'esprima/package.json';
3 |
4 | const ID = 'esprima';
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(['range', 'loc']),
14 |
15 | loadParser(callback) {
16 | require(['esprima'], callback);
17 | },
18 |
19 | parse(esprima, code, options) {
20 | return esprima.parse(code, options);
21 | },
22 |
23 | *forEachProperty(node) {
24 | if (node && typeof node === 'object') {
25 | for (let prop in node) {
26 | if (typeof node[prop] === 'function') {
27 | continue;
28 | }
29 | yield {
30 | value: node[prop],
31 | key: prop,
32 | computed: false,
33 | };
34 | }
35 | }
36 | },
37 |
38 | getDefaultOptions() {
39 | return {
40 | sourceType: 'module',
41 | loc: false,
42 | range: true,
43 | tokens: false,
44 | comment: false,
45 | attachComment: false,
46 | tolerant: false,
47 | jsx: true,
48 | };
49 | },
50 |
51 | _getSettingsConfiguration() {
52 | return {
53 | fields: [
54 | ['sourceType', ['script', 'module']],
55 | 'range',
56 | 'loc',
57 | 'attachComment',
58 | 'comment',
59 | 'tokens',
60 | 'tolerant',
61 | 'jsx',
62 | ],
63 | required: new Set(['range']),
64 | };
65 | },
66 |
67 | };
68 |
--------------------------------------------------------------------------------
/website/src/parsers/js/flow.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from 'flow-parser/package.json';
3 |
4 | const ID = 'flow';
5 | export const defaultOptions = {
6 | enums: false,
7 | esproposal_class_instance_fields: true,
8 | esproposal_class_static_fields: true,
9 | esproposal_decorators: true,
10 | esproposal_export_star_as: true,
11 | esproposal_optional_chaining: true,
12 | esproposal_nullish_coalescing: true,
13 | tokens: false,
14 | types: true,
15 | };
16 | export const parserSettingsConfiguration = {
17 | fields: [
18 | 'enums',
19 | 'esproposal_class_instance_fields',
20 | 'esproposal_class_static_fields',
21 | 'esproposal_decorators',
22 | 'esproposal_export_star_as',
23 | 'esproposal_optional_chaining',
24 | 'esproposal_nullish_coalescing',
25 | 'tokens',
26 | 'types',
27 | ],
28 | };
29 |
30 | export default {
31 | ...defaultParserInterface,
32 |
33 | id: ID,
34 | displayName: ID,
35 | version: pkg.version,
36 | homepage: pkg.homepage || 'https://flow.org/',
37 | locationProps: new Set(['range', 'loc']),
38 |
39 | loadParser(callback) {
40 | require(['flow-parser'], callback);
41 | },
42 |
43 | parse(flowParser, code, options) {
44 | return flowParser.parse(code, options);
45 | },
46 |
47 | getDefaultOptions() {
48 | return defaultOptions;
49 | },
50 |
51 | _getSettingsConfiguration() {
52 | return parserSettingsConfiguration;
53 | },
54 | };
55 |
--------------------------------------------------------------------------------
/website/src/parsers/js/hermes.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | // NOTE: We load the hermes-parser package in a worker and not directly, because
3 | // it violates the typical limit on the size of a WebAssembly module that can be
4 | // compiled synchronously on the main thread.
5 | import HermesWorkerClient from './hermes/HermesWorkerClient';
6 | import pkg from 'hermes-parser/package.json';
7 |
8 | export const defaultOptions = {
9 | sourceType: 'unambiguous',
10 | flow: 'detect',
11 | allowReturnOutsideFunction: false,
12 | babel: false,
13 | tokens: false,
14 | };
15 |
16 | export const parserSettingsConfiguration = {
17 | fields: [
18 | ['sourceType', ['unambiguous', 'module', 'script']],
19 | ['flow', ['detect', 'all']],
20 | 'allowReturnOutsideFunction',
21 | 'babel',
22 | 'tokens',
23 | ],
24 | };
25 |
26 | export default {
27 | ...defaultParserInterface,
28 |
29 | id: 'hermes',
30 | displayName: pkg.name,
31 | version: pkg.version,
32 | homepage: pkg.homepage || 'https://hermesengine.dev/',
33 | locationProps: new Set(['range', 'loc', 'start', 'end']),
34 |
35 | loadParser(callback) {
36 | callback(new HermesWorkerClient());
37 | },
38 |
39 | async parse(hermes, code, options) {
40 | return await hermes.parse(code, options);
41 | },
42 |
43 | nodeToRange(node) {
44 | // For `babel: true` mode
45 | if (typeof node.start !== 'undefined') {
46 | return [node.start, node.end];
47 | }
48 | // For `babel: false` mode
49 | return node.range;
50 | },
51 |
52 | getDefaultOptions() {
53 | return defaultOptions;
54 | },
55 |
56 | _getSettingsConfiguration() {
57 | return parserSettingsConfiguration;
58 | },
59 | };
60 |
--------------------------------------------------------------------------------
/website/src/parsers/js/hermes/HermesWorkerClient.js:
--------------------------------------------------------------------------------
1 | // Some ESLint rules don't understand the Webpack loader syntax.
2 | // eslint-disable-next-line require-in-package/require-in-package, import/default
3 | import HermesWorker from 'worker-loader!./hermes-worker.js';
4 |
5 | // A Promise-based client for making requests to hermes-worker.js.
6 | export default class HermesWorkerClient {
7 | constructor() {
8 | this._nextRequestId = 0;
9 | this._requests = new Map();
10 | this._worker = new HermesWorker();
11 | this._worker.onmessage = this._handleMessage.bind(this);
12 | }
13 |
14 | _handleMessage(e) {
15 | const {type, action, value, requestId} = e.data;
16 | const request = this._requests.get(requestId);
17 | if (!request) {
18 | throw new Error(
19 | `Received a response for a nonexistent '${type}' request ID: ${requestId}`,
20 | );
21 | }
22 | this._requests.delete(requestId);
23 | switch (action) {
24 | case 'resolve':
25 | request.resolve(value);
26 | break;
27 | case 'reject':
28 | // The worker sends errors as plain objects to work around the
29 | // limitations of the structured clone algorithm.
30 | request.reject(Object.assign(new Error(), value));
31 | break;
32 | }
33 | }
34 |
35 | _request(type, args) {
36 | return new Promise((resolve, reject) => {
37 | const requestId = this._nextRequestId++;
38 | this._requests.set(requestId, {resolve, reject});
39 | this._worker.postMessage({type, args, requestId});
40 | });
41 | }
42 |
43 | parse(...args) {
44 | return this._request('parse', args);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/website/src/parsers/js/hermes/hermes-worker.js:
--------------------------------------------------------------------------------
1 | /* eslint-env worker */
2 |
3 | // A Web Worker that wraps methods from the hermes-parser package behind a
4 | // minimal request/response protocol.
5 |
6 | import * as hermesParser from 'hermes-parser';
7 |
8 | const handlers = {
9 | parse(code, options) {
10 | return hermesParser.parse(code, options);
11 | },
12 | };
13 |
14 | onmessage = async function(e) {
15 | const {type, requestId, args = []} = e.data;
16 | let handler = () => {
17 | throw new Error('No handler in Hermes worker for message type: ' + type);
18 | };
19 | if (Object.hasOwnProperty.call(handlers, type)) {
20 | handler = handlers[type];
21 | }
22 | let value;
23 | try {
24 | value = handler(...args);
25 | } catch (e) {
26 | postMessage({
27 | type,
28 | requestId,
29 | action: 'reject',
30 | // Errors don't survive the structured clone algorithm very well across
31 | // browsers - they're either not allowed or lose some of their properties.
32 | // Send a plain-object copy to be reconstituted by the client.
33 | value: {name: e.name, stack: e.stack, message: e.message, ...e},
34 | });
35 | return;
36 | }
37 | postMessage({type, requestId, action: 'resolve', value});
38 | };
39 |
--------------------------------------------------------------------------------
/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/js/shift.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'shift-parser/package.json';
3 |
4 | const ID = 'shift';
5 |
6 | let lastParsedLocations;
7 |
8 | export default {
9 | ...defaultParserInterface,
10 |
11 | id: ID,
12 | displayName: ID,
13 | version: pkg.version,
14 | homepage: pkg.homepage,
15 | locationProps: new Set(['loc']),
16 |
17 | loadParser(callback) {
18 | require(['shift-parser'], callback);
19 | },
20 |
21 | parse(shift, code, options) {
22 | const parseMethod = options.sourceType === 'module' ?
23 | 'parseModuleWithLocation' :
24 | 'parseScriptWithLocation';
25 | const { tree, locations } = shift[parseMethod](code, options);
26 | lastParsedLocations = locations;
27 | return tree;
28 | },
29 |
30 | nodeToRange(node) {
31 | if (lastParsedLocations && lastParsedLocations.has(node)) {
32 | let loc = lastParsedLocations.get(node);
33 | return [loc.start.offset, loc.end.offset];
34 | }
35 | },
36 |
37 | opensByDefault(node, key) {
38 | return (
39 | key === 'items' ||
40 | key === 'declaration' ||
41 | key === 'declarators' ||
42 | key === 'statements' ||
43 | key === 'expression' ||
44 | key === 'body'
45 | );
46 | },
47 |
48 | getDefaultOptions() {
49 | return {
50 | earlyErrors: false,
51 | sourceType: 'module',
52 | };
53 | },
54 |
55 | _getSettingsConfiguration() {
56 | return {
57 | fields: [
58 | ['sourceType', ['script', 'module']],
59 | 'earlyErrors',
60 | ],
61 | };
62 | },
63 |
64 | };
65 |
--------------------------------------------------------------------------------
/website/src/parsers/js/tenko.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from 'tenko/package.json';
3 |
4 | const ID = 'tenko';
5 | export const defaultOptions = {
6 | goalMode: 'script',
7 | webCompat: true,
8 | strictMode: false,
9 | targetEsVersion: Infinity,
10 | ranges: true,
11 |
12 | babelCompat: false,
13 | acornCompat: false,
14 |
15 | exposeScopes: false,
16 | astUids: false,
17 | allowGlobalReturn: false,
18 | fullErrorContext: false,
19 | templateNewlineNormalization: true,
20 | };
21 |
22 | export const parserSettingsConfiguration = {
23 | fields: [
24 | ['goalMode', ['script', 'module']],
25 | 'allowGlobalReturn',
26 | 'strictMode',
27 | 'webCompat',
28 | ['targetEsVersion', [Infinity, 6, 7, 8, 9, 10, 11]],
29 | 'exposeScopes',
30 | 'astUids',
31 | 'fullErrorContext',
32 | 'templateNewlineNormalization',
33 | 'ranges',
34 | 'acornCompat',
35 | 'babelCompat',
36 | ],
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(['loc']),
47 |
48 | loadParser(callback) {
49 | require(['tenko'], callback);
50 | },
51 |
52 | parse(tenko, code, options) {
53 | return tenko.Tenko(code, {...options});
54 | },
55 |
56 | getNodeName(node) {
57 | return node.type;
58 | },
59 |
60 | nodeToRange(node) {
61 | if (node.loc && node.loc.range) {
62 | return [node.loc.range.start, node.loc.range.end];
63 | }
64 | },
65 |
66 | getDefaultOptions() {
67 | return defaultOptions;
68 | },
69 |
70 | _getSettingsConfiguration() {
71 | return parserSettingsConfiguration;
72 | },
73 | };
74 |
--------------------------------------------------------------------------------
/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/js/transformers/babel/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'babel5/package.json';
3 |
4 | const ID = 'babel';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 | showInMenu: false,
12 |
13 | defaultParserID: 'babylon',
14 |
15 | loadTransformer(callback) {
16 | require(
17 | ['../../../transpilers/babel', 'babel5'],
18 | (transpile, babel) => callback({ transpile: transpile.default, babel: babel }),
19 | );
20 | },
21 |
22 | transform({ transpile, babel }, transformCode, code) {
23 | transformCode = transpile(transformCode);
24 | let transform = compileModule( // eslint-disable-line no-shadow
25 | transformCode,
26 | );
27 |
28 | return babel.transform(code, {
29 | whitelist: [],
30 | plugins: [transform.default || transform],
31 | sourceMaps: true,
32 | });
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/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/babel6/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'babel6/package.json';
3 |
4 | const ID = 'babelv6';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 | showInMenu: false,
12 |
13 | defaultParserID: 'babylon6',
14 |
15 | loadTransformer(callback) {
16 | require([
17 | '../../../transpilers/babel',
18 | 'babel6',
19 | 'recast',
20 | ], (transpile, babel, recast) => callback({ transpile: transpile.default, babel, recast }));
21 | },
22 |
23 | transform({ transpile, babel, recast }, transformCode, code) {
24 | transformCode = transpile(transformCode);
25 | let transform = compileModule( // eslint-disable-line no-shadow
26 | transformCode,
27 | );
28 |
29 | return babel.transform(code, {
30 | parserOpts: {
31 | parser: recast.parse,
32 | plugins: [
33 | 'asyncGenerators',
34 | 'classConstructorCall',
35 | 'classProperties',
36 | 'decorators',
37 | 'doExpressions',
38 | 'exportExtensions',
39 | 'flow',
40 | 'functionSent',
41 | 'functionBind',
42 | 'jsx',
43 | 'objectRestSpread',
44 | 'dynamicImport',
45 | ],
46 | },
47 | generatorOpts: {
48 | generator: recast.print,
49 | },
50 | plugins: [(transform.default || transform)(babel)],
51 | sourceMaps: true,
52 | });
53 | },
54 | };
55 |
--------------------------------------------------------------------------------
/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/src/parsers/js/transformers/babel7/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'babel7/package.json';
3 |
4 | const ID = 'babelv7';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 |
12 | defaultParserID: 'babylon7',
13 |
14 | loadTransformer(callback) {
15 | require([
16 | '../../../transpilers/babel',
17 | 'babel7',
18 | 'recast',
19 | ], (transpile, babel, recast) => callback({ transpile: transpile.default, babel, recast }));
20 | },
21 |
22 | transform({ transpile, babel, recast }, transformCode, code) {
23 | transformCode = transpile(transformCode);
24 | let transform = compileModule( // eslint-disable-line no-shadow
25 | transformCode,
26 | );
27 |
28 | return babel.transformAsync(code, {
29 | parserOpts: {
30 | parser: recast.parse,
31 | plugins: [
32 | 'asyncGenerators',
33 | 'bigInt',
34 | 'classPrivateMethods',
35 | 'classPrivateProperties',
36 | 'classProperties',
37 | ['decorators', {decoratorsBeforeExport: false}],
38 | 'doExpressions',
39 | 'dynamicImport',
40 | 'exportDefaultFrom',
41 | 'exportNamespaceFrom',
42 | 'flow',
43 | 'flowComments',
44 | 'functionBind',
45 | 'functionSent',
46 | 'importMeta',
47 | 'jsx',
48 | 'logicalAssignment',
49 | 'nullishCoalescingOperator',
50 | 'numericSeparator',
51 | 'objectRestSpread',
52 | 'optionalCatchBinding',
53 | 'optionalChaining',
54 | ['pipelineOperator', {proposal: 'minimal'}],
55 | 'throwExpressions',
56 | ],
57 | },
58 | retainLines: false,
59 | generatorOpts: {
60 | generator: recast.print,
61 | },
62 | plugins: [(transform.default || transform)(babel)],
63 | sourceMaps: true,
64 | });
65 | },
66 | };
67 |
--------------------------------------------------------------------------------
/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/eslint1/index.js:
--------------------------------------------------------------------------------
1 | import pkg from 'eslint1/package.json';
2 |
3 | const ID = 'eslint-v1';
4 | const name = 'ESLint v1'
5 |
6 | export default {
7 | id: ID,
8 | displayName: name,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 | showInMenu: false,
12 |
13 | defaultParserID: 'acorn-to-esprima',
14 |
15 | loadTransformer(callback) {
16 | require(
17 | [
18 | // Explicitly require just the stuff we care about to avoid loading
19 | // RuleTester and CLIEngine, which are unnecessary and bloat out the
20 | // package size.
21 | 'eslint1/lib/eslint',
22 | 'eslint1/lib/util/source-code',
23 | 'eslint1/lib/rules',
24 | '../../utils/eslintUtils',
25 | ],
26 | (eslint, sourceCode, rules, utils) => callback({eslint, sourceCode, rules, utils}),
27 | );
28 | },
29 |
30 | transform({ eslint, sourceCode, rules, utils }, transformCode, code) {
31 | utils.defineRule(rules, transformCode);
32 | return utils.runRule(code, eslint, sourceCode);
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/eslint2/index.js:
--------------------------------------------------------------------------------
1 | import pkg from 'eslint2/package.json';
2 |
3 | const ID = 'eslint-v2';
4 | const name = 'ESLint v2'
5 |
6 | export default {
7 | id: ID,
8 | displayName: name,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 | showInMenu: false,
12 |
13 | defaultParserID: 'babel-eslint',
14 |
15 | loadTransformer(callback) {
16 | require(
17 | [
18 | // Explicitly require just the stuff we care about to avoid loading
19 | // RuleTester and CLIEngine, which are unnecessary and bloat out the
20 | // package size.
21 | 'eslint2/lib/eslint',
22 | 'eslint2/lib/util/source-code',
23 | 'eslint2/lib/rules',
24 | '../../utils/eslintUtils',
25 | ],
26 | (eslint, sourceCode, rules, utils) => callback({eslint, sourceCode, rules, utils}),
27 | );
28 | },
29 |
30 | transform({ eslint, rules, sourceCode, utils }, transformCode, code) {
31 | utils.defineRule(rules, transformCode);
32 | return utils.runRule(code, eslint, sourceCode);
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/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/eslint3/index.js:
--------------------------------------------------------------------------------
1 | import pkg from 'eslint3/package.json';
2 |
3 | const ID = 'eslint-v3';
4 | const name = 'ESLint v3'
5 |
6 | export default {
7 | id: ID,
8 | displayName: name,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 | showInMenu: false,
12 |
13 | defaultParserID: 'babel-eslint',
14 |
15 | loadTransformer(callback) {
16 | require(
17 | [
18 | // Explicitly require just the stuff we care about to avoid loading
19 | // RuleTester and CLIEngine, which are unnecessary and bloat out the
20 | // package size.
21 | 'eslint3/lib/eslint',
22 | 'eslint3/lib/util/source-code',
23 | 'eslint3/lib/rules',
24 | '../../utils/eslintUtils',
25 | ],
26 | (eslint, sourceCode, rules, utils) => callback({eslint, sourceCode, rules, utils}),
27 | );
28 | },
29 |
30 | transform({ eslint, rules, sourceCode, utils }, transformCode, code) {
31 | utils.defineRule(rules, transformCode);
32 | return utils.runRule(code, eslint, sourceCode);
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/eslint4/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default function(context) {
2 | return {
3 | TemplateLiteral(node) {
4 | context.report({
5 | node,
6 | message: 'Do not use template literals',
7 |
8 | fix(fixer) {
9 | if (node.expressions.length) {
10 | // Can't auto-fix template literal with expressions
11 | return;
12 | }
13 |
14 | return [
15 | fixer.replaceTextRange([node.start, node.start + 1], '"'),
16 | fixer.replaceTextRange([node.end - 1, node.end], '"'),
17 | ];
18 | },
19 | });
20 | }
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/eslint4/index.js:
--------------------------------------------------------------------------------
1 | import pkg from 'eslint4/package.json';
2 |
3 | const ID = 'eslint-v4';
4 | const name = 'ESLint v4';
5 |
6 | export default {
7 | id: ID,
8 | displayName: name,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 |
12 | defaultParserID: 'babel-eslint',
13 |
14 | loadTransformer(callback) {
15 | require(
16 | [
17 | 'eslint4/lib/linter',
18 | 'eslint4/lib/util/source-code',
19 | '../../utils/eslint4Utils',
20 | ],
21 | (Linter, sourceCode, utils) => callback({eslint: new Linter(), sourceCode, utils}),
22 | );
23 | },
24 |
25 | transform({ eslint, sourceCode, utils }, transformCode, code) {
26 | utils.defineRule(eslint, transformCode);
27 | return utils.runRule(code, eslint, sourceCode);
28 | },
29 | };
30 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/eslint8/codeExample.txt:
--------------------------------------------------------------------------------
1 | export const meta = {
2 | type: 'problem',
3 | hasSuggestions: true,
4 | fixable: true,
5 | };
6 |
7 | export function create(context) {
8 | return {
9 | TemplateLiteral(node) {
10 | context.report({
11 | node,
12 | message: 'Do not use template literals',
13 |
14 | fix(fixer) {
15 | if (node.expressions.length) {
16 | // Can't auto-fix template literal with expressions
17 | return;
18 | }
19 |
20 | return [
21 | fixer.replaceTextRange([node.start, node.start + 1], '"'),
22 | fixer.replaceTextRange([node.end - 1, node.end], '"'),
23 | ];
24 | },
25 | });
26 | }
27 | };
28 | };
29 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/eslint8/index.js:
--------------------------------------------------------------------------------
1 | import pkg from 'eslint8/package.json';
2 |
3 | const ID = 'eslint-v8';
4 | const name = 'ESLint v8';
5 |
6 | export default {
7 | id: ID,
8 | displayName: name,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 |
12 | defaultParserID: 'babel-eslint',
13 |
14 | loadTransformer(callback) {
15 | require([
16 | 'eslint8/lib/linter',
17 | 'eslint8/lib/source-code',
18 | '../../utils/eslint4Utils',
19 | ], (Linter, sourceCode, utils) =>
20 | callback({ eslint: new Linter.Linter(), sourceCode, utils }));
21 | },
22 |
23 | transform({ eslint, sourceCode, utils }, transformCode, code) {
24 | utils.defineRule(eslint, transformCode);
25 | return utils.runRule(code, eslint, sourceCode);
26 | },
27 | };
28 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/jscodeshift/codeExample.txt:
--------------------------------------------------------------------------------
1 | // jscodeshift can take a parser, like "babel", "babylon", "flow", "ts", or "tsx"
2 | // Read more: https://github.com/facebook/jscodeshift#parser
3 | export const parser = '{{parser}}'
4 |
5 | // Press ctrl+space for code completion
6 | export default function transformer(file, api) {
7 | const j = api.jscodeshift;
8 |
9 | return j(file.source)
10 | .find(j.Identifier)
11 | .forEach(path => {
12 | j(path).replaceWith(
13 | j.identifier(path.node.name.split('').reverse().join(''))
14 | );
15 | })
16 | .toSource();
17 | }
18 |
--------------------------------------------------------------------------------
/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": "babel"
12 | }
13 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/prettier/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'prettier/package.json';
3 |
4 | const ID = 'prettier';
5 | const name = 'prettier';
6 |
7 | export default {
8 | id: ID,
9 | displayName: name,
10 | version: pkg.version,
11 | homepage: pkg.homepage,
12 |
13 | defaultParserID: 'babylon7',
14 |
15 | loadTransformer(callback) {
16 | require(
17 | ['../../../transpilers/babel', 'prettier/standalone', 'prettier/parser-babel'],
18 | (transpile, prettier, babel) => callback({ transpile: transpile.default, prettier, babel }),
19 | );
20 | },
21 |
22 | transform({ transpile, prettier, babel }, transformCode, code) {
23 | transformCode = transpile(transformCode);
24 | const options = compileModule(transformCode);
25 | return prettier.format(
26 | code,
27 | Object.assign({plugins: [babel]}, options.default || options),
28 | );
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/recast/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default function transformer(code, { recast, parsers }) {
2 | const ast = recast.parse(code, { parser: parsers.esprima });
3 |
4 | recast.visit(ast, {
5 | visitIdentifier(path) {
6 | path.node.name = path.node.name.split("").reverse().join("");
7 | return false;
8 | }
9 | });
10 |
11 | return recast.print(ast).code;
12 | }
13 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/recast/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'recast/package.json';
3 |
4 | const ID = 'recast';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage || 'https://github.com/benjamn/recast',
11 |
12 | defaultParserID: 'recast',
13 |
14 | loadTransformer(callback) {
15 | require(
16 | [
17 | '../../../transpilers/babel',
18 | 'recast',
19 | 'recast/parsers/acorn',
20 | 'recast/parsers/babel',
21 | 'recast/parsers/babylon',
22 | 'recast/parsers/esprima',
23 | 'recast/parsers/flow',
24 | 'recast/parsers/typescript',
25 | ],
26 | (transpile, recast, acorn, babel, babylon, esprima, flow, typescript) => {
27 | callback({
28 | transpile: transpile.default,
29 | recast,
30 | parsers: {
31 | acorn,
32 | babel,
33 | babylon,
34 | esprima,
35 | flow,
36 | typescript,
37 | },
38 | });
39 | },
40 | );
41 | },
42 |
43 | transform(
44 | { transpile, recast, parsers },
45 | transformCode,
46 | code,
47 | ) {
48 | transformCode = transpile(transformCode);
49 | const transformModule = compileModule( // eslint-disable-line no-shadow
50 | transformCode,
51 | );
52 | const transform = transformModule.__esModule ?
53 | transformModule.default :
54 | transformModule;
55 |
56 | const result = transform(
57 | code,
58 | {
59 | recast,
60 | parsers,
61 | },
62 | );
63 | if (typeof result !== 'string') {
64 | throw new Error(
65 | 'Transformers must either return undefined, null or a string, not ' +
66 | `"${typeof result}".`,
67 | );
68 | }
69 | return result;
70 | },
71 | };
72 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/tslint/codeExample.txt:
--------------------------------------------------------------------------------
1 | export class Rule extends Lint.Rules.AbstractRule {
2 | public static FAILURE_STRING = "Do not use template literals";
3 |
4 | public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
5 | return this.applyWithWalker(new NoTemplateExpressionWalker(sourceFile, this.getOptions()));
6 | }
7 | }
8 |
9 | // The walker takes care of all the work.
10 | class NoTemplateExpressionWalker extends Lint.RuleWalker {
11 | public visitTemplateExpression(node: ts.TemplateExpression) {
12 | // create a failure at the current position
13 | this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
14 |
15 | // call the base version of this visitor to actually parse this node
16 | super.visitTemplateExpression(node);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/tslint/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'tslint/package.json';
3 |
4 | const ID = 'tslint';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 |
12 | defaultParserID: 'typescript',
13 |
14 | loadTransformer(callback) {
15 | require([
16 | '../../../transpilers/typescript',
17 | 'tslint/lib/index',
18 | 'typescript',
19 | ],
20 | (
21 | transpile,
22 | tslint,
23 | typescript,
24 | ) => callback({transpile: transpile.default, tslint, typescript}));
25 | },
26 |
27 | transform({ transpile, tslint, typescript }, transformCode, code) {
28 | transformCode = transpile(transformCode);
29 | let transform = compileModule( // eslint-disable-line no-shadow
30 | transformCode,
31 | {
32 | Lint: tslint,
33 | ts: typescript,
34 | },
35 | );
36 |
37 | let linter = new tslint.Linter({});
38 | let rule = new transform.Rule({});
39 | let sourceFile = linter.getSourceFile('astExplorer.ts', code);
40 | let ruleFailures = linter.applyRule(rule, sourceFile);
41 |
42 | return formatResults(ruleFailures);
43 | },
44 | };
45 |
46 | function formatResults(results) {
47 | return results.length === 0
48 | ? 'Lint rule not fired.'
49 | : results.map(formatResult).join('').trim();
50 | }
51 |
52 | function formatResult(result) {
53 | let { line, character } = result.startPosition.lineAndCharacter;
54 | let rawLine = result.rawLines.split('\n')[line];
55 | let pointer = '-'.repeat(character) + '^';
56 | return `
57 | // ${result.failure} (at ${line+1}:${character+1})
58 | ${rawLine}
59 | // ${pointer}
60 | `;
61 | }
62 |
--------------------------------------------------------------------------------
/website/src/parsers/js/transformers/typescript/codeExample.txt:
--------------------------------------------------------------------------------
1 | /**
2 | * The transformer signature is based on https://github.com/cevek/ttypescript#program
3 | */
4 | export default function (program) {
5 | const checker = program.getTypeChecker();
6 | return (context) => {
7 | return (sourceFile) => {
8 | const visitor = (node) => {
9 | // This branch evaluates '2 + 2' like expressions and replaces the node with the result (in this case '4')
10 | if (ts.isBinaryExpression(node)) {
11 | if (ts.isNumericLiteral(node.left) && ts.isNumericLiteral(node.right)) {
12 | // We could parse `node.text` as a number, or we can use the typechecker to get type info for nodes
13 | const lhs = checker.getTypeAtLocation(node.left);
14 | const rhs = checker.getTypeAtLocation(node.right);
15 |
16 | switch (node.operatorToken.kind) {
17 | case ts.SyntaxKind.PlusToken:
18 | return context.factory.createNumericLiteral(lhs.value + rhs.value);
19 | }
20 | }
21 | }
22 | //
23 | if (ts.isIdentifier(node) && node.text === 'printTips' || node.text === 'tips') {
24 | return context.factory.createIdentifier(node.text.split('').reverse().join(''));
25 | }
26 | return ts.visitEachChild(node, visitor, context);
27 | };
28 | return ts.visitNode(sourceFile, visitor);
29 | };
30 | };
31 | };
32 |
33 |
--------------------------------------------------------------------------------
/website/src/parsers/js/typescript-eslint-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from './utils/defaultESTreeParserInterface';
2 | import pkg from '@typescript-eslint/parser/package.json';
3 |
4 | const ID = '@typescript-eslint/parser';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://typescript-eslint.io/',
13 | locationProps: new Set(['loc', 'start', 'end', 'range']),
14 |
15 | loadParser(callback) {
16 | require(['@typescript-eslint/parser'], callback);
17 | },
18 |
19 | parse(parser, code, options) {
20 | return parser.parse(code, options);
21 | },
22 |
23 | getDefaultOptions() {
24 | return {
25 | range: true,
26 | loc: false,
27 | tokens: false,
28 | comment: false,
29 | useJSXTextNode: false,
30 | ecmaVersion: 6,
31 | sourceType: 'module',
32 |
33 | ecmaFeatures: {
34 | jsx: true,
35 | },
36 | };
37 | },
38 |
39 | _getSettingsConfiguration(defaultOptions) {
40 | return {
41 | fields: [
42 | ['ecmaVersion', [3, 5, 6, 7, 8, 9], value => Number(value)],
43 | ['sourceType', ['script', 'module']],
44 | 'range',
45 | 'loc',
46 | 'tokens',
47 | 'comment',
48 | 'useJSXTextNode',
49 | {
50 | key: 'ecmaFeatures',
51 | title: 'ecmaFeatures',
52 | fields: Object.keys(defaultOptions.ecmaFeatures),
53 | settings:
54 | settings => settings.ecmaFeatures || {...defaultOptions.ecmaFeatures},
55 | },
56 | ],
57 | required: new Set(['range']),
58 | };
59 | },
60 | };
61 |
--------------------------------------------------------------------------------
/website/src/parsers/js/uglify.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from '../../../node_modules/uglify-es/package.json';
3 | import compileModule from '../utils/compileModule';
4 |
5 | const ID = 'uglify-js';
6 |
7 | export default {
8 | ...defaultParserInterface,
9 |
10 | id: ID,
11 | displayName: ID,
12 | version: pkg.version,
13 | homepage: pkg.homepage,
14 | locationProps: new Set(['start', 'end']),
15 | typeProps: new Set(['TYPE']),
16 |
17 | loadParser(callback) {
18 | require([
19 | 'raw-loader?esModule=false!uglify-es/lib/utils.js',
20 | 'raw-loader?esModule=false!uglify-es/lib/ast.js',
21 | 'raw-loader?esModule=false!uglify-es/lib/parse.js',
22 | ], (...contents) => {
23 | contents.push('exports.parse = parse;');
24 | callback(compileModule(contents.join('\n\n')));
25 | });
26 | },
27 |
28 | parse(UglifyJS, code) {
29 | return UglifyJS.parse(code);
30 | },
31 |
32 | getNodeName(node) {
33 | let type = node.TYPE;
34 | if (type === 'Token') {
35 | type += `(${node.type})`;
36 | }
37 | return type;
38 | },
39 |
40 | nodeToRange(node) {
41 | let start, end;
42 | switch (node.TYPE) {
43 | case 'Token':
44 | start = end = node;
45 | break;
46 | case undefined:
47 | return null;
48 | default:
49 | ({ start, end } = node);
50 | break;
51 | }
52 | if (start && end) {
53 | return [start.pos, end.endpos];
54 | }
55 | return null;
56 | },
57 |
58 | opensByDefault(node, key) {
59 | return (
60 | key === 'body' ||
61 | key === 'elements' || // array literals
62 | key === 'definitions' || // variable declaration
63 | key === 'properties'
64 | );
65 | },
66 |
67 | _ignoredProperties: new Set(['_walk', 'CTOR']),
68 | };
69 |
--------------------------------------------------------------------------------
/website/src/parsers/js/utils/defaultESTreeParserInterface.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../../utils/defaultParserInterface';
2 |
3 | export default {
4 | ...defaultParserInterface,
5 |
6 | opensByDefault(node, key) {
7 | return (
8 | Boolean(node) && node.type === 'Program' ||
9 | key === 'body' ||
10 | key === 'elements' || // array literals
11 | key === 'declarations' || // variable declaration
12 | key === 'expression' // expression statements
13 | );
14 | },
15 |
16 | };
17 |
--------------------------------------------------------------------------------
/website/src/parsers/js/utils/eslintUtils.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../utils/compileModule';
2 | import transpile from '../../transpilers/babel';
3 | import {parseNoPatch} from 'babel-eslint';
4 |
5 | export function formatResults(results) {
6 | return results.length === 0
7 | ? 'Lint rule not fired.'
8 | : results.map(formatResult).join('').trim();
9 | }
10 |
11 | export function formatResult(result) {
12 | var pointer = '-'.repeat(result.column - 1) + '^';
13 | return `
14 | // ${result.message} (at ${result.line}:${result.column})
15 | ${result.source}
16 | // ${pointer}
17 | `;
18 | }
19 |
20 | export function defineRule(eslintRules, code) {
21 | // Compile the transform code and install it as an ESLint rule. The rule
22 | // name doesn't really matter here, so we'll just use a hard-coded name.
23 | code = transpile(code);
24 | const rule = compileModule(code);
25 | eslintRules.define('astExplorerRule', rule.default || rule);
26 | }
27 |
28 | export function runRule(code, eslint, sourceCode) {
29 | // Run the ESLint rule on the AST of the provided code.
30 | // Reference: http://eslint.org/docs/developer-guide/nodejs-api
31 | const ast = parseNoPatch(code, {
32 | sourceType: 'module',
33 | });
34 | const results = eslint.verify(new sourceCode(code, ast), {
35 | env: {es6: true},
36 | parserOptions: {
37 | ecmaVersion: 8,
38 | sourceType: 'module',
39 | ecmaFeatures: {experimentalObjectRestSpread: true},
40 | },
41 | rules: {
42 | astExplorerRule: 2,
43 | },
44 | });
45 | return formatResults(results);
46 | }
47 |
--------------------------------------------------------------------------------
/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/json/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/javascript/javascript';
2 |
3 | export const id = 'json';
4 | export const displayName = 'JSON';
5 | export const mimeTypes = ['application/json'];
6 | export const fileExtension = 'json';
7 | export const editorMode = {name: 'javascript', json: true};
8 |
--------------------------------------------------------------------------------
/website/src/parsers/json/json-to-ast.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'json-to-ast/package.json';
3 |
4 | const ID = 'jsonToAst';
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 |
15 | loadParser(callback) {
16 | require(['json-to-ast'], callback);
17 | },
18 |
19 | parse(jsonToAst, code) {
20 | return jsonToAst(code);
21 | },
22 |
23 | nodeToRange({loc}) {
24 | if (loc) {
25 | return [
26 | loc.start.offset,
27 | loc.end.offset,
28 | ];
29 | }
30 | },
31 | }
32 |
--------------------------------------------------------------------------------
/website/src/parsers/json/momoa.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from '@humanwhocodes/momoa/package.json';
3 |
4 | const ID = 'momoa';
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 |
15 | loadParser(callback) {
16 | require(['@humanwhocodes/momoa'], callback);
17 | },
18 |
19 | parse(momoa, code, options) {
20 | return momoa.parse(code, options);
21 | },
22 |
23 | nodeToRange({loc}) {
24 | if (loc) {
25 | return [
26 | loc.start.offset,
27 | loc.end.offset,
28 | ];
29 | }
30 | },
31 |
32 | getDefaultOptions() {
33 | return {
34 | comments: true,
35 | tokens: true,
36 | ranges: true,
37 | };
38 | },
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/website/src/parsers/lua/codeExample.txt:
--------------------------------------------------------------------------------
1 | --[[
2 | Paste or drop some Lua here and explore
3 | the syntax tree created by chosen parser.
4 | Enjoy!
5 | --]]
6 |
7 | function allwords ()
8 | local line = io.read() -- current line
9 | local pos = 1 -- current position in the line
10 | return function () -- iterator function
11 | while line do -- repeat while there are lines
12 | local s, e = string.find(line, "%w+", pos)
13 | if s then -- found a word?
14 | pos = e + 1 -- update next position
15 | return string.sub(line, s, e) -- return the word
16 | else
17 | line = io.read() -- word not found; try next line
18 | pos = 1 -- restart from first position
19 | end
20 | end
21 | return nil -- no more lines: end of traversal
22 | end
23 | end
--------------------------------------------------------------------------------
/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/src/parsers/lua/luaparse.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import defaultParserInterface from '../utils/defaultParserInterface';
3 | import pkg from 'luaparse/package.json';
4 |
5 | const ID = 'luaparse';
6 |
7 | export default {
8 | ...defaultParserInterface,
9 |
10 | id: ID,
11 | displayName: ID,
12 | version: `${pkg.version}`,
13 | homepage: pkg.homepage,
14 | locationProps: new Set(['range', 'loc']),
15 |
16 | loadParser(callback) {
17 | require(['luaparse'], callback);
18 | },
19 |
20 | parse(luaparse, code, options={}) {
21 | return luaparse.parse(code, options);
22 | },
23 |
24 | getDefaultOptions() {
25 | return {
26 | ranges: true,
27 | locations: false,
28 | comments: true,
29 | scope: false,
30 | luaVersion: '5.1',
31 | };
32 | },
33 |
34 | _getSettingsConfiguration() {
35 | return {
36 | fields: [
37 | 'ranges',
38 | 'locations',
39 | 'comments',
40 | 'scope',
41 | ['luaVersion', ['5.1', '5.2', '5.3']],
42 | ],
43 | required: new Set(['ranges']),
44 | };
45 |
46 | },
47 |
48 | renderSettings(parserSettings, onChange) {
49 | return (
50 |
51 |
52 |
55 | Option descriptions
56 |
57 |
58 | {defaultParserInterface.renderSettings.call(
59 | this,
60 | parserSettings,
61 | onChange,
62 | )}
63 |
64 | );
65 | },
66 | };
67 |
--------------------------------------------------------------------------------
/website/src/parsers/lucene/codeExample.txt:
--------------------------------------------------------------------------------
1 | name:frank OR job:engineer AND food:/marshmal+ows/
2 |
--------------------------------------------------------------------------------
/website/src/parsers/lucene/index.js:
--------------------------------------------------------------------------------
1 | export const id = 'lucene';
2 | export const displayName = 'Lucene';
3 | export const mimeTypes = [''];
4 | export const fileExtension = 'lucene';
5 |
--------------------------------------------------------------------------------
/website/src/parsers/lucene/lucene.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'lucene/package.json';
3 |
4 | const ID = 'lucene';
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(['fieldLocation', 'termLocation', 'location']),
14 |
15 | loadParser(callback) {
16 | require(['lucene'], callback);
17 | },
18 |
19 | parse({parse}, code) {
20 | return parse(code);
21 | },
22 |
23 | nodeToRange(node) {
24 | let start = [];
25 | let end = [];
26 |
27 | if (node.location) {
28 | start.push(node.location.start.offset);
29 | end.push(node.location.end.offset);
30 | }
31 | if (node.fieldLocation) {
32 | start.push(node.fieldLocation.start.offset);
33 | end.push(node.fieldLocation.end.offset);
34 | }
35 | if (node.termLocation) {
36 | start.push(node.termLocation.start.offset);
37 | end.push(node.termLocation.end.offset);
38 | }
39 |
40 | if (start.length === 0 || end.length === 0) {
41 | return;
42 | }
43 |
44 | return [start.reduce((a, b) => Math.min(a, b)), end.reduce((a, b) => Math.max(a, b))];
45 | },
46 |
47 | getDefaultOptions() {
48 | return {};
49 | },
50 |
51 | };
52 |
--------------------------------------------------------------------------------
/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/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/markdown/transformers/remark/codeExample.txt:
--------------------------------------------------------------------------------
1 | // available utilities are: "unist-util-is", "unist-util-visit", and "unist-util-visit-parents"
2 | const visit = require("unist-util-visit");
3 |
4 | module.exports = function attacher(options) {
5 | return function transformer(tree, vfile) {
6 | // add a level to headings, for example `# heading` to `## heading`
7 | visit(tree, "heading", (node) => {
8 | node.depth += 1
9 | });
10 | return tree;
11 | };
12 | };
13 |
--------------------------------------------------------------------------------
/website/src/parsers/markdown/transformers/remark/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'remark/package.json';
3 |
4 | const ID = 'remark';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 |
12 | defaultParserID: ID,
13 |
14 | loadTransformer(callback) {
15 | require([
16 | 'remark',
17 | 'unist-util-is',
18 | 'unist-util-visit',
19 | 'unist-util-visit-parents',
20 | ], ({ remark }, { is }, { visit }, { visitParents }) => {
21 | callback({
22 | remark,
23 | 'unist-util-is': is,
24 | 'unist-util-visit': visit,
25 | 'unist-util-visit-parents': visitParents,
26 | });
27 | });
28 | },
29 |
30 | transform({ remark, ...availableModules }, transformCode, code) {
31 | function sandboxRequire(name) {
32 | if (!Object.getOwnPropertyNames(availableModules).includes(name))
33 | throw new Error(`Cannot find module '${name}'`);
34 | return availableModules[name];
35 | }
36 |
37 | const transform = compileModule(transformCode, { require: sandboxRequire });
38 | return remark().use(transform).processSync(code).value;
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/website/src/parsers/mathjs/codeExample.txt:
--------------------------------------------------------------------------------
1 | (sin(2x) + e^x) / 2
2 |
--------------------------------------------------------------------------------
/website/src/parsers/mathjs/index.js:
--------------------------------------------------------------------------------
1 | export const id = 'mathjs';
2 | export const displayName = 'Math.js';
3 | export const mimeTypes = ['text/mathjs'];
4 | export const fileExtension = 'mathjs';
5 |
--------------------------------------------------------------------------------
/website/src/parsers/mathjs/mathjs.js:
--------------------------------------------------------------------------------
1 | import pkg from 'mathjs/package.json';
2 |
3 | import defaultParserInterface from '../utils/defaultParserInterface'
4 |
5 | const ID = 'mathjs'
6 |
7 | export default {
8 | ...defaultParserInterface,
9 |
10 | id: ID,
11 | displayName: ID,
12 | version: pkg.version,
13 | homepage: 'https://mathjs.org/',
14 | locationProps: new Set(['span']),
15 |
16 | defaultParserID: 'mathjs',
17 |
18 | async loadParser(callback) {
19 | require(['mathjs'], callback);
20 | },
21 |
22 | parse(parser, code) {
23 | try {
24 | return parser.parse(code)
25 | } catch (message) {
26 | // AST Explorer expects the thrown error to be an object, not a string.
27 | throw new SyntaxError(message);
28 | }
29 | },
30 |
31 | getNodeName(node) {
32 | return node.type
33 | },
34 |
35 | // TODO once this feature is added to mathjs
36 | // nodeToRange(node) {
37 | // },
38 |
39 | opensByDefault(node) {
40 | return node.type === 'BlockNode'
41 | },
42 | }
43 |
--------------------------------------------------------------------------------
/website/src/parsers/mdx/codeExample.txt:
--------------------------------------------------------------------------------
1 | import MyComp from './components/MyComp'
2 |
3 | export const meta = {
4 | title: 'Page Title',
5 | description: 'This is a page description',
6 | }
7 |
8 | # Hello
9 |
10 |
11 | Component children
12 |
13 |
14 | Some *emphasis*, **importance**, and `code`.
15 |
16 | ---
17 |
18 | ```javascript
19 | console.log('!');
20 | ```
21 |
22 | * foo
23 | * bar
24 | * baz
25 |
--------------------------------------------------------------------------------
/website/src/parsers/mdx/index.js:
--------------------------------------------------------------------------------
1 | export const id = 'mdx';
2 | export const displayName = 'MDX';
3 | export const mimeTypes = ['text/mdx'];
4 | export const fileExtension = 'mdx';
5 |
--------------------------------------------------------------------------------
/website/src/parsers/mdx/mdxhast.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from '@mdx-js/mdx/package.json';
3 |
4 | const ID = 'mdxhast';
5 |
6 | function removeNewlines(node) {
7 | if (node.children != null) {
8 | node.children = node.children.filter(node => node.value !== '\n');
9 | node.children.forEach(removeNewlines);
10 | }
11 | }
12 |
13 | export default {
14 | ...defaultParserInterface,
15 |
16 | id: ID,
17 | displayName: ID,
18 | version: pkg.version,
19 | homepage: 'https://mdxjs.com',
20 | locationProps: new Set(['position']),
21 |
22 | loadParser(callback) {
23 | require(['@mdx-js/mdx', '@mdx-js/mdx/mdx-ast-to-mdx-hast'], (mdx, mdxAstToMdxHast) => callback({mdx, mdxAstToMdxHast}));
24 | },
25 |
26 | parse({mdx, mdxAstToMdxHast}, code) {
27 | let result;
28 | mdx.sync(code, {
29 | hastPlugins: [
30 | mdxAstToMdxHast,
31 | () => removeNewlines,
32 | () => tree => {
33 | result = tree;
34 | },
35 | ],
36 | });
37 |
38 | return result;
39 | },
40 |
41 | nodeToRange({ position }) {
42 | if (position) {
43 | return [position.start.offset, position.end.offset];
44 | }
45 | },
46 |
47 | opensByDefault(node, key) {
48 | return key === 'children';
49 | },
50 | };
51 |
--------------------------------------------------------------------------------
/website/src/parsers/mdx/transformers/mdx/codeExample.txt:
--------------------------------------------------------------------------------
1 | export default {
2 | mdPlugins: [],
3 | hastPlugins: [],
4 | }
5 |
--------------------------------------------------------------------------------
/website/src/parsers/mdx/transformers/mdx/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from '@mdx-js/mdx/package.json';
3 |
4 | const ID = 'mdx';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: 'https://mdxjs.com',
11 |
12 | defaultParserID: 'mdxhast',
13 |
14 | loadTransformer(callback) {
15 | require([
16 | '../../../transpilers/babel',
17 | '@mdx-js/mdx',
18 | 'prettier/standalone',
19 | 'prettier/parser-babel',
20 | ], (transpile, mdx, prettier, babel) => {
21 | callback({ transpile: transpile.default, mdx, prettier, babel });
22 | });
23 | },
24 |
25 | transform({ transpile, mdx, prettier, babylon }, transformCode, code) {
26 | transformCode = transpile(transformCode);
27 | const transform = compileModule(transformCode);
28 | const jsxCode = mdx.sync(code, {
29 | ...(transform.default || transform),
30 | });
31 | try {
32 | return prettier.format(jsxCode, {
33 | parser: 'babylon',
34 | plugins: [babylon],
35 | });
36 | } catch (err) {
37 | return `
38 | ${err.message}
39 |
40 | ------------
41 | Full output:
42 | ------------
43 |
44 | ${jsxCode.trim()}
45 | `.trim();
46 | }
47 | },
48 | };
49 |
--------------------------------------------------------------------------------
/website/src/parsers/monkey/codeExample.txt:
--------------------------------------------------------------------------------
1 | let version = 1 + (50 / 2) - (8 * 3);
2 |
3 | let name = "The Monkey programming language";
4 |
5 | let isMonkeyFastNow = true;
6 |
7 | let people = [{"name": "Anna", "age": 24}, {"name": "Bob", "age": 99}];
8 |
9 | let getName = fn(person) { person["name"]; };
10 | getName(people[0]);
11 | getName(people[1]);
12 |
13 | puts(len(people))
14 |
15 | let fibonacci = fn(x) {
16 | if (x == 0) {
17 | 0
18 | } else {
19 | if (x == 1) {
20 | return 1;
21 | } else {
22 | fibonacci(x - 1) + fibonacci(x - 2);
23 | }
24 | }
25 | };
26 |
27 |
28 | let newAdder = fn(a, b) {
29 | fn(c) { a + b + c };
30 | };
31 |
32 | let adder = newAdder(1, 2);
33 |
34 | adder(8);
35 |
--------------------------------------------------------------------------------
/website/src/parsers/monkey/index.js:
--------------------------------------------------------------------------------
1 | export const id = 'monkey';
2 | export const displayName = 'Monkey';
3 | export const mimeTypes = [];
4 | export const fileExtension = 'monkey';
5 |
--------------------------------------------------------------------------------
/website/src/parsers/monkey/monkey.js:
--------------------------------------------------------------------------------
1 | import pkg from '@gengjiawen/monkey-wasm/package.json';
2 |
3 | import defaultParserInterface from '../utils/defaultParserInterface'
4 |
5 | const ID = 'monkey'
6 |
7 | export default {
8 | ...defaultParserInterface,
9 |
10 | id: ID,
11 | displayName: ID,
12 | version: pkg.version,
13 | homepage: 'https://monkeylang.org/',
14 | locationProps: new Set(['span']),
15 |
16 | async loadParser(callback) {
17 | require(['@gengjiawen/monkey-wasm/monkey_wasm.js'], callback);
18 | },
19 |
20 | parse(parser, code) {
21 | try {
22 | return JSON.parse(parser.parse(code));
23 | } catch (message) {
24 | // AST Explorer expects the thrown error to be an object, not a string.
25 | throw new SyntaxError(message);
26 | }
27 | },
28 |
29 | getNodeName(node) {
30 | return node.type
31 | },
32 |
33 | nodeToRange(node) {
34 | if (node && node.span && typeof node.span.start === 'number') {
35 | return [node.span.start, node.span.end];
36 | }
37 | },
38 | }
39 |
--------------------------------------------------------------------------------
/website/src/parsers/ocaml/codeExample.txt:
--------------------------------------------------------------------------------
1 | let tips = [
2 | "Click on any AST node with a '+' to expand it";
3 |
4 | "Hovering over a node highlights the
5 | corresponding location in the source code";
6 |
7 | "Shift click on an AST node to expand the whole subtree"
8 | ]
9 |
10 | let printTips () =
11 | tips |> (List.iteri (fun i tip -> Printf.printf "Tip %d: %s\n" i tip))
12 |
--------------------------------------------------------------------------------
/website/src/parsers/ocaml/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/mllike/mllike';
2 |
3 | export const id = 'ocaml';
4 | export const editorMode = 'text/x-ocaml';
5 | export const displayName = 'OCaml';
6 | export const mimeTypes = ['text/x-ocaml'];
7 | export const fileExtension = 'ml';
8 |
--------------------------------------------------------------------------------
/website/src/parsers/ocaml/refmt-ml.js:
--------------------------------------------------------------------------------
1 | import config from '../reason/refmt';
2 |
3 | const ID = 'refmt-ml';
4 |
5 | export default {
6 | ...config,
7 | id: ID,
8 | parse: function(parser, code) {
9 | return parser.parseOcaml(code);
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/website/src/parsers/php/codeExample.txt:
--------------------------------------------------------------------------------
1 | $tip) {
15 | echo "Tip $i: " . $tip;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/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/parsers/php/php-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'php-parser/package.json';
3 |
4 | const ID = 'php-parser';
5 |
6 | const defaultOptions = {
7 | parser: {
8 | extractDoc: true,
9 | },
10 | ast: {
11 | withPositions: true,
12 | },
13 | };
14 |
15 | export default {
16 | ...defaultParserInterface,
17 |
18 | id: ID,
19 | displayName: ID,
20 | version: pkg.version,
21 | homepage: pkg.homepage,
22 | locationProps: new Set(['loc']),
23 | typeProps: new Set(['kind']),
24 |
25 | loadParser(callback) {
26 | require(['php-parser'], callback);
27 | },
28 |
29 | parse(Engine, code) {
30 | const parser = new Engine(defaultOptions);
31 | return parser.parseCode(code, '');
32 | },
33 |
34 | getNodeName(node) {
35 | return node.kind;
36 | },
37 |
38 | nodeToRange(node) {
39 | if (node.loc && node.loc.start && node.loc.end) {
40 | return [node.loc.start.offset, node.loc.end.offset];
41 | }
42 | },
43 |
44 | opensByDefault(node, key) {
45 | return key === 'body' || key === 'what' || key === 'items';
46 | },
47 | };
48 |
--------------------------------------------------------------------------------
/website/src/parsers/protobuf/codeExample.txt:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package tutorial;
3 |
4 | import "google/protobuf/timestamp.proto";
5 |
6 | option go_package = "github.com/protocolbuffers/protobuf/examples/go/tutorialpb";
7 |
8 | message Person {
9 | string name = 1;
10 | int32 id = 2; // Unique ID number for this person.
11 | string email = 3;
12 |
13 | enum PhoneType {
14 | MOBILE = 0;
15 | HOME = 1;
16 | WORK = 2;
17 | }
18 |
19 | message PhoneNumber {
20 | string number = 1;
21 | PhoneType type = 2;
22 | }
23 |
24 | repeated PhoneNumber phones = 4;
25 |
26 | google.protobuf.Timestamp last_updated = 5;
27 | }
28 |
29 | // Our address book file is just one of these.
30 | message AddressBook {
31 | repeated Person people = 1;
32 | }
33 |
--------------------------------------------------------------------------------
/website/src/parsers/protobuf/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/protobuf/protobuf';
2 |
3 | export const id = 'protobuf';
4 | export const displayName = 'Protocol Buffers';
5 | export const mimeTypes = ['text/x-protobuf'];
6 | export const fileExtension = 'proto';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/protobuf/pbkit.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'pbkit/package.json';
3 |
4 | const ID = 'pbkit';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 | id: ID,
9 | displayName: ID,
10 | version: pkg.version,
11 | homepage: 'https://github.com/riiid/pbkit',
12 | locationProps: new Set(['start', 'end']),
13 | typeProps: new Set(['type']),
14 |
15 | loadParser(callback) {
16 | require(['pbkit/core/parser/proto'], callback);
17 | },
18 |
19 | parse(parser, code) {
20 | return parser.parse(code).ast;
21 | },
22 |
23 | nodeToRange(node) {
24 | const { start, end } = node;
25 | return [start, end];
26 | },
27 |
28 | opensByDefault(node, key) {
29 | if (key === 'statements') {
30 | return true;
31 | }
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/website/src/parsers/pug/codeExample.txt:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(lang='en')
3 | head
4 | title Pug
5 | script(type='text/javascript').
6 | const foo = true;
7 | let bar = function() {};
8 | if (foo) {
9 | bar(1 + 5)
10 | }
11 | body
12 | h1 Pug - node template engine
13 | #container.col
14 | p You are amazing
15 | p
16 | | Pug is a terse and simple
17 | | templating language with a
18 | | strong focus on performance
19 | | and powerful features.
20 |
--------------------------------------------------------------------------------
/website/src/parsers/pug/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/pug/pug';
2 |
3 | export const id = 'pug';
4 | export const displayName = 'Pug';
5 | export const mimeTypes = [];
6 | export const fileExtension = 'pug';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/pug/pug.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'pug-parser/package.json';
3 |
4 | const ID = 'pug';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/pugjs/pug',
13 | typeProps: new Set(['type', 'name']),
14 | locationProps: new Set(['line', 'column']),
15 |
16 | loadParser(callback) {
17 | require(['pug-lexer', 'pug-parser'], (lex, parse) => {
18 | callback({ lex, parse });
19 | });
20 | },
21 |
22 | parse({ lex, parse }, code) {
23 | return parse(lex(code, {}), { src: code });
24 | },
25 |
26 | opensByDefault(node, key) {
27 | switch (key) {
28 | case 'block':
29 | case 'nodes':
30 | return true;
31 | }
32 | },
33 |
34 | getNodeName(node) {
35 | let { type } = node;
36 | /* eslint-disable no-fallthrough */
37 | switch (type) {
38 | case 'Block': return '';
39 | case 'Doctype': return `Doctype(${node.val})`;
40 | case 'Comment': if (node.buffer) return 'Comment(buffer)';
41 | case 'NamedBlock': return `Block:${node.mode}(${node.name})`;
42 | case 'Code': if (node.val === 'break') return 'Code(break)';
43 | case 'When': if (node.expr === 'default') return 'When(default)';
44 | case 'Include':
45 | case 'RawInclude':
46 | case 'Extends':
47 | case 'Each':
48 | case 'While':
49 | case 'Conditional':
50 | case 'Case':
51 | case 'AttributeBlock':
52 | case 'Text': return type;
53 | default: type = 'Attribute';
54 | case 'Filter':
55 | case 'Mixin': if (node.call) type = 'Mixin:call';
56 | case 'Tag': return `${type}(${node.name})`;
57 | }
58 | /* eslint-enable no-fallthrough */
59 | },
60 | };
61 |
--------------------------------------------------------------------------------
/website/src/parsers/python/codeExample.txt:
--------------------------------------------------------------------------------
1 | print("Hello world")
2 |
3 | num1 = 1.5
4 | num2 = 6.3
5 |
6 | # Add two numbers
7 | sum = num1 + num2
8 |
9 | # Display the sum
10 | print('The sum of {0} and {1} is {2}'.format(num1, num2, sum))
11 |
12 | # Note: change this value for a different result
13 | num = 8
14 |
15 | # To take the input from the user
16 | #num = float(input('Enter a number: '))
17 |
18 | num_sqrt = num ** 0.5
19 | print('The square root of %0.3f is %0.3f'%(num ,num_sqrt))
20 |
21 |
--------------------------------------------------------------------------------
/website/src/parsers/python/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/python/python';
2 |
3 | export const id = 'python';
4 | export const displayName = 'Python';
5 | export const mimeTypes = [];
6 | export const fileExtension = 'py';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/python/python.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'filbert/package.json';
3 |
4 | const ID = 'python';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/differentmatt/filbert',
13 | locationProps: new Set(['range', 'loc', 'start', 'end']),
14 |
15 | loadParser(callback) {
16 | require(['filbert'], (parser) => {
17 | callback({ parser });
18 | });
19 | },
20 |
21 | parse({ parser }, code) {
22 | return parser.parse(code, {
23 | locations: true,
24 | ranges: true,
25 | });
26 | },
27 |
28 | opensByDefault(node, key) {
29 | switch (key) {
30 | case 'block':
31 | case 'nodes':
32 | return true;
33 | }
34 | },
35 |
36 | nodeToRange(node) {
37 | const { range } = node;
38 | if (typeof range === 'object') {
39 | return range;
40 | }
41 | },
42 |
43 | };
44 |
--------------------------------------------------------------------------------
/website/src/parsers/reason/codeExample.txt:
--------------------------------------------------------------------------------
1 | let tips = [
2 | "Click on any AST node with a '+' to expand it",
3 |
4 | "Hovering over a node highlights the
5 | corresponding location in the source code",
6 |
7 | "Shift click on an AST node to expand the whole subtree",
8 | ];
9 |
10 | let printTips = () =>
11 | tips |> List.iteri((i, tip) => Printf.printf("Tip %d: %s\n", i, tip));
12 |
--------------------------------------------------------------------------------
/website/src/parsers/reason/index.js:
--------------------------------------------------------------------------------
1 | export const id = 'reason';
2 | export const displayName = 'Reason';
3 | export const mimeTypes = [];
4 | export const fileExtension = 're';
5 |
--------------------------------------------------------------------------------
/website/src/parsers/reason/refmt.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import esyPkg from 'astexplorer-refmt/esy.json';
3 | import CodeMirror from 'codemirror';
4 | import addCodeMirrorMode from './codeMirrorMode';
5 |
6 | addCodeMirrorMode(CodeMirror);
7 |
8 | const ID = 'refmt';
9 | const locKeys = [
10 | 'loc',
11 | 'pcd_loc',
12 | 'pcf_loc',
13 | 'pci_loc',
14 | 'pcl_loc',
15 | 'pctf_loc',
16 | 'pcty_loc',
17 | 'pexp_loc',
18 | 'pext_loc',
19 | 'pincl_loc',
20 | 'pld_loc',
21 | 'pmb_loc',
22 | 'pmd_loc',
23 | 'pmod_loc',
24 | 'pmtd_loc',
25 | 'pmty_loc',
26 | 'popen_loc',
27 | 'ppat_loc',
28 | 'psig_loc',
29 | 'pstr_loc',
30 | 'ptyp_loc',
31 | 'ptype_loc',
32 | 'pval_loc',
33 | 'pvb_loc',
34 | ];
35 | const parserVersion = esyPkg.dependencies['@esy-ocaml/reason'];
36 |
37 | export default {
38 | ...defaultParserInterface,
39 |
40 | id: ID,
41 | displayName: ID,
42 | version: parserVersion,
43 | homepage: `https://www.npmjs.com/package/@esy-ocaml/reason/v/${parserVersion}`,
44 | locationProps: new Set(locKeys),
45 |
46 | loadParser(callback) {
47 | require(['astexplorer-refmt'], callback);
48 | },
49 |
50 | parse(parser, code) {
51 | return parser.parseReason(code);
52 | },
53 |
54 | getNodeName(node) {
55 | return node.type;
56 | },
57 |
58 | nodeToRange(node) {
59 | const locKey = locKeys.find(key => Object.prototype.hasOwnProperty.call(node, key));
60 | if (locKey) {
61 | const range = [
62 | node[locKey].loc_start.pos_cnum,
63 | node[locKey].loc_end.pos_cnum,
64 | ];
65 | return range;
66 | }
67 | },
68 | };
69 |
--------------------------------------------------------------------------------
/website/src/parsers/regexp/codeExample.txt:
--------------------------------------------------------------------------------
1 | /[a-z]/i
--------------------------------------------------------------------------------
/website/src/parsers/regexp/index.js:
--------------------------------------------------------------------------------
1 | export const id = 'regexp';
2 | export const displayName = 'RegExp';
3 | export const mimeTypes = ['text/regexp'];
4 | export const fileExtension = 'regexp';
--------------------------------------------------------------------------------
/website/src/parsers/regexp/regexp-tree.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'regexp-tree/package.json';
3 |
4 | const ID = 'regexp-tree';
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 |
15 | loadParser(callback) {
16 | require(['regexp-tree'], (regexpTree) => {
17 | callback(regexpTree);
18 | });
19 | },
20 |
21 | parse(regexpTree, code, options={}) {
22 | regexpTree
23 | .parser
24 | .setOptions(options);
25 |
26 | return regexpTree.parse(code);
27 | },
28 |
29 | nodeToRange(node) {
30 | if (node.loc != null) {
31 | return [node.loc.start, node.loc.end];
32 | }
33 | },
34 |
35 | opensByDefault(node, key) {
36 | return (
37 | node.type === 'RegExp' ||
38 | key === 'body' ||
39 | key === 'expressions'
40 | );
41 | },
42 |
43 | getDefaultOptions() {
44 | return {
45 | captureLocations: true,
46 | };
47 | },
48 |
49 | };
50 |
--------------------------------------------------------------------------------
/website/src/parsers/regexp/regexpp.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'regexpp/package.json';
3 |
4 | const ID = 'regexpp';
5 |
6 | /** @type {import("regexpp").RegExpParser.Options} */
7 | export const defaultOptions = {
8 | strict: false,
9 | ecmaVersion: 2020,
10 | };
11 |
12 | export default {
13 | ...defaultParserInterface,
14 |
15 | id: ID,
16 | displayName: ID,
17 | version: pkg.version,
18 | homepage: pkg.homepage,
19 | locationProps: new Set(['end', 'start']),
20 |
21 | loadParser(callback) {
22 | require(['regexpp'], callback);
23 | },
24 |
25 | parse(regexpp, code, options) {
26 | if (Object.keys(options).length === 0) {
27 | options = this.getDefaultOptions();
28 | }
29 | return regexpp.parseRegExpLiteral(code, options);
30 | },
31 |
32 | nodeToRange(node) {
33 | if (typeof node.start === 'number' && typeof node.end === 'number') {
34 | return [node.start, node.end];
35 | }
36 | },
37 |
38 | opensByDefault(node, key) {
39 | return (
40 | key === 'pattern' ||
41 | key === 'elements' ||
42 | key === 'element' ||
43 | key === 'alternatives'
44 | );
45 | },
46 |
47 | getDefaultOptions() {
48 | return defaultOptions;
49 | },
50 |
51 | _ignoredProperties: new Set(['parent', 'references', 'resolved']),
52 |
53 | };
54 |
--------------------------------------------------------------------------------
/website/src/parsers/regexp/regjsparser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'regjsparser/package.json';
3 |
4 | const ID = 'regjsparser';
5 |
6 | export const defaultOptions = {
7 | unicodePropertyEscape: true,
8 | namedGroups: true,
9 | lookbehind: true,
10 | };
11 |
12 | export default {
13 | ...defaultParserInterface,
14 |
15 | id: ID,
16 | displayName: ID,
17 | version: pkg.version,
18 | homepage: pkg.homepage,
19 | locationProps: new Set(['range']),
20 |
21 | loadParser(callback) {
22 | require(['regjsparser'], callback);
23 | },
24 |
25 | parse(regjsparser, code, options) {
26 | if (Object.keys(options).length === 0) {
27 | options = this.getDefaultOptions();
28 | }
29 | var firstSlash = code.indexOf('/');
30 | var lastSlash = code.lastIndexOf('/');
31 | if (firstSlash !== 0 || lastSlash < 1) {
32 | throw new Error('Please wrap the regex pattern by slash `/`, i.e. /foo/');
33 | }
34 | var flags = code.slice(lastSlash + 1);
35 | var pattern = code.slice(firstSlash + 1, lastSlash);
36 | return regjsparser.parse(pattern, flags, options);
37 | },
38 |
39 | nodeToRange(node) {
40 | if (node.range != null) {
41 | return [node.range[0] + 1, node.range[1] + 1];
42 | }
43 | },
44 |
45 | opensByDefault(node, key) {
46 | return (
47 | key === 'body'
48 | );
49 | },
50 |
51 | getDefaultOptions() {
52 | return defaultOptions;
53 | },
54 |
55 | };
56 |
--------------------------------------------------------------------------------
/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/regexp/transformers/regexp-tree/index.js:
--------------------------------------------------------------------------------
1 | import compileModule from '../../../utils/compileModule';
2 | import pkg from 'regexp-tree/package.json';
3 |
4 | const ID = 'regexp-tree';
5 |
6 | export default {
7 | id: ID,
8 | displayName: ID,
9 | version: pkg.version,
10 | homepage: pkg.homepage,
11 |
12 | defaultParserID: ID,
13 |
14 | loadTransformer(callback) {
15 | require([
16 | '../../../transpilers/babel',
17 | 'regexp-tree',
18 | ], (transpile, regexpTree) => callback({ transpile: transpile.default, regexpTree }));
19 | },
20 |
21 | transform({ transpile, regexpTree }, transformCode, code) {
22 | transformCode = transpile(transformCode);
23 | let handler = compileModule( // eslint-disable-line no-shadow
24 | transformCode,
25 | );
26 |
27 | return regexpTree.transform(code, handler).toString();
28 | },
29 | };
30 |
--------------------------------------------------------------------------------
/website/src/parsers/rust/codeExample.txt:
--------------------------------------------------------------------------------
1 | const TIPS: &[&str] = &[
2 | "Click on any AST node with a '+' to expand it",
3 |
4 | "Hovering over a node highlights the \
5 | corresponding location in the source code",
6 |
7 | "Shift click on an AST node to expand the whole subtree",
8 | ];
9 |
10 | pub fn print_tips() {
11 | for (i, tip) in TIPS.iter().enumerate() {
12 | println!("Tip {}: {}.", i, tip);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/website/src/parsers/rust/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/rust/rust';
2 |
3 | export const id = 'rust';
4 | export const displayName = 'Rust';
5 | export const mimeTypes = [];
6 | export const fileExtension = 'rs';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/rust/syn.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'astexplorer-syn/package.json';
3 |
4 | const ID = 'syn';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: `https://docs.rs/syn/${pkg.version}/syn/`,
13 | _ignoredProperties: new Set(['_type']),
14 | locationProps: new Set(['span']),
15 |
16 | loadParser(callback) {
17 | require(['astexplorer-syn'], callback);
18 | },
19 |
20 | parse(parser, code) {
21 | this.lineOffsets = [];
22 | let index = 0;
23 | do {
24 | this.lineOffsets.push(index);
25 | } while ((index = code.indexOf('\n', index) + 1)); // eslint-disable-line no-cond-assign
26 | return parser.parseFile(code);
27 | },
28 |
29 | getNodeName(node) {
30 | return node._type;
31 | },
32 |
33 | nodeToRange(node) {
34 | if (node.span) {
35 | return [node.span.start, node.span.end].map(
36 | ({ line, column }) => this.lineOffsets[line - 1] + column,
37 | );
38 | }
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/website/src/parsers/san/codeExample.txt:
--------------------------------------------------------------------------------
1 |
2 |
{{title}}
3 |
7 |
8 |
--------------------------------------------------------------------------------
/website/src/parsers/san/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/htmlmixed/htmlmixed';
2 |
3 | export const id = 'san';
4 | export const displayName = 'San';
5 | export const mimeTypes = ['text/html'];
6 | export const fileExtension = 'san.html';
7 | export const editorMode = 'htmlmixed';
8 |
--------------------------------------------------------------------------------
/website/src/parsers/san/san-template-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'san/package.json';
3 |
4 | const ID = 'san';
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([]),
14 | typeProps: new Set(['tag']),
15 |
16 | loadParser(callback) {
17 | require(['san'], callback);
18 | },
19 |
20 | parse(parser, code, options) {
21 | return parser.parseTemplate(code, options).children[0];
22 | },
23 |
24 | opensByDefault(node, key) {
25 | return key === 'children';
26 | },
27 |
28 | getNodeName(node) {
29 | return node.tagName;
30 | },
31 |
32 | getDefaultOptions() {
33 | return {};
34 | },
35 | _ignoredProperties: new Set([]),
36 | };
37 |
--------------------------------------------------------------------------------
/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/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/src/parsers/scala/scalameta.js:
--------------------------------------------------------------------------------
1 | import pkg from 'scalameta-parsers/package.json';
2 | import defaultParserInterface from '../utils/defaultParserInterface';
3 |
4 | const ID = 'scalameta';
5 |
6 | const dialects = {
7 | 'Scala 2.10': 'Scala210',
8 | 'Scala 2.11': 'Scala211',
9 | 'Scala 2.12': 'Scala212',
10 | 'Scala 2.13': 'Scala213',
11 | 'Scala 3': 'Scala3',
12 | 'Sbt 0.13.6': 'Sbt0136',
13 | 'Sbt 0.13.7': 'Sbt0137',
14 | 'Sbt 1': 'Sbt 1',
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/scalameta/scalameta',
24 | locationProps: new Set(['pos']),
25 |
26 | loadParser(callback) {
27 | require(['scalameta-parsers'], callback);
28 | },
29 |
30 | parse(scalametaParser, code, options) {
31 | const parsed = scalametaParser.parseSource(code, options);
32 | const { error, lineNumber, columnNumber } = parsed;
33 | if (error) {
34 | const e = new SyntaxError(parsed.error);
35 | e.lineNumber = lineNumber + 1;
36 | e.columnNumber = columnNumber + 1;
37 | throw e;
38 | }
39 | return parsed;
40 | },
41 |
42 | nodeToRange(node) {
43 | if (node.pos) {
44 | return [node.pos.start, node.pos.end];
45 | }
46 | },
47 |
48 | opensByDefault(node, key) {
49 | return (
50 | node.type === 'Program' ||
51 | key === 'body' ||
52 | key === 'self' ||
53 | key === 'stats'
54 | );
55 | },
56 |
57 | getDefaultOptions() {
58 | return {
59 | dialect: 'Scala213',
60 | };
61 | },
62 |
63 | _getSettingsConfiguration() {
64 | return {
65 | fields: [['dialect', dialects]],
66 | required: new Set('dialect'),
67 | };
68 | },
69 | };
70 |
--------------------------------------------------------------------------------
/website/src/parsers/solididy/codeExample.txt:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.18;
2 | contract SimpleStore {
3 | function set(uint _value) public {
4 | value = _value;
5 | }
6 |
7 | function get() public constant returns (uint) {
8 | return value;
9 | }
10 |
11 | uint value;
12 | }
--------------------------------------------------------------------------------
/website/src/parsers/solididy/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/javascript/javascript';
2 |
3 | export const id = 'solididy';
4 | export const displayName = 'Solidity';
5 | export const mimeTypes = [];
6 | export const fileExtension = 'sol';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/solididy/solidity-parser-antlr.js:
--------------------------------------------------------------------------------
1 | import pkg from 'solidity-parser-antlr/package.json';
2 | import defaultParserInterface from '../utils/defaultParserInterface';
3 |
4 | const ID = 'solidity-parser-antlr';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/federicobond/solidity-parser-antlr',
13 |
14 | loadParser(callback) {
15 | require(['solidity-parser-antlr'], callback);
16 | },
17 |
18 | parse(parser, code, options) {
19 | return parser.parse(code, options);
20 | },
21 |
22 | opensByDefault(node, key) {
23 | return node.type === 'SourceUnit' ||
24 | node.type === 'ContractDefinition' ||
25 | key === 'children' ||
26 | key === 'subNodes' ||
27 | key === 'body'
28 | },
29 |
30 | getDefaultOptions() {
31 | return {
32 | range: true,
33 | loc: false,
34 | tolerant: false,
35 | };
36 | },
37 |
38 | _getSettingsConfiguration() {
39 | return {
40 | fields: [
41 | 'range',
42 | 'loc',
43 | 'tolerant',
44 | ],
45 | };
46 | },
47 |
48 | };
49 |
50 |
--------------------------------------------------------------------------------
/website/src/parsers/solididy/solidity-parser-diligence.js:
--------------------------------------------------------------------------------
1 | import pkg from 'solidity-parser-diligence/package.json';
2 | import defaultParserInterface from '../utils/defaultParserInterface';
3 |
4 | const ID = 'solidity-parser-diligence';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/consensys/solidity-parser-antlr',
13 |
14 | loadParser(callback) {
15 | require(['solidity-parser-diligence'], callback);
16 | },
17 |
18 | parse(parser, code, options) {
19 | return parser.parse(code, options);
20 | },
21 |
22 | opensByDefault(node, key) {
23 | return node.type === 'SourceUnit' ||
24 | node.type === 'ContractDefinition' ||
25 | key === 'children' ||
26 | key === 'subNodes' ||
27 | key === 'body'
28 | },
29 |
30 | getDefaultOptions() {
31 | return {
32 | range: true,
33 | loc: false,
34 | tolerant: false,
35 | };
36 | },
37 |
38 | _getSettingsConfiguration() {
39 | return {
40 | fields: [
41 | 'range',
42 | 'loc',
43 | 'tolerant',
44 | ],
45 | };
46 | },
47 |
48 | };
49 |
50 |
--------------------------------------------------------------------------------
/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/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/src/parsers/sql/sql-parser-cst.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'sql-parser-cst/package.json';
3 |
4 | const ID = 'sql-parser-cst';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/nene/sql-parser-cst',
13 | locationProps: new Set(['range']),
14 |
15 | loadParser(callback) {
16 | require(['sql-parser-cst'], callback);
17 | },
18 |
19 | parse(parser, code, options) {
20 | return parser.parse(code, options);
21 | },
22 |
23 | getNodeName(node) {
24 | return node.type;
25 | },
26 |
27 | nodeToRange(node) {
28 | return node.range;
29 | },
30 |
31 | getDefaultOptions() {
32 | return {
33 | dialect: 'sqlite',
34 | preserveComments: true,
35 | includeRange: true,
36 | };
37 | },
38 |
39 | _getSettingsConfiguration() {
40 | return {
41 | fields: [
42 | ['dialect', ['sqlite', 'mysql']],
43 | 'preserveComments',
44 | 'preserveNewlines',
45 | 'preserveSpaces',
46 | 'includeRange',
47 | ],
48 | };
49 | },
50 | };
51 |
--------------------------------------------------------------------------------
/website/src/parsers/sql/sqlite-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'sqlite-parser/package.json';
3 |
4 | const ID = 'sqlite-parser';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/codeschool/sqlite-parser',
13 |
14 | loadParser(callback) {
15 | require(['sqlite-parser'], callback);
16 | },
17 |
18 | parse(sqliteParser, code) {
19 | return sqliteParser(code);
20 | },
21 |
22 | opensByDefault(node, key) {
23 | return key === 'statement';
24 | },
25 |
26 | };
27 |
--------------------------------------------------------------------------------
/website/src/parsers/svelte/codeExample.txt:
--------------------------------------------------------------------------------
1 |
4 |
5 | Hello {name}!
6 |
--------------------------------------------------------------------------------
/website/src/parsers/svelte/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/htmlmixed/htmlmixed';
2 |
3 | export const id = 'svelte';
4 | export const displayName = 'Svelte';
5 | export const mimeTypes = ['text/html'];
6 | export const fileExtension = 'svelte';
7 | export const editorMode = 'htmlmixed';
8 |
--------------------------------------------------------------------------------
/website/src/parsers/svelte/svelte-parser.js:
--------------------------------------------------------------------------------
1 | export { default } from '../html/svelte';
2 |
--------------------------------------------------------------------------------
/website/src/parsers/thrift/codeExample.txt:
--------------------------------------------------------------------------------
1 | namespace js test
2 |
3 | const string test = 'test'
4 |
5 | struct MyStruct {
6 | 1: optional string test
7 | }
8 |
9 | service MyService {
10 | void ping()
11 | }
12 |
--------------------------------------------------------------------------------
/website/src/parsers/thrift/index.js:
--------------------------------------------------------------------------------
1 | export const id = 'thrift-idl';
2 | export const displayName = 'Thrift IDL';
3 | export const mimeTypes = ['text/x-thrift-idl'];
4 | export const fileExtension = 'thrift';
5 |
--------------------------------------------------------------------------------
/website/src/parsers/thrift/thrift-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from '@creditkarma/thrift-parser/package.json';
3 |
4 | const ID = 'ck-thrift-parser';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: 'https://github.com/creditkarma/thrift-parser',
13 | locationProps: new Set(['location']),
14 |
15 | loadParser(callback) {
16 | require(['@creditkarma/thrift-parser'], callback);
17 | },
18 |
19 | parse({parse}, code) {
20 | return parse(code);
21 | },
22 |
23 | getNodeName(node) {
24 | return node.type;
25 | },
26 |
27 | nodeToRange({ loc }) {
28 | if (loc !== null && loc !== undefined) {
29 | return [loc.start.index, loc.end.index];
30 | }
31 | },
32 |
33 | opensByDefault(node, key) {
34 | return node === 'ThriftDocument' || key === 'body';
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/website/src/parsers/transpilers/babel.js:
--------------------------------------------------------------------------------
1 | import * as babel from 'babel-core';
2 | import es2015 from 'babel-preset-es2015';
3 | import stage0 from 'babel-preset-stage-0';
4 | import flowStripTypes from 'babel-plugin-transform-flow-strip-types';
5 | import protect from '../utils/protectFromLoops';
6 |
7 | const options = {
8 | presets: [es2015, stage0],
9 | plugins: [flowStripTypes],
10 | ast: false,
11 | babelrc: false,
12 | highlightCode: false,
13 | };
14 |
15 | export default function transpile(code) {
16 | let es5Code = babel.transform(code, options).code;
17 | es5Code = protect(es5Code);
18 | return es5Code;
19 | }
20 |
--------------------------------------------------------------------------------
/website/src/parsers/transpilers/typescript.js:
--------------------------------------------------------------------------------
1 | import ts from 'typescript';
2 | import protect from '../utils/protectFromLoops';
3 |
4 | let compilerOptions = { module: ts.ModuleKind.System };
5 |
6 | export default function transpile(code) {
7 | let es5Code = ts.transpileModule(code, compilerOptions).outputText;
8 | es5Code = protect(es5Code);
9 | return es5Code;
10 | }
11 |
--------------------------------------------------------------------------------
/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/utils/protectFromLoops.js:
--------------------------------------------------------------------------------
1 | import halts, {loopProtect} from 'halting-problem';
2 |
3 | export default function protect(jsCode) {
4 | // assert that there are no obvious infinite loops
5 | halts(jsCode);
6 | // guard against non-obvious loops with a timeout of 5 seconds
7 | let start = Date.now();
8 | jsCode = loopProtect(
9 | jsCode,
10 | [
11 | // this function gets called in all possible loops
12 | // it gets passed the line number as its only argument
13 | '(function (line) {',
14 | 'if (Date.now() > ' + (start + 5000) + ') {',
15 | ' throw new Error("Infinite loop detected on line " + line);',
16 | '}',
17 | '})',
18 | ].join(''),
19 | );
20 |
21 | return jsCode;
22 | }
23 |
--------------------------------------------------------------------------------
/website/src/parsers/vue/codeExample.txt:
--------------------------------------------------------------------------------
1 |
2 | {{ greeting }} World!
3 |
4 |
5 |
14 |
15 |
21 |
--------------------------------------------------------------------------------
/website/src/parsers/vue/index.js:
--------------------------------------------------------------------------------
1 | import 'codemirror/mode/vue/vue';
2 |
3 | export const id = 'vue';
4 | export const displayName = 'Vue';
5 | export const mimeTypes = [];
6 | export const fileExtension = 'vue';
7 |
--------------------------------------------------------------------------------
/website/src/parsers/vue/vue-compiler-dom.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from '@vue/compiler-dom/package.json';
3 |
4 | const ID = '@vue/compiler-dom';
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(['start', 'end']),
14 | typeProps: new Set(['tag']),
15 |
16 | loadParser(callback) {
17 | require(['@vue/compiler-dom'], callback);
18 | },
19 |
20 | parse(parser, code, options) {
21 | return parser.parse(code, options);
22 | },
23 |
24 | nodeToRange(node) {
25 | if (node.type || node.name) {
26 | return [node.loc.start.offset, node.loc.end.offset];
27 | }
28 | },
29 |
30 | opensByDefault(node, key) {
31 | return key === 'children';
32 | },
33 |
34 | getNodeName(node) {
35 | return node.tag;
36 | },
37 |
38 | getDefaultOptions() {
39 | return {};
40 | },
41 |
42 | _ignoredProperties: new Set([
43 | 'components',
44 | 'directives',
45 | 'codegenNode',
46 | 'helpers',
47 | 'hoists',
48 | 'imports',
49 | 'cached',
50 | 'temps',
51 | ]),
52 | };
53 |
--------------------------------------------------------------------------------
/website/src/parsers/vue/vue-eslint-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'vue-eslint-parser/package.json';
3 |
4 | const ID = 'vue-eslint-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(['start', 'end']),
14 | typeProps: new Set(['tag']),
15 |
16 | loadParser(callback) {
17 | require(['vue-eslint-parser'], callback);
18 | },
19 |
20 | parse(parser, code, options) {
21 | if (Object.keys(options).length === 0) {
22 | options = this.getDefaultOptions();
23 | }
24 | return parser.parse(code, options);
25 | },
26 |
27 | nodeToRange(node) {
28 | if (node.type || node.name) {
29 | return node.range;
30 | }
31 | },
32 |
33 | opensByDefault(node, key) {
34 | return key === 'children';
35 | },
36 |
37 | getNodeName(node) {
38 | return node.tag;
39 | },
40 |
41 | getDefaultOptions() {
42 | return {
43 | ecmaVersion: 10,
44 | sourceType: 'module',
45 | vueFeatures: {
46 | filter: true,
47 | interpolationAsNonHTML: false,
48 | },
49 | };
50 | },
51 |
52 | _getSettingsConfiguration() {
53 | const defaultOptions = this.getDefaultOptions();
54 |
55 | return {
56 | fields: [
57 | ['ecmaVersion', [3, 5, 6, 7, 8, 9, 10, 11], value => Number(value)],
58 | ['sourceType', ['script', 'module']],
59 | {
60 | key: 'vueFeatures',
61 | title: 'vueFeatures',
62 | fields: Object.keys(defaultOptions.vueFeatures),
63 | settings:
64 | settings => settings.vueFeatures || {...defaultOptions.vueFeatures},
65 | },
66 | ],
67 | };
68 | },
69 |
70 | _ignoredProperties: new Set(['parent', 'tokens']),
71 | };
72 |
--------------------------------------------------------------------------------
/website/src/parsers/vue/vue-template-compiler.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'vue-template-compiler/package.json';
3 |
4 | const ID = 'vue-template-compiler';
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(['start', 'end']),
14 | typeProps: new Set(['tag']),
15 |
16 | loadParser(callback) {
17 | require(['vue-template-compiler/browser'], callback);
18 | },
19 |
20 | parse(parser, code, options) {
21 | return parser.compile(code, options).ast;
22 | },
23 |
24 | nodeToRange(node) {
25 | if (node.type || node.name) {
26 | return [node.start, node.end];
27 | }
28 | },
29 |
30 | opensByDefault(node, key) {
31 | return key === 'children';
32 | },
33 |
34 | getNodeName(node) {
35 | return node.tag;
36 | },
37 |
38 | getDefaultOptions() {
39 | return {
40 | outputSourceRange: true,
41 | whitespace: 'preserve',
42 | };
43 | },
44 | _ignoredProperties: new Set(['parent']),
45 | };
46 |
--------------------------------------------------------------------------------
/website/src/parsers/wat/codeExample.txt:
--------------------------------------------------------------------------------
1 | ;; This is WebAssembly Text Format (WAT).
2 | ;; Paste or drop some WAT here and explore
3 |
4 | (module
5 |
6 | ;; this is simple function that adds a couple of parameters
7 | (func (param $a i32) (param $b i32)
8 | (get_local $a)
9 | (get_local $b)
10 | (i32.add)
11 | )
12 |
13 | ;; this statement exports the function to the host environment
14 | (export "add" (func $add))
15 | )
--------------------------------------------------------------------------------
/website/src/parsers/wat/index.js:
--------------------------------------------------------------------------------
1 | export const id = 'wat';
2 | export const displayName = 'WAT';
3 | export const mimeTypes = ['application/wasm'];
4 | export const fileExtension = 'wat';
5 |
--------------------------------------------------------------------------------
/website/src/parsers/wat/wat-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from '@webassemblyjs/wast-parser/package.json';
3 |
4 | const ID = 'wat-parser';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: 'https://webassembly.js.org/',
13 |
14 | locationProps: new Set(['loc']),
15 |
16 | getOffset({ line, column }) {
17 | return this.lineOffsets[line - 1] + column;
18 | },
19 |
20 | nodeToRange({ loc }) {
21 | if (!loc) return;
22 | return [loc.start, loc.end].map(pos => this.getOffset(pos));
23 | },
24 |
25 | loadParser(callback) {
26 | require(['@webassemblyjs/wast-parser'], function(parser) {
27 | callback(parser);
28 | });
29 | },
30 |
31 | parse({ parse }, code) {
32 | this.lineOffsets = [];
33 | let index = 0;
34 | do {
35 | this.lineOffsets.push(index);
36 | } while (index = code.indexOf('\n', index) + 1); // eslint-disable-line no-cond-assign
37 | return parse(code);
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/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/webidl/webidl2.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'webidl2/package.json';
3 |
4 | const ID = 'webidl2';
5 |
6 | export default {
7 | ...defaultParserInterface,
8 |
9 | id: ID,
10 | displayName: ID,
11 | version: pkg.version,
12 | homepage: pkg.homepage || 'https://github.com/w3c/webidl2.js',
13 | typeProps: new Set(['name', 'type', 'idlType', 'escapedName']),
14 |
15 | getNodeName(node) {
16 | if (node.name) {
17 | return node.name + (node.optional ? '?' : '');
18 | } else if (node.type) {
19 | return node.type;
20 | } else if (node.idlType) {
21 | return node.idlType.idlType || node.idlType;
22 | }
23 | },
24 |
25 | loadParser(callback) {
26 | require(['webidl2'], callback);
27 | },
28 |
29 | parse({ parse }, code, options) {
30 | return parse(code, options);
31 | },
32 |
33 | opensByDefault(node, key) {
34 | return key === 'members';
35 | },
36 |
37 | getDefaultOptions() {
38 | return {
39 | concrete: false,
40 | };
41 | },
42 | };
43 |
--------------------------------------------------------------------------------
/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/yaml/yaml-ast-parser.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'yaml-ast-parser/package.json';
3 |
4 | const ID = 'yaml-ast-parser';
5 | let Kind = null;
6 |
7 | export default {
8 | ...defaultParserInterface,
9 |
10 | id: ID,
11 | displayName: ID,
12 | version: pkg.version,
13 | homepage: pkg.homepage || 'https://www.npmjs.com/package/yaml-ast-parser',
14 |
15 | _ignoredProperties: new Set(['parent', 'errors']),
16 | locationProps: new Set(['startPosition', 'endPosition']),
17 | typeProps: new Set(['kind']),
18 |
19 | nodeToRange(node) {
20 | if (typeof node.startPosition === 'number') {
21 | return [node.startPosition, node.endPosition];
22 | }
23 | },
24 |
25 | getNodeName(node) {
26 | return Kind[node.kind];
27 | },
28 |
29 | loadParser(callback) {
30 | require(['yaml-ast-parser'], function(yamlAstParser) {
31 | Kind = yamlAstParser.Kind;
32 | callback(yamlAstParser);
33 | });
34 | },
35 |
36 | parse({ load }, code) {
37 | return load(code);
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/website/src/parsers/yaml/yaml.js:
--------------------------------------------------------------------------------
1 | import defaultParserInterface from '../utils/defaultParserInterface';
2 | import pkg from 'yaml/package.json';
3 |
4 | const ID = 'yaml';
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(['position']),
14 |
15 | loadParser(callback) {
16 | require(['yaml'], callback);
17 | },
18 |
19 | nodeToRange(node) {
20 | if (node.range) {
21 | return node.range;
22 | }
23 | if (node.type === 'PAIR' && (node.key || node.value)) {
24 | if (node.key && node.value) {
25 | return [node.key.range[0], node.value.range[1]];
26 | } else if (node.key) {
27 | return node.key.range;
28 | } else {
29 | return node.value.range;
30 | }
31 | }
32 | },
33 |
34 | parse({ parseAllDocuments }, code, options) {
35 | return parseAllDocuments(code, options);
36 | },
37 |
38 | getDefaultOptions() {
39 | return {
40 | keepBlobsInJSON: true,
41 | keepCstNodes: false,
42 | keepNodeTypes: true,
43 | merge: false,
44 | mapAsMap: false,
45 | simpleKeys: false,
46 | maxAliasCount: 100,
47 | prettyErrors: true,
48 | };
49 | },
50 | };
51 |
--------------------------------------------------------------------------------
/website/src/shims/jest-validate.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | validate(){},
3 | };
4 |
--------------------------------------------------------------------------------
/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/storage/index.js:
--------------------------------------------------------------------------------
1 | export default class StorageHandler {
2 | constructor(backends) {
3 | this._backends = backends;
4 | }
5 |
6 | _first() {
7 | return this._backends[0];
8 | }
9 |
10 | _owns(revision) {
11 | for (const backend of this._backends) {
12 | if (backend.owns(revision)) {
13 | return backend;
14 | }
15 | }
16 | return null;
17 | }
18 |
19 | updateHash(revision) {
20 | global.location.hash = revision.getPath();
21 | }
22 |
23 | fetchFromURL() {
24 | if (/^#?\/?$/.test(global.location.hash)) {
25 | return Promise.resolve(null);
26 | }
27 | for (const backend of this._backends) {
28 | if (backend.matchesURL()) {
29 | return backend.fetchFromURL();
30 | }
31 | }
32 | return Promise.reject(new Error('Unknown URL format.'));
33 | }
34 |
35 | /**
36 | * Create a new snippet.
37 | */
38 | create(data) {
39 | return this._first().create(data);
40 | }
41 |
42 | /**
43 | * Update an existing snippet.
44 | */
45 | update(revision, data) {
46 | return this._first().update(revision, data);
47 | }
48 |
49 | /**
50 | * Fork existing snippet.
51 | */
52 | fork(revision, data) {
53 | return this._first().fork(revision, data);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/website/src/utils/classnames.js:
--------------------------------------------------------------------------------
1 | export default function cx(...configs) {
2 | return configs.map(
3 | config => typeof config === 'string' ?
4 | config :
5 | Object.keys(config).filter(k => config[k]).join(' '),
6 | ).join(' ');
7 | }
8 |
--------------------------------------------------------------------------------
/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/utils/pubsub.js:
--------------------------------------------------------------------------------
1 | const subscribers = {};
2 |
3 | export function subscribe(topic, handler) {
4 | let handlers = subscribers[topic];
5 | if (!handlers) {
6 | handlers = subscribers[topic] = [];
7 | }
8 | if (handlers.indexOf(handler) === -1) {
9 | handlers.push(handler);
10 | }
11 |
12 | return () => handlers.splice(handlers.indexOf(handler), 1);
13 | }
14 |
15 | export function publish(topic, data) {
16 | if (subscribers[topic]) {
17 | setTimeout(function callSubscribers() {
18 | if (subscribers[topic]) {
19 | const handlers = subscribers[topic];
20 | for (var i = 0; i < handlers.length; i++) {
21 | handlers[i](data);
22 | }
23 | }
24 | }, 0);
25 | }
26 | }
27 |
28 | export function clear(unsubscribers) {
29 | unsubscribers.forEach(call);
30 | }
31 |
32 | function call(f) {
33 | return f();
34 | }
35 |
--------------------------------------------------------------------------------
/website/src/utils/stringify.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Converts a JS value to a sensible string representation.
3 | */
4 | export default function stringify(value) {
5 | switch (typeof value) {
6 | case 'function':
7 | return value.toString().match(/function[^(]*\([^)]*\)/)[0];
8 | case 'object':
9 | return value ? JSON.stringify(value, stringify) : 'null';
10 | case 'undefined':
11 | return 'undefined';
12 | case 'number':
13 | case 'bigint':
14 | return Number.isNaN(value) ? 'NaN' : String(value);
15 | default:
16 | return JSON.stringify(value);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------