Skip to content

Commit

Permalink
Update AST
Browse files Browse the repository at this point in the history
  • Loading branch information
ota-meshi committed Dec 14, 2020
1 parent 5057048 commit e9ff377
Show file tree
Hide file tree
Showing 7 changed files with 359 additions and 25 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/GHPages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ jobs:
- uses: actions/setup-node@v1
- name: Install And Build
run: |+
npm install
npm run build
cd explorer
npm install
npm run build
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/cron.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
name: CI-cron

on:
schedule:
- cron: '30 17 * * *'
Expand Down
3 changes: 1 addition & 2 deletions explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
},
"dependencies": {
"core-js": "^3.6.5",
"vue": "^3.0.0",
"yaml-eslint-parser": "0.0.8"
"vue": "^3.0.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
Expand Down
6 changes: 4 additions & 2 deletions explorer/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<template>
<header class="header">
<label class="title">yaml-eslint-parser</label>
<SnsBar />
<a
href="https://github.com/ota-meshi/yaml-eslint-parser"
class="github-link"
>GitHub</a
>View on GitHub</a
>
</header>
<main class="main">
Expand All @@ -14,11 +15,13 @@

<script>
import AstExplorer from "./components/AstExplorer.vue"
import SnsBar from "./components/SnsBar.vue"
export default {
name: "App",
components: {
AstExplorer,
SnsBar,
},
}
</script>
Expand All @@ -35,7 +38,6 @@ export default {
align-items: center;
}
.github-link {
width: 4em;
display: flex;
align-items: center;
}
Expand Down
275 changes: 255 additions & 20 deletions explorer/src/components/AstExplorer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,29 @@
<div class="ast-explorer-root">
<AstOptions v-model="options" />
<div class="ast-explorer">
<MonacoEditor v-model="yamlValue" language="yaml" />
<MonacoEditor v-model="astJson" language="json" read-only />
<MonacoEditor
ref="sourceEditor"
v-model="yamlValue"
language="yaml"
@focus-editor-text="handleFocus('source')"
@change-cursor-position="handleCursor($event, 'source')"
/>
<MonacoEditor
ref="jsonEditor"
:model-value="astJson.json"
language="json"
read-only
@focus-editor-text="handleFocus('json')"
@change-cursor-position="handleCursor($event, 'json')"
/>
</div>
</div>
</template>

<script>
import MonacoEditor from "./MonacoEditor.vue"
import AstOptions from "./AstOptions.vue"
import * as yamlEslintParser from "yaml-eslint-parser"
import * as yamlEslintParser from "../../.."
export default {
name: "AstExplorer",
Expand All @@ -22,12 +35,13 @@ export default {
showLocations: false,
},
yamlValue: `---
# Welcome yaml-eslint-parser
message: Here you can see the AST generated by yaml-eslint-parser.
github: https://github.com/ota-meshi/yaml-eslint-parser
eslint: https://github.com/ota-meshi/eslint-plugin-yml
# Welcome to yaml-eslint-parser!!
🎉 Hello: Here you can see the AST generated by yaml-eslint-parser.
🐙 GitHub: https://github.com/ota-meshi/yaml-eslint-parser
✅ ESLint Plugin: https://github.com/ota-meshi/eslint-plugin-yml
`,
astJson: "",
astJson: {},
modeEditor: "",
}
},
watch: {
Expand All @@ -42,26 +56,247 @@ eslint: https://github.com/ota-meshi/eslint-plugin-yml
},
methods: {
refresh() {
this.astJson = JSON.stringify(
yamlEslintParser.parseForESLint(this.yamlValue).ast,
replacer.bind(null, this.options),
2,
)
let ast
try {
ast = yamlEslintParser.parseForESLint(this.yamlValue).ast
} catch (e) {
ast = {
message: e.message,
...e,
}
}
const json = createAstJson(this.options, ast)
this.astJson = json
},
handleFocus(editor) {
this.modeEditor = editor
},
handleCursor(evt, editor) {
if (this.modeEditor !== editor || !this.astJson) {
return
}
const position = evt.position
if (editor === "source") {
const locData = findLoc(this.astJson, "sourceLoc")
if (locData) {
this.$refs.jsonEditor.setCursorPosition(locData.jsonLoc)
}
} else if (editor === "json") {
const locData = findLoc(this.astJson, "jsonLoc")
if (locData) {
this.$refs.sourceEditor.setCursorPosition(
locData.sourceLoc,
{ columnOffset: 1 },
)
}
}
// eslint-disable-next-line require-jsdoc -- demo
function findLoc(astJson, locName) {
let locData = astJson.locations.find((l) =>
locInPoint(l[locName], position),
)
let nextLocData
while (
locData &&
(nextLocData = locData.locations.find((l) =>
locInPoint(l[locName], position),
))
) {
locData = nextLocData
}
return locData
}
// eslint-disable-next-line require-jsdoc -- demo
function locInPoint(loc, pos) {
if (
loc.start.line < pos.lineNumber &&
pos.lineNumber < loc.end.line
) {
return true
}
if (
loc.start.line === pos.lineNumber &&
pos.lineNumber === loc.end.line
) {
return (
loc.start.column <= pos.column &&
pos.column < loc.end.column
)
}
if (
loc.start.line === pos.lineNumber &&
pos.lineNumber < loc.end.line
) {
return loc.start.column <= pos.column
}
if (
loc.start.line < pos.lineNumber &&
pos.lineNumber === loc.end.line
) {
return pos.column < loc.end.column
}
return false
}
},
},
}
class AstJsonContext {
constructor() {
this.json = ""
this.jsonPosition = { line: 1, column: 1 }
this.locations = []
this._indentOffset = 0
this._stack = null
}
pushNode(node) {
this._stack = {
upper: this._stack,
node,
jsonLocStart: { ...this.jsonPosition },
locations: [],
}
}
popNode() {
const loc = {
node: this._stack.node,
sourceLoc: this._stack.node.loc,
jsonLoc: {
start: this._stack.jsonLocStart,
end: { ...this.jsonPosition },
},
locations: this._stack.locations,
}
this._stack = this._stack.upper
if (this._stack) {
this._stack.locations.push(loc)
} else {
this.locations.push(loc)
}
}
appendText(text) {
const str = String(text)
this.json += str
const lines = str.split("\n")
if (lines.length > 1) {
this.jsonPosition = {
line: this.jsonPosition.line + lines.length - 1,
column: lines.pop().length + 1,
}
} else {
this.jsonPosition.column += str.length
}
return this
}
appendIndent() {
return this.appendText(" ".repeat(this._indentOffset))
}
indent() {
this._indentOffset++
return this
}
outdent() {
this._indentOffset--
return this
}
}
/**
* replacer for AST JSON
* Build AST JSON
*/
function replacer(options, key, val) {
if (key === "parent") {
return undefined
function createAstJson(options, value) {
const ctx = new AstJsonContext()
processValue(options, ctx, value)
return ctx
}
// eslint-disable-next-line require-jsdoc -- ignore
function processValue(options, ctx, value) {
const type = typeof value
if (
type === "string" ||
type === "number" ||
type === "boolean" ||
value === null
) {
ctx.appendText(JSON.stringify(value))
return
} else if (type !== "object") {
ctx.appendText('"?"')
return
}
if (!options.showLocations) {
if (key === "range" || key === "loc") return undefined
if (Array.isArray(value)) {
ctx.appendText("[\n").indent()
const arr = [...value]
while (arr.length) {
ctx.appendIndent()
const e = arr.shift()
processValue(options, ctx, e)
if (arr.length) {
ctx.appendText(",")
}
ctx.appendText("\n")
}
ctx.outdent().appendIndent().appendText("]")
} else {
let entries = Object.entries(value)
const valueIsNode = isNode(value)
if (valueIsNode) {
ctx.pushNode(value)
const typeEntry = entries.find(([key]) => key === "type")
const locEntries = options.showLocations
? entries.filter(([key]) => key === "loc" || key === "range")
: []
entries = entries.filter(
([key]) =>
key !== "type" &&
key !== "loc" &&
key !== "range" &&
key !== "parent",
)
if (typeEntry) entries.unshift(typeEntry)
entries.push(...locEntries)
}
ctx.appendText("{\n").indent()
while (entries.length) {
ctx.appendIndent()
const [key, val] = entries.shift()
processValue(options, ctx, key)
ctx.appendText(": ")
processValue(options, ctx, val)
if (entries.length) {
ctx.appendText(",")
}
ctx.appendText("\n")
}
ctx.outdent().appendIndent().appendText("}")
if (valueIsNode) {
ctx.popNode()
}
}
return val
}
/**
* Check if given value is node
*/
function isNode(value) {
return (
value != null &&
Array.isArray(value.range) &&
"loc" in value &&
"type" in value
)
}
</script>

Expand Down

0 comments on commit e9ff377

Please sign in to comment.