Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@
"npm-run-all": "^4.1.5",
"parcel-bundler": "^1.12.5",
"parcel-plugin-inliner": "^1.0.16",
"php-array-parser": "^1.0.1",
"php-parser": "^3.0.3",
"php-parser": "^3.2.2",
"pug": "^3.0.3",
"rimraf": "^3.0.2",
"standard-version": "^9.3.1",
Expand Down
56 changes: 31 additions & 25 deletions src/parsers/json.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,57 @@
import SortedStringify from 'json-stable-stringify'
import SortedStringify from "json-stable-stringify";
// @ts-ignore
import JsonMap from 'json-source-map'
import { Parser } from './base'
import JsonMap from "json-source-map";
import { Parser } from "./base";

export class JsonParser extends Parser {
id = 'json'
id = "json";

constructor() {
super(['json'], 'json')
super(["json"], "json");
}

async parse(text: string) {
if (!text || !text.trim())
return {}
return JSON.parse(text)
if (!text || !text.trim()) return {};
return JSON.parse(text);
}

async dump(object: object, sort: boolean, compare: ((x: string, y: string) => number) | undefined) {
const indent = this.options.tab === '\t' ? this.options.tab : this.options.indent
async dump(
object: object,
sort: boolean,
compare: ((x: string, y: string) => number) | undefined
) {
const indent =
this.options.tab === "\t" ? this.options.tab : this.options.indent;

if (sort)
return `${SortedStringify(object, { space: indent, cmp: compare ? (a, b) => compare(a.key, b.key) : undefined })}\n`
else
return `${JSON.stringify(object, null, indent)}\n`
return `${SortedStringify(object, {
space: indent,
cmp: compare ? (a, b) => compare(a.key, b.key) : undefined
})}\n`;
else return `${JSON.stringify(object, null, indent)}\n`;
}

annotationSupported = true
annotationLanguageIds = ['json']
annotationSupported = true;
annotationLanguageIds = ["json"];

parseAST(text: string) {
if (!text || !text.trim())
return []
if (!text || !text.trim()) return [];

const map = JsonMap.parse(text).pointers
const map = JsonMap.parse(text).pointers;
const pairs = Object.entries<any>(map)
.filter(([k, v]) => k)
.map(([k, v]) => ({
quoted: true,
start: v.value.pos + 1,
end: v.valueEnd.pos - 1,
// https://tools.ietf.org/html/rfc6901
key: k.slice(1)
.replace(/\//g, '.')
.replace(/~0/g, '~')
.replace(/~1/g, '/'),
}))

return pairs
key: k
.slice(1)
.replace(/\//g, ".")
.replace(/~0/g, "~")
.replace(/~1/g, "/")
}));

return pairs;
}
}
187 changes: 180 additions & 7 deletions src/parsers/php.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,197 @@
// @ts-ignore
import parser from 'php-array-parser'
import {
Array as PhpArray,
Engine,
Entry,
Node,
Return,
String,
} from 'php-parser'
import { Parser } from './base'
import { KeyInDocument } from '~/core'

