UNPKG

@remotex-labs/xmap

Version:

A library with a sourcemap parser and TypeScript code formatter for the CLI

428 lines (426 loc) 16.8 kB
"use strict"; var S = Object.create; var l = Object.defineProperty; var u = Object.getOwnPropertyDescriptor; var y = Object.getOwnPropertyNames; var x = Object.getPrototypeOf, C = Object.prototype.hasOwnProperty; var K = (i, e) => { for (var t in e) l(i, t, { get: e[t], enumerable: !0 }); }, m = (i, e, t, n) => { if (e && typeof e == "object" || typeof e == "function") for (let o of y(e)) !C.call(i, o) && o !== t && l(i, o, { get: () => e[o], enumerable: !(n = u(e, o)) || n.enumerable }); return i; }; var f = (i, e, t) => (t = i != null ? S(x(i)) : {}, m( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. e || !i || !i.__esModule ? l(t, "default", { value: i, enumerable: !0 }) : t, i )), v = (i) => m(l({}, "__esModule", { value: !0 }), i); // src/components/highlighter.component.ts var T = {}; K(T, { CodeHighlighter: () => d, highlightCode: () => w }); module.exports = v(T); var r = f(require("typescript"), 1), h = require("typescript"), a = require("@remotex-labs/xansi/xterm.component"), E = { enumColor: a.xterm.burntOrange, typeColor: a.xterm.lightGoldenrodYellow, classColor: a.xterm.lightOrange, stringColor: a.xterm.oliveGreen, keywordColor: a.xterm.lightCoral, commentColor: a.xterm.darkGray, functionColor: a.xterm.lightOrange, variableColor: a.xterm.burntOrange, interfaceColor: a.xterm.lightGoldenrodYellow, parameterColor: a.xterm.deepOrange, getAccessorColor: a.xterm.lightYellow, numericLiteralColor: a.xterm.lightGray, methodSignatureColor: a.xterm.burntOrange, regularExpressionColor: a.xterm.oliveGreen, propertyAssignmentColor: a.xterm.canaryYellow, propertyAccessExpressionColor: a.xterm.lightYellow, expressionWithTypeArgumentsColor: a.xterm.lightOrange }, d = class { /** * Creates an instance of the CodeHighlighter class. * * @param sourceFile - The TypeScript AST node representing the source file * @param code - The source code string to be highlighted * @param schema - The color scheme used for highlighting different elements in the code * * @since 1.0.0 */ constructor(e, t, n) { this.sourceFile = e; this.code = t; this.schema = n; } /** * A Map of segments where the key is a combination of start and end positions. * * @remarks * This structure ensures unique segments and allows for fast lookups and updates. * * @see HighlightNodeSegmentInterface * @since 1.0.0 */ segments = /* @__PURE__ */ new Map(); /** * Parses a TypeScript AST node and processes its comments to identify segments that need highlighting. * * @param node - The TypeScript AST node to be parsed * * @since 1.0.0 */ parseNode(e) { this.processComments(e), this.processKeywords(e), this.processNode(e); } /** * Generates a string with highlighted code segments based on the provided color scheme. * * @returns The highlighted code as a string, with ANSI color codes applied to the segments * * @remarks * This method processes the stored segments, applies the appropriate colors to each segment, * and returns the resulting highlighted code as a single string. * * @since 1.0.0 */ highlight() { let e = 0, t, n = []; return Array.from( this.segments.values() ).sort((s, c) => s.start - c.start || s.end - c.end).forEach((s) => { if (t && s.start < t.end) { let c = n.pop(); if (!c) return; let g = this.getSegmentSource(s.start, s.end), p = `${s.color(g)}`; n.push(c.replace(g, p)); return; } n.push(this.getSegmentSource(e, s.start)), n.push(s.color(this.getSegmentSource(s.start, s.end))), e = s.end, t = s; }), n.join("") + this.getSegmentSource(e); } /** * Extracts a text segment from the source code using position indices. * * @param start - The starting index position in the source text * @param end - The ending index position in the source text (optional) * @returns The substring of a source text between the start and end positions * * @remarks * This utility method provides access to specific portions of the source code * based on character positions. When the end parameter is omitted, the extraction * will continue to the end of the source text. * * This method is typically used during the highlighting process to access the * actual text content that corresponds to syntax nodes or other text ranges * before applying formatting. * * @example * ```ts * // Extract a variable name * const variableName = this.getSegmentSource(10, 15); * * // Extract from a position to the end of a source * const remaining = this.getSegmentSource(100); * ``` * * @see addSegment * @see highlight * * @since 1.0.0 */ getSegmentSource(e, t) { return this.code.slice(e, t); } /** * Registers a text segment for syntax highlighting with specified style information. * * @param start - The starting position of the segment in the source text * @param end - The ending position of the segment in the source text * @param color - The {@link ColorFunctionType} to apply to this segment * * @remarks * This method creates a unique key for each segment based on its position and stores the segment information in a map. * Each segment contains its position information, styling code, * and reset code which will later be used during the highlighting process. * * If multiple segments are added with the same positions, the later additions will * overwrite earlier ones due to the map's key-based storage. * * @example * ```ts * // Highlight a variable name in red * this.addSegment(10, 15, xterm.red); * * // Highlight a keyword with custom color * this.addSegment(20, 26, xterm.blue); * ``` * * @see Colors * @see processNode * * @since 1.0.0 */ addSegment(e, t, n) { let o = `${e}-${t}`; this.segments.set(o, { start: e, end: t, color: n }); } /** * Processes and highlights comments associated with a TypeScript AST node. * * @param node - The TypeScript AST node whose comments are to be processed * * @remarks * This method identifies both leading and trailing comments associated with the given node * and adds them to the highlighting segments. * The comments are extracted from the full source text using TypeScript's utility functions * and are highlighted using the color specified * in the schema's commentColor property. * * Leading comments appear before the node, while trailing comments appear after it. * Both types are processed with the same highlighting style. * * @example * ```ts * // For a node that might have comments like: * // This is a leading comment * const x = 5; // This is a trailing comment * * this.processComments(someNode); * // Both comments will be added to segments with the comment color * ``` * * @see addSegment * @see ts.getLeadingCommentRanges * @see ts.getTrailingCommentRanges * * @since 1.0.0 */ processComments(e) { [ ...r.default.getTrailingCommentRanges(this.sourceFile.getFullText(), e.getFullStart()) || [], ...r.default.getLeadingCommentRanges(this.sourceFile.getFullText(), e.getFullStart()) || [] ].forEach((n) => this.addSegment(n.pos, n.end, this.schema.commentColor)); } /** * Processes TypeScript keywords and primitive type references in an AST node for syntax highlighting. * * @param node - The TypeScript AST node to be processed for keywords * * @remarks * This method handles two categories of tokens that require special highlighting: * * 1. Primitive type references: Highlights references to built-in types like `null`, * `void`, `string`, `number`, `boolean`, and `undefined` using the type color. * * 2. TypeScript keywords: Identifies any node whose kind falls within the TypeScript * keyword range (between FirstKeyword and LastKeyword) and highlights it using * the keyword color. * * Each identified token is added to the segment collection with the appropriate position * and color information. * * @example * ```ts * // Inside syntax highlighting process * this.processKeywords(someNode); * // If the node represents a keyword like 'const' or a primitive type like 'string', * // it will be added to the segments with the appropriate color * ``` * * @see addSegment * @see ts.SyntaxKind * * @since 1.0.0 */ processKeywords(e) { if ([ h.SyntaxKind.NullKeyword, h.SyntaxKind.VoidKeyword, h.SyntaxKind.StringKeyword, h.SyntaxKind.NumberKeyword, h.SyntaxKind.BooleanKeyword, h.SyntaxKind.UndefinedKeyword ].includes(e.kind)) return this.addSegment(e.getStart(), e.getEnd(), this.schema.typeColor); e && e.kind >= r.default.SyntaxKind.FirstKeyword && e.kind <= r.default.SyntaxKind.LastKeyword && this.addSegment(e.getStart(), e.getEnd(), this.schema.keywordColor); } /** * Processes identifier nodes and applies appropriate syntax highlighting based on their context. * * @param node - The TypeScript AST node representing the identifier to be processed * * @remarks * This method determines the appropriate color for an identifier by examining its parent node's kind. * Different colors are applied based on the identifier's role in the code: * - Enum members use enumColor * - Interface names use interfaceColor * - Class names use classColor * - Function and method names use functionColor * - Parameters use parameterColor * - Variables and properties use variableColor * - Types use typeColor * - And more specialized cases for other syntax kinds * * Special handling is applied to property access expressions to differentiate between * the object being accessed and the property being accessed. * * @example * ```ts * // Inside the CodeHighlighter class * const identifierNode = getIdentifierNode(); // Get some identifier node * this.processIdentifier(identifierNode); * // The identifier is now added to segments with appropriate color based on its context * ``` * * @see addSegment * @see HighlightSchemeInterface * * @since 1.0.0 */ processIdentifier(e) { let t = e.getEnd(), n = e.getStart(); switch (e.parent.kind) { case r.default.SyntaxKind.EnumMember: return this.addSegment(n, t, this.schema.enumColor); case r.default.SyntaxKind.CallExpression: case r.default.SyntaxKind.EnumDeclaration: case r.default.SyntaxKind.PropertySignature: case r.default.SyntaxKind.ModuleDeclaration: return this.addSegment(n, t, this.schema.variableColor); case r.default.SyntaxKind.InterfaceDeclaration: return this.addSegment(n, t, this.schema.interfaceColor); case r.default.SyntaxKind.GetAccessor: return this.addSegment(n, t, this.schema.getAccessorColor); case r.default.SyntaxKind.PropertyAssignment: return this.addSegment(n, t, this.schema.propertyAssignmentColor); case r.default.SyntaxKind.MethodSignature: return this.addSegment(n, t, this.schema.methodSignatureColor); case r.default.SyntaxKind.MethodDeclaration: case r.default.SyntaxKind.FunctionDeclaration: return this.addSegment(n, t, this.schema.functionColor); case r.default.SyntaxKind.ClassDeclaration: return this.addSegment(n, t, this.schema.classColor); case r.default.SyntaxKind.Parameter: return this.addSegment(n, t, this.schema.parameterColor); case r.default.SyntaxKind.VariableDeclaration: return this.addSegment(n, t, this.schema.variableColor); case r.default.SyntaxKind.PropertyDeclaration: return this.addSegment(n, t, this.schema.variableColor); case r.default.SyntaxKind.PropertyAccessExpression: return e.parent.getChildAt(0).getText() === e.getText() ? this.addSegment(n, t, this.schema.variableColor) : this.addSegment(n, t, this.schema.propertyAccessExpressionColor); case r.default.SyntaxKind.ExpressionWithTypeArguments: return this.addSegment(n, t, this.schema.expressionWithTypeArgumentsColor); case r.default.SyntaxKind.BreakStatement: case r.default.SyntaxKind.ShorthandPropertyAssignment: case r.default.SyntaxKind.BindingElement: return this.addSegment(n, t, this.schema.variableColor); case r.default.SyntaxKind.BinaryExpression: case r.default.SyntaxKind.SwitchStatement: case r.default.SyntaxKind.TemplateSpan: return this.addSegment(n, t, this.schema.variableColor); case r.default.SyntaxKind.TypeReference: case r.default.SyntaxKind.TypeAliasDeclaration: return this.addSegment(n, t, this.schema.typeColor); case r.default.SyntaxKind.NewExpression: return this.addSegment(n, t, this.schema.variableColor); } } /** * Processes a TypeScript template expression and adds highlighting segments for its literal parts. * * @param templateExpression - The TypeScript template expression to be processed * * @remarks * This method adds color segments for both the template head and each template span's literal part. * All template string components are highlighted using the color defined in the schema's stringColor. * * @example * ```ts * // Given a template expression like: `Hello ${name}` * this.processTemplateExpression(templateNode); * // Both "Hello " and the closing part after the expression will be highlighted * ``` * * @see addSegment * * @since 1.0.0 */ processTemplateExpression(e) { let t = e.head.getStart(), n = e.head.getEnd(); this.addSegment(t, n, this.schema.stringColor), e.templateSpans.forEach((o) => { let s = o.literal.getStart(), c = o.literal.getEnd(); this.addSegment(s, c, this.schema.stringColor); }); } /** * Processes a TypeScript AST node and adds highlighting segments based on the node's kind. * * @param node - The TypeScript AST node to be processed * * @remarks * This method identifies the node's kind and applies the appropriate color for highlighting. * It handles various syntax kinds, including literals (string, numeric, regular expressions), * template expressions, identifiers, and type references. * For complex node types like template expressions and identifiers, it delegates to specialized processing methods. * * @throws Error - When casting to TypeParameterDeclaration fails for non-compatible node kinds * * @example * ```ts * // Inside the CodeHighlighter class * const node = sourceFile.getChildAt(0); * this.processNode(node); * // Node is now added to the segment map with appropriate colors * ``` * * @see processTemplateExpression * @see processIdentifier * * @since 1.0.0 */ processNode(e) { let t = e.getStart(), n = e.getEnd(); switch (e.kind) { case r.default.SyntaxKind.TypeParameter: return this.addSegment(t, t + e.name.text.length, this.schema.typeColor); case r.default.SyntaxKind.TypeReference: return this.addSegment(t, n, this.schema.typeColor); case r.default.SyntaxKind.StringLiteral: case r.default.SyntaxKind.NoSubstitutionTemplateLiteral: return this.addSegment(t, n, this.schema.stringColor); case r.default.SyntaxKind.RegularExpressionLiteral: return this.addSegment(t, n, this.schema.regularExpressionColor); case r.default.SyntaxKind.TemplateExpression: return this.processTemplateExpression(e); case r.default.SyntaxKind.Identifier: return this.processIdentifier(e); case r.default.SyntaxKind.BigIntLiteral: case r.default.SyntaxKind.NumericLiteral: return this.addSegment(t, n, this.schema.numericLiteralColor); } } }; function w(i, e = {}) { let t = r.default.createSourceFile("temp.ts", i, r.default.ScriptTarget.Latest, !0, r.default.ScriptKind.TS), n = new d(t, i, Object.assign(E, e)); function o(s) { n.parseNode(s); for (let c = 0; c < s.getChildCount(); c++) o(s.getChildAt(c)); } return r.default.forEachChild(t, o), n.highlight(); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { CodeHighlighter, highlightCode }); //# sourceMappingURL=highlighter.component.js.map