Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/dceprojects.corals.io/vendor/nesk/puphpeteer/src/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/dceprojects.corals.io/vendor/nesk/puphpeteer/src/doc-generator.ts
import * as ts from 'typescript';
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');

type ObjectMemberAsJson = { [key: string]: string; }

type ObjectMembersAsJson = {
    properties: ObjectMemberAsJson,
    getters: ObjectMemberAsJson,
    methods: ObjectMemberAsJson,
}

type ClassAsJson = { name: string } & ObjectMembersAsJson
type MemberContext = 'class'|'literal'
type TypeContext = 'methodReturn'

class TypeNotSupportedError extends Error {
    constructor(message?: string) {
        super(message || 'This type is currently not supported.');
    }
}

interface SupportChecker {
    supportsMethodName(methodName: string): boolean;
}

class JsSupportChecker {
    supportsMethodName(methodName: string): boolean {
        return true;
    }
}

class PhpSupportChecker {
    supportsMethodName(methodName: string): boolean {
        return !methodName.includes('$');
    }
}

interface DocumentationFormatter {
    formatProperty(name: string, type: string, context: MemberContext): string
    formatGetter(name: string, type: string): string
    formatAnonymousFunction(parameters: string, returnType: string): string
    formatFunction(name: string, parameters: string, returnType: string): string
    formatParameter(name: string, type: string, isVariadic: boolean, isOptional: boolean): string
    formatTypeAny(): string
    formatTypeUnknown(): string
    formatTypeVoid(): string
    formatTypeUndefined(): string
    formatTypeNull(): string
    formatTypeBoolean(): string
    formatTypeNumber(): string
    formatTypeString(): string
    formatTypeReference(type: string): string
    formatGeneric(parentType: string, argumentTypes: string[], context?: TypeContext): string
    formatQualifiedName(left: string, right: string): string
    formatIndexedAccessType(object: string, index: string): string
    formatLiteralType(value: string): string
    formatUnion(types: string[]): string
    formatIntersection(types: string[]): string
    formatObject(members: string[]): string
    formatArray(type: string): string
}

class JsDocumentationFormatter implements DocumentationFormatter {
    formatProperty(name: string, type: string, context: MemberContext): string {
        return `${name}: ${type}`;
    }

    formatGetter(name: string, type: string): string {
        return `${name}: ${type}`;
    }

    formatAnonymousFunction(parameters: string, returnType: string): string {
        return `(${parameters}) => ${returnType}`;
    }

    formatFunction(name: string, parameters: string, returnType: string): string {
        return `${name}(${parameters}): ${returnType}`;
    }

    formatParameter(name: string, type: string, isVariadic: boolean, isOptional: boolean): string {
        return `${isVariadic ? '...' : ''}${name}${isOptional ? '?' : ''}: ${type}`;
    }

    formatTypeAny(): string {
        return 'any';
    }

    formatTypeUnknown(): string {
        return 'unknown';
    }

    formatTypeVoid(): string {
        return 'void';
    }

    formatTypeUndefined(): string {
        return 'undefined';
    }

    formatTypeNull(): string {
        return 'null';
    }

    formatTypeBoolean(): string {
        return 'boolean';
    }

    formatTypeNumber(): string {
        return 'number';
    }

    formatTypeString(): string {
        return 'string';
    }

    formatTypeReference(type: string): string {
        return type;
    }

    formatGeneric(parentType: string, argumentTypes: string[], context?: TypeContext): string {
        return `${parentType}<${argumentTypes.join(', ')}>`;
    }

    formatQualifiedName(left: string, right: string): string {
        return `${left}.${right}`;
    }

    formatIndexedAccessType(object: string, index: string): string {
        return `${object}[${index}]`;
    }

    formatLiteralType(value: string): string {
        return `'${value}'`;
    }

    formatUnion(types: string[]): string {
        return types.join(' | ');
    }

    formatIntersection(types: string[]): string {
        return types.join(' & ');
    }

    formatObject(members: string[]): string {
        return `{ ${members.join(', ')} }`;
    }

    formatArray(type: string): string {
        return `${type}[]`;
    }
}

class PhpDocumentationFormatter implements DocumentationFormatter {
    static readonly allowedJsClasses = ['Promise', 'Record', 'Map'];

    constructor(
        private readonly resourcesNamespace: string,
        private readonly resources: string[],
    ) {}

    formatProperty(name: string, type: string, context: MemberContext): string {
        return context === 'class'
            ? `${type} ${name}`
            : `${name}: ${type}`;
    }

    formatGetter(name: string, type: string): string {
        return `${type} ${name}`;
    }

    formatAnonymousFunction(parameters: string, returnType: string): string {
        return `callable(${parameters}): ${returnType}`;
    }

    formatFunction(name: string, parameters: string, returnType: string): string {
        return `${returnType} ${name}(${parameters})`;
    }

    formatParameter(name: string, type: string, isVariadic: boolean, isOptional: boolean): string {
        if (isVariadic && type.endsWith('[]')) {
            type = type.slice(0, -2);
        }

        const defaultValue = isOptional ? ' = null' : '';
        return `${type} ${isVariadic ? '...' : ''}\$${name}${defaultValue}`;
    }

    formatTypeAny(): string {
        return 'mixed';
    }

    formatTypeUnknown(): string {
        return 'mixed';
    }

    formatTypeVoid(): string {
        return 'void';
    }

    formatTypeUndefined(): string {
        return 'null';
    }

    formatTypeNull(): string {
        return 'null';
    }

    formatTypeBoolean(): string {
        return 'bool';
    }

    formatTypeNumber(): string {
        return 'float';
    }

    formatTypeString(): string {
        return 'string';
    }

    formatTypeReference(type: string): string {
        // Allow some specific JS classes to be used in phpDoc
        if (PhpDocumentationFormatter.allowedJsClasses.includes(type)) {
            return type;
        }

        // Prefix PHP resources with their namespace
        if (this.resources.includes(type)) {
            return `\\${this.resourcesNamespace}\\${type}`;
        }

        // If the type ends with "options" then convert it to an associative array
        if (/options$/i.test(type)) {
            return 'array<string, mixed>';
        }

        // Types ending with "Fn" are always callables or strings
        if (type.endsWith('Fn')) {
            return this.formatUnion(['callable', 'string']);
        }

        if (type === 'Function') {
            return 'callable';
        }

        if (type === 'PuppeteerLifeCycleEvent') {
            return 'string';
        }

        if (type === 'Serializable') {
            return this.formatUnion(['int', 'float', 'string', 'bool', 'null', 'array']);
        }

        if (type === 'SerializableOrJSHandle') {
            return this.formatUnion([this.formatTypeReference('Serializable'), this.formatTypeReference('JSHandle')]);
        }

        if (type === 'HandleType') {
            return this.formatUnion([this.formatTypeReference('JSHandle'), this.formatTypeReference('ElementHandle')]);
        }

        return 'mixed';
    }

    formatGeneric(parentType: string, argumentTypes: string[], context?: TypeContext): string {
        // Avoid generics with "mixed" as parent type
        if (parentType === 'mixed') {
            return 'mixed';
        }

        // Unwrap promises for method return types
        if (context === 'methodReturn' && parentType === 'Promise' && argumentTypes.length === 1) {
            return argumentTypes[0];
        }

        // Transform Record and Map types to associative arrays
        if (['Record', 'Map'].includes(parentType) && argumentTypes.length === 2) {
            parentType = 'array';
        }

        return `${parentType}<${argumentTypes.join(', ')}>`;
    }

    formatQualifiedName(left: string, right: string): string {
        return `mixed`;
    }

    formatIndexedAccessType(object: string, index: string): string {
        return `mixed`;
    }

    formatLiteralType(value: string): string {
        return `'${value}'`;
    }

    private prepareUnionOrIntersectionTypes(types: string[]): string[] {
        // Replace "void" type by "null"
        types = types.map(type => type === 'void' ? 'null' : type)

        // Remove duplicates
        const uniqueTypes = new Set(types);
        return Array.from(uniqueTypes.values());
    }

    formatUnion(types: string[]): string {
        const result = this.prepareUnionOrIntersectionTypes(types).join('|');

        // Convert enums to string type
        if (/^('\w+'\|)*'\w+'$/.test(result)) {
            return 'string';
        }

        return result;
    }

    formatIntersection(types: string[]): string {
        return this.prepareUnionOrIntersectionTypes(types).join('&');
    }

    formatObject(members: string[]): string {
        return `array{ ${members.join(', ')} }`;
    }

    formatArray(type: string): string {
        return `${type}[]`;
    }
}

class DocumentationGenerator {
    constructor(
        private readonly supportChecker: SupportChecker,
        private readonly formatter: DocumentationFormatter,
    ) {}

    private hasModifierForNode(
        node: ts.Node,
        modifier: ts.KeywordSyntaxKind
    ): boolean {
        if (!node.modifiers) {
            return false;
        }

        return node.modifiers.some((node) => node.kind === modifier);
    }

    private isNodeAccessible(node: ts.Node): boolean {
        // @ts-ignore
        if (node.name && this.getNamedDeclarationAsString(node).startsWith('_')) {
            return false;
        }

        return (
            this.hasModifierForNode(node, ts.SyntaxKind.PublicKeyword) ||
            (!this.hasModifierForNode(node, ts.SyntaxKind.ProtectedKeyword) &&
            !this.hasModifierForNode(node, ts.SyntaxKind.PrivateKeyword))
        );
    }

    private isNodeStatic(node: ts.Node): boolean {
        return this.hasModifierForNode(node, ts.SyntaxKind.StaticKeyword);
    }

    public getClassDeclarationAsJson(node: ts.ClassDeclaration): ClassAsJson {
        return Object.assign(
            { name: this.getNamedDeclarationAsString(node) },
            this.getMembersAsJson(node.members, 'class'),
        );
    }

    private getMembersAsJson(members: ts.NodeArray<ts.NamedDeclaration>, context: MemberContext): ObjectMembersAsJson {
        const json: ObjectMembersAsJson = {
            properties: {},
            getters: {},
            methods: {},
        };

        for (const member of members) {
            if (!this.isNodeAccessible(member) || this.isNodeStatic(member)) {
                continue;
            }

            const name = member.name ? this.getNamedDeclarationAsString(member) : null;

            if (ts.isPropertySignature(member) || ts.isPropertyDeclaration(member)) {
                json.properties[name] = this.getPropertySignatureOrDeclarationAsString(member, context);
            } else if (ts.isGetAccessorDeclaration(member)) {
                json.getters[name] = this.getGetAccessorDeclarationAsString(member);
            } else if (ts.isMethodDeclaration(member)) {
                if (!this.supportChecker.supportsMethodName(name)) {
                    continue;
                }
                json.methods[name] = this.getSignatureDeclarationBaseAsString(member);
            }
        }

        return json;
    }

    private getPropertySignatureOrDeclarationAsString(
        node: ts.PropertySignature | ts.PropertyDeclaration,
        context: MemberContext
    ): string {
        const type = this.getTypeNodeAsString(node.type);
        const name = this.getNamedDeclarationAsString(node);
        return this.formatter.formatProperty(name, type, context);
    }

    private getGetAccessorDeclarationAsString(
        node: ts.GetAccessorDeclaration
    ): string {
        const type = this.getTypeNodeAsString(node.type);
        const name = this.getNamedDeclarationAsString(node);
        return this.formatter.formatGetter(name, type);
    }

    private getSignatureDeclarationBaseAsString(
        node: ts.SignatureDeclarationBase
    ): string {
        const name = node.name && this.getNamedDeclarationAsString(node);
        const parameters = node.parameters
            .map(parameter => this.getParameterDeclarationAsString(parameter))
            .join(', ');

        const returnType = this.getTypeNodeAsString(node.type, name ? 'methodReturn' : undefined);

        return name
            ? this.formatter.formatFunction(name, parameters, returnType)
            : this.formatter.formatAnonymousFunction(parameters, returnType);
    }

    private getParameterDeclarationAsString(node: ts.ParameterDeclaration): string {
        const name = this.getNamedDeclarationAsString(node);
        const type = this.getTypeNodeAsString(node.type);
        const isVariadic = node.dotDotDotToken !== undefined;
        const isOptional = node.questionToken !== undefined;
        return this.formatter.formatParameter(name, type, isVariadic, isOptional);
    }

    private getTypeNodeAsString(node: ts.TypeNode, context?: TypeContext): string {
        if (node.kind === ts.SyntaxKind.AnyKeyword) {
            return this.formatter.formatTypeAny();
        } else if (node.kind === ts.SyntaxKind.UnknownKeyword) {
            return this.formatter.formatTypeUnknown();
        } else if (node.kind === ts.SyntaxKind.VoidKeyword) {
            return this.formatter.formatTypeVoid();
        } else if (node.kind === ts.SyntaxKind.UndefinedKeyword) {
            return this.formatter.formatTypeUndefined();
        } else if (node.kind === ts.SyntaxKind.NullKeyword) {
            return this.formatter.formatTypeNull();
        } else if (node.kind === ts.SyntaxKind.BooleanKeyword) {
            return this.formatter.formatTypeBoolean();
        } else if (node.kind === ts.SyntaxKind.NumberKeyword) {
            return this.formatter.formatTypeNumber();
        } else if (node.kind === ts.SyntaxKind.StringKeyword) {
            return this.formatter.formatTypeString();
        } else if (ts.isTypeReferenceNode(node)) {
            return this.getTypeReferenceNodeAsString(node, context);
        } else if (ts.isIndexedAccessTypeNode(node)) {
            return this.getIndexedAccessTypeNodeAsString(node);
        } else if (ts.isLiteralTypeNode(node)) {
            return this.getLiteralTypeNodeAsString(node);
        } else if (ts.isUnionTypeNode(node)) {
            return this.getUnionTypeNodeAsString(node, context);
        } else if (ts.isIntersectionTypeNode(node)) {
            return this.getIntersectionTypeNodeAsString(node, context);
        } else if (ts.isTypeLiteralNode(node)) {
            return this.getTypeLiteralNodeAsString(node);
        } else if (ts.isArrayTypeNode(node)) {
            return this.getArrayTypeNodeAsString(node, context);
        } else if (ts.isFunctionTypeNode(node)) {
            return this.getSignatureDeclarationBaseAsString(node);
        } else {
            throw new TypeNotSupportedError();
        }
    }

    private getTypeReferenceNodeAsString(node: ts.TypeReferenceNode, context?: TypeContext): string {
        return this.getGenericTypeReferenceNodeAsString(node, context) || this.getSimpleTypeReferenceNodeAsString(node);
    }

    private getGenericTypeReferenceNodeAsString(node: ts.TypeReferenceNode, context?: TypeContext): string | null {
        if (!node.typeArguments || node.typeArguments.length === 0) {
            return null;
        }

        const parentType = this.getSimpleTypeReferenceNodeAsString(node);
        const argumentTypes = node.typeArguments.map((node) => this.getTypeNodeAsString(node));
        return this.formatter.formatGeneric(parentType, argumentTypes, context);
    }

    private getSimpleTypeReferenceNodeAsString(node: ts.TypeReferenceNode): string {
        return ts.isIdentifier(node.typeName)
            ? this.formatter.formatTypeReference(this.getIdentifierAsString(node.typeName))
            : this.getQualifiedNameAsString(node.typeName);
    }

    private getQualifiedNameAsString(node: ts.QualifiedName): string {
        const right = this.getIdentifierAsString(node.right);
        const left = ts.isIdentifier(node.left)
            ? this.getIdentifierAsString(node.left)
            : this.getQualifiedNameAsString(node.left);

        return this.formatter.formatQualifiedName(left, right);
    }

    private getIndexedAccessTypeNodeAsString(
        node: ts.IndexedAccessTypeNode
    ): string {
        const object = this.getTypeNodeAsString(node.objectType);
        const index = this.getTypeNodeAsString(node.indexType);
        return this.formatter.formatIndexedAccessType(object, index);
    }

    private getLiteralTypeNodeAsString(node: ts.LiteralTypeNode): string {
        if (node.literal.kind === ts.SyntaxKind.NullKeyword) {
            return this.formatter.formatTypeNull();
        } else if (node.literal.kind === ts.SyntaxKind.BooleanKeyword) {
            return this.formatter.formatTypeBoolean();
        } else if (ts.isLiteralExpression(node.literal)) {
            return this.formatter.formatLiteralType(node.literal.text);
        }
        throw new TypeNotSupportedError();
    }

    private getUnionTypeNodeAsString(node: ts.UnionTypeNode, context?: TypeContext): string {
        const types = node.types.map(typeNode => this.getTypeNodeAsString(typeNode, context));
        return this.formatter.formatUnion(types);
    }

    private getIntersectionTypeNodeAsString(node: ts.IntersectionTypeNode, context?: TypeContext): string {
        const types = node.types.map(typeNode => this.getTypeNodeAsString(typeNode, context));
        return this.formatter.formatIntersection(types);
    }

    private getTypeLiteralNodeAsString(node: ts.TypeLiteralNode): string {
        const members = this.getMembersAsJson(node.members, 'literal');
        const stringMembers = Object.values(members).map(Object.values);
        const flattenMembers = stringMembers.reduce((acc, val) => acc.concat(val), []);
        return this.formatter.formatObject(flattenMembers);
    }

    private getArrayTypeNodeAsString(node: ts.ArrayTypeNode, context?: TypeContext): string {
        const type = this.getTypeNodeAsString(node.elementType, context);
        return this.formatter.formatArray(type);
    }

    private getNamedDeclarationAsString(node: ts.NamedDeclaration): string {
        if (!ts.isIdentifier(node.name)) {
            throw new TypeNotSupportedError();
        }
        return this.getIdentifierAsString(node.name);
    }

    private getIdentifierAsString(node: ts.Identifier): string {
        return String(node.escapedText);
    }
}

const { argv } = yargs(hideBin(process.argv))
    .command('$0 <language> <definition-files...>')
    .option('resources-namespace', { type: 'string', default: '' })
    .option('resources', { type: 'array', default: [] })
    .option('pretty', { type: 'boolean', default: false })

let supportChecker, formatter;
switch (argv.language.toUpperCase()) {
    case 'JS':
        supportChecker = new JsSupportChecker();
        formatter = new JsDocumentationFormatter();
        break;
    case 'PHP':
        supportChecker = new PhpSupportChecker();
        formatter = new PhpDocumentationFormatter(argv.resourcesNamespace, argv.resources);
        break;
    default:
        console.error(`Unsupported "${argv.language}" language.`);
        process.exit(1);
}

const docGenerator = new DocumentationGenerator(supportChecker, formatter);
const program = ts.createProgram(argv.definitionFiles, {});
const classes = {};

for (const fileName of argv.definitionFiles) {
    const sourceFile = program.getSourceFile(fileName);

    ts.forEachChild(sourceFile, node => {
        if (ts.isClassDeclaration(node)) {
            const classAsJson = docGenerator.getClassDeclarationAsJson(node);
            classes[classAsJson.name] = classAsJson;
        }
    });
}

process.stdout.write(JSON.stringify(classes, null, argv.pretty ? 2 : null));

Spamworldpro Mini