芝麻web文件管理V1.00
编辑当前文件:/home/freeclou/optimyar/wp-content/plugins/code-snippets/js/utils/Linter.ts
/** * Based on work licensed under the BSD 3-Clause license. * * Copyright (c) 2017, glayzzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import { Engine } from 'php-parser' import CodeMirror from 'codemirror' import type { Block, Location, Node } from 'php-parser' export interface Annotation { message: string severity: string from: CodeMirror.Position to: CodeMirror.Position } export interface Identifier extends Node { name: string } export interface Declaration extends Node { name: Identifier | string } export class Linter { private readonly code: string private readonly function_names: Set
private readonly class_names: Set
public readonly annotations: Annotation[] /** * Constructor. * @param code */ constructor(code: string) { this.code = code this.annotations = [] this.function_names = new Set() this.class_names = new Set() } /** * Lint the provided code. */ lint() { const parser = new Engine({ parser: { suppressErrors: true, version: 800 }, ast: { withPositions: true } }) try { const program = parser.parseEval(this.code) if (0 < program.errors.length) { for (const error of program.errors) { this.annotate(error.message, error.loc) } } this.visit(program) } catch (error) { console.error(error) } } /** * Visit nodes recursively. * @param node */ visit(node: Node) { if (node.kind) { this.validate(node) } if ('children' in node) { const block =
node for (const child of block.children) { this.visit(child) } } } /** * Check whether a given identifier has already been defined, creating an annotation if so. * @param identifier * @param registry * @param label */ checkDuplicateIdentifier(identifier: Identifier, registry: Set
, label: string) { if (registry.has(identifier.name)) { this.annotate(`Cannot redeclare ${label} ${identifier.name}()`, identifier.loc) } else { registry.add(identifier.name) } } /** * Perform additional validations on nodes. * @param node */ validate(node: Node) { const decl =
node const ident =
decl.name if (!('name' in decl && 'name' in ident) || 'identifier' !== ident.kind) { return } if ('function' === node.kind) { this.checkDuplicateIdentifier(ident, this.function_names, 'function') } else if ('class' === node.kind) { this.checkDuplicateIdentifier(ident, this.class_names, 'class') } } /** * Create a lint annotation. * @param message * @param location * @param severity */ annotate(message: string, location: Location | null, severity = 'error') { const [start, end] = location ? location.end.offset < location.start.offset ? [location.end, location.start] : [location.start, location.end] : [{ line: 0, column: 0 }, { line: 0, column: 0 }] this.annotations.push({ message, severity, from: CodeMirror.Pos(start.line - 1, start.column), to: CodeMirror.Pos(end.line - 1, end.column) }) } }