export class PhpParser extends Parser {
id = 'php'
readonly = true
readonly = false
phpParser: Engine = new Engine({
// some options :
parser: {
extractDoc: true,
php7: true,
},
ast: {
withPositions: true,
},
})

constructor() {
super(['php'], 'php')
}

async parse(text: string) {
// Remove left part of return expression and any ending `?>`.
const ret = text.indexOf('return') + 'return'.length
text = text.substr(ret)
text = text.replace(/\?>\s*$/, '_')
return parser.parse(text)
const programme = this.phpParser.parseCode(text, '')
if (!programme.children.length && programme.children[0].kind != 'return')
return {}

const returnChild = programme.children[0] as Return
if (returnChild.expr?.kind != 'array')
return {}

const returnExpression = returnChild.expr

return this.parsePhpArray(returnExpression)
}

async dump(
object: object,
sort: boolean,
compare: ((x: string, y: string) => number) | undefined,
) {
const indent
= this.options.tab === '\t'
? this.options.tab
: ' '.repeat(this.options.indent)

return `<?php

${indent.repeat(1)}return ${this.arrayToPhp(object, indent, 2, sort, compare)};

`
}

annotationSupported = true
annotationLanguageIds = ['php']

parseAST(text: string) {
const programme = this.phpParser.parseCode(text, '')
if (!programme.children.length && programme.children[0].kind != 'return')
return []

const returnChild = programme.children[0] as Return
if (returnChild.expr?.kind != 'array')
return []

const returnExpression = returnChild.expr

return this.phpToAST(returnExpression, '')
}

private phpToAST(initialData: Node, parent: string): KeyInDocument[] {
if (initialData.kind != 'array')
return []

const array = initialData as PhpArray
return array.items
.filter((item) => {
const entery = item as Entry
if (item.kind != 'entry')
return false

if (entery.key?.kind != 'string')
return false

if (entery.value?.kind != 'string' && entery.value?.kind != 'array')
return false

if (!entery.value.loc)
return false

return true
})
.map((item): KeyInDocument | KeyInDocument[] => {
const entery = item as Entry
const keyString = ((entery.key as unknown) as String).value

if (entery.value.kind === 'array')
return this.phpToAST(entery.value, keyString)

return {
quoted: true,
key: parent ? `${parent}.${keyString}` : keyString,
start: entery.value.loc?.start.offset ?? 0,
end: entery.value.loc?.end.offset ?? 0,
}
})
.flatMap(item => (Array.isArray(item) ? item : [item]))
}

async dump() {
private parsePhpArray(initialData: Node) {
if (initialData.kind != 'array')
return {}

const returnValue = {} as Record<string, any>
const array = initialData as PhpArray

array.items.forEach((item) => {
const entery = item as Entry

if (item.kind != 'entry')
return

if (entery.key?.kind != 'string')
return

const keyString = ((entery.key as unknown) as String).value

if (entery.value?.kind != 'string' && entery.value?.kind != 'array')
return

if (entery.value.kind === 'string')
returnValue[keyString] = ((entery.value as unknown) as String).value
else if (entery.value.kind === 'array')
returnValue[keyString] = this.parsePhpArray(entery.value)
})

return returnValue
}

private arrayToPhp(
object: object,
identEl: string,
indent: number,
sort: boolean,
compare: ((x: string, y: string) => number) | undefined,
): string {
if (typeof object === 'string')
return `"${object}"`

if (typeof object === 'boolean')
return object ? 'true' : 'false'

if (typeof object === 'number')
return object

const indentation = identEl.repeat(indent)

if (typeof object === 'object') {
const entries = Object.entries(object)
if (sort) {
entries.sort(([keyA], [keyB]) =>
compare ? compare(keyA, keyB) : keyA.localeCompare(keyB),
)
}

return (
`[\n${
entries
.map(
([key, value]) =>
`${indentation} "${key}" => ${this.arrayToPhp(
value,
identEl,
indent + 1,
sort,
compare,
)}`,
)
.join(',\n')
}\n${
indentation
}]`
)
}

return ''
}
}
20 changes: 4 additions & 16 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8411,22 +8411,10 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=

php-array-parser@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/php-array-parser/-/php-array-parser-1.0.1.tgz#9da12683c3bebbe228a7e238c716435437631eaa"
integrity sha512-elnanzvSd/+U2eWD9Hp2MIab6LzWlnp9J+sTrQasDoR6VsWMDa3fDYBS8pojvu3RwPbpgDUHUxV5WGhfJ1NewQ==
dependencies:
php-parser "^2.0.3"

php-parser@^2.0.3:
version "2.2.0"
resolved "https://registry.yarnpkg.com/php-parser/-/php-parser-2.2.0.tgz#67384f0a5933dbbef40beab0ab31d0b8c582ff88"
integrity sha1-ZzhPClkz2770C+qwqzHQuMWC/4g=

php-parser@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/php-parser/-/php-parser-3.0.3.tgz#287779ea8a273ec5cf926f28e5f38ffa4ad32d4a"
integrity sha512-WjbrtYrwmLY9hpoKoq1+mVqJhT0dEVDZRWSpNIw2MpTw3VM/K4C6e0WR4KlU6G/XROkV7tpH4NesV2dDiPxqaw==
php-parser@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/php-parser/-/php-parser-3.2.2.tgz#49c6fac29fbf8f995e1b8609ad52bd41b1ecda07"
integrity sha512-voj3rzCJmEbwHwH3QteON28wA6K+JbcaJEofyUZkUXmcViiXofjbSbcE5PtqtjX6nstnnAEYCFoRq0mkjP5/cg==

physical-cpu-count@^2.0.0:
version "2.0.0"
Expand Down