Fix bin/publish: copy docs.dist from project root

Fix bin/publish: use correct .env path for rspade_system
Fix bin/publish script: prevent grep exit code 1 from terminating script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-10-21 02:08:33 +00:00
commit f6fac6c4bc
79758 changed files with 10547827 additions and 0 deletions

218
node_modules/@jqhtml/vscode-extension/out/componentIndex.js generated vendored Executable file
View File

@@ -0,0 +1,218 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JqhtmlComponentIndex = void 0;
const vscode = __importStar(require("vscode"));
/**
* JQHTML Component Indexer
*
* Maintains an index of all JQHTML component definitions in the workspace
* for fast lookup during goto definition operations.
*/
class JqhtmlComponentIndex {
constructor() {
this.componentMap = new Map();
// Start initial indexing
this.reindexWorkspace();
// Watch for changes to .jqhtml files
this.setupFileWatcher();
}
/**
* Set up file system watcher for .jqhtml files
*/
setupFileWatcher() {
this.fileWatcher = vscode.workspace.createFileSystemWatcher('**/*.jqhtml');
// Re-index when files are created, changed, or deleted
this.fileWatcher.onDidCreate(uri => this.indexFile(uri));
this.fileWatcher.onDidChange(uri => this.indexFile(uri));
this.fileWatcher.onDidDelete(uri => this.removeFileFromIndex(uri));
}
/**
* Re-index all .jqhtml files in the workspace
*/
reindexWorkspace() {
return __awaiter(this, void 0, void 0, function* () {
// Avoid multiple concurrent reindexing
if (this.indexPromise) {
return this.indexPromise;
}
this.indexPromise = this._reindexWorkspace();
yield this.indexPromise;
this.indexPromise = undefined;
});
}
_reindexWorkspace() {
return __awaiter(this, void 0, void 0, function* () {
console.log('JQHTML: Starting workspace component indexing...');
this.componentMap.clear();
const workspaceFolders = vscode.workspace.workspaceFolders;
if (!workspaceFolders) {
console.log('JQHTML: No workspace folders found');
return;
}
// Search each workspace folder explicitly for multi-root workspace support
const allFiles = [];
for (const folder of workspaceFolders) {
const files = yield vscode.workspace.findFiles(new vscode.RelativePattern(folder, '**/*.jqhtml'), new vscode.RelativePattern(folder, '**/node_modules/**'));
allFiles.push(...files);
}
// Index each file
const promises = allFiles.map(uri => this.indexFile(uri));
yield Promise.all(promises);
console.log(`JQHTML: Indexed ${this.componentMap.size} components from ${allFiles.length} files`);
});
}
/**
* Index a single .jqhtml file
*/
indexFile(uri) {
return __awaiter(this, void 0, void 0, function* () {
try {
// Remove old entries from this file
this.removeFileFromIndex(uri);
// Read file content
const document = yield vscode.workspace.openTextDocument(uri);
const text = document.getText();
const lines = text.split('\n');
// Look for component definitions
// Pattern: <Define:ComponentName (followed by non-alphanumeric or end of tag)
//
// DIAGNOSTIC HISTORY:
// - Issue: Component "Contacts_Datagrid" not found in index
// - This regex SHOULD match: <Define:Contacts_Datagrid...
// - Component name pattern: [A-Z][A-Za-z0-9_]* (starts uppercase, then alphanum+underscore)
// - Contacts_Datagrid matches this pattern
//
// POSSIBLE REASONS FOR MISSED COMPONENTS:
// 1. File not in workspace folders (check workspaceFolders in console)
// 2. File in node_modules (explicitly excluded line 75)
// 3. Syntax variations:
// - Extra whitespace: <Define: Contacts_Datagrid> (space after colon) ❌
// - Wrong case: <define:Contacts_Datagrid> (lowercase 'define') ❌
// - Missing colon: <DefineContacts_Datagrid> ❌
// 4. Indexing hasn't completed yet (async operation)
// 5. File watcher didn't fire (check file modification timestamp)
//
// DEBUGGING STEPS:
// 1. Check console output "JQHTML: Indexed X components from Y files"
// 2. Check console log when file is saved (should trigger onDidChange)
// 3. Manually reload VS Code window to force reindex
// 4. Check if file path contains "node_modules"
const definePattern = /<Define:([A-Z][A-Za-z0-9_]*)(?:[^\w]|>|$)/g;
for (let lineNum = 0; lineNum < lines.length; lineNum++) {
const line = lines[lineNum];
let match;
// Reset regex for each line
definePattern.lastIndex = 0;
while ((match = definePattern.exec(line)) !== null) {
const componentName = match[1];
const charPos = match.index + '<Define:'.length;
// Store component definition
this.componentMap.set(componentName, {
name: componentName,
uri: uri,
position: new vscode.Position(lineNum, charPos),
line: line.trim()
});
// Debug: Log each component as it's indexed (commented out - too verbose)
// console.log(`JQHTML Index: Indexed "${componentName}" from ${path.basename(uri.fsPath)}:${lineNum + 1}`);
}
}
}
catch (error) {
console.error(`JQHTML: Error indexing file ${uri.fsPath}:`, error);
}
});
}
/**
* Remove all components from a file from the index
*/
removeFileFromIndex(uri) {
// Remove all components defined in this file
const toRemove = [];
this.componentMap.forEach((def, name) => {
if (def.uri.toString() === uri.toString()) {
toRemove.push(name);
}
});
// Verbose logging commented out to reduce console noise
// if (toRemove.length > 0) {
// console.log(`JQHTML Index: Removing ${toRemove.length} component(s) from deleted file: ${uri.fsPath}`);
// console.log(`JQHTML Index: Components removed: ${toRemove.join(', ')}`);
// }
toRemove.forEach(name => {
this.componentMap.delete(name);
});
// console.log(`JQHTML Index: Current index size after removal: ${this.componentMap.size} components`);
}
/**
* Find a component definition by name
*/
findComponent(name) {
return this.componentMap.get(name);
}
/**
* Get all component names (for autocomplete)
*/
getAllComponentNames() {
return Array.from(this.componentMap.keys());
}
/**
* Check if a string is a component reference (starts with capital letter)
*/
static isComponentReference(tagName) {
return /^[A-Z]/.test(tagName);
}
/**
* Dispose of resources
*/
dispose() {
if (this.fileWatcher) {
this.fileWatcher.dispose();
}
this.componentMap.clear();
}
}
exports.JqhtmlComponentIndex = JqhtmlComponentIndex;
//# sourceMappingURL=componentIndex.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"componentIndex.js","sourceRoot":"","sources":["../src/componentIndex.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,590 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JqhtmlHoverProvider = exports.JqhtmlDefinitionProvider = void 0;
const vscode = __importStar(require("vscode"));
const componentIndex_1 = require("./componentIndex");
/**
* JQHTML Definition Provider
*
* Provides "Go to Definition" functionality for JQHTML components.
* When a user Ctrl/Cmd+clicks on a component name or uses F12,
* this provider will locate the component definition.
*/
class JqhtmlDefinitionProvider {
constructor(componentIndex) {
this.componentIndex = componentIndex;
}
provideDefinition(document, position, token) {
return __awaiter(this, void 0, void 0, function* () {
console.log(`\n========== JQHTML: provideDefinition called ==========`);
console.log(`File: ${document.uri.fsPath}`);
console.log(`Position: Line ${position.line + 1}, Character ${position.character}`);
const line = document.lineAt(position.line).text;
console.log(`JQHTML: Line text: "${line}"`);
// Check if we're in a $ attribute with unquoted value
const dollarAttrResult = this.checkDollarAttributeContext(document, position, line);
if (dollarAttrResult) {
console.log(`JQHTML: In $ attribute context:`, dollarAttrResult);
return yield this.handleDollarAttributeDefinition(document, position, dollarAttrResult);
}
// Get the word at the cursor position
const wordRange = document.getWordRangeAtPosition(position, /[A-Z][A-Za-z0-9_]*/);
if (!wordRange) {
console.log(`JQHTML: No word range found at position`);
return undefined;
}
const word = document.getText(wordRange);
console.log(`JQHTML: Word at cursor: "${word}"`);
// Check if this looks like a component reference
if (!componentIndex_1.JqhtmlComponentIndex.isComponentReference(word)) {
console.log(`JQHTML: "${word}" is not a component reference (doesn't start with capital)`);
return undefined;
}
// line already declared at top of function
const charBefore = wordRange.start.character > 0 ?
line.charAt(wordRange.start.character - 1) : '';
// Check if this word is inside an extends="" attribute value
let beforeWord = line.substring(0, wordRange.start.character);
if (beforeWord.match(/extends\s*=\s*["']?\s*$/)) {
console.log(`JQHTML: "${word}" is in extends attribute, treating as component reference`);
// This is in extends="ComponentName", treat as component reference
const componentDef = this.componentIndex.findComponent(word);
if (!componentDef) {
console.log(`JQHTML: Component '${word}' not found in index`);
return undefined;
}
// Verify the file still exists
try {
yield vscode.workspace.fs.stat(componentDef.uri);
}
catch (error) {
console.log(`JQHTML: Component '${word}' definition file no longer exists`);
this.componentIndex.reindexWorkspace();
return undefined;
}
console.log(`JQHTML: Found definition for '${word}' at ${componentDef.uri.fsPath}:${componentDef.position.line + 1}`);
return new vscode.Location(componentDef.uri, componentDef.position);
}
// Check if this word is in a tag context
// Look for < before the component name (accounting for Define: prefix)
let isInTagContext = false;
// Check for opening tag: <ComponentName or <Define:ComponentName
beforeWord = line.substring(0, wordRange.start.character);
if (beforeWord.match(/<\s*$/) || beforeWord.match(/<Define:\s*$/)) {
isInTagContext = true;
}
// Check for closing tag: </ComponentName or </Define:ComponentName
if (beforeWord.match(/<\/\s*$/) || beforeWord.match(/<\/Define:\s*$/)) {
isInTagContext = true;
}
// Check for slot syntax: <#slotname> or </#slotname>
if (beforeWord.match(/<#\s*$/) || beforeWord.match(/<\/#\s*$/)) {
// This is a slot, not a component
return undefined;
}
if (!isInTagContext) {
// Also check if cursor is inside the tag name (not in attributes)
const afterWord = line.substring(wordRange.end.character);
// If there's a space or > after the word, and < before it somewhere
if ((afterWord.match(/^[\s>]/) || afterWord.length === 0) && beforeWord.includes('<')) {
// Verify we're not in an attribute value
const lastLessThan = beforeWord.lastIndexOf('<');
const lastGreaterThan = beforeWord.lastIndexOf('>');
if (lastLessThan > lastGreaterThan) {
isInTagContext = true;
}
}
}
if (!isInTagContext) {
console.log(`JQHTML: "${word}" not in tag context, ignoring`);
return undefined;
}
console.log(`JQHTML: "${word}" IS in tag context, looking up in index...`);
console.log(`JQHTML: Current index size: ${this.componentIndex.getAllComponentNames().length} components`);
console.log(`JQHTML: Index contains: ${this.componentIndex.getAllComponentNames().join(', ')}`);
// Look up the component in our index
const componentDef = this.componentIndex.findComponent(word);
if (!componentDef) {
// Component not found in index
//
// DIAGNOSTIC HISTORY:
// - Issue: Go to Definition goes to random CSS file instead of component
// - Symptom: Component correctly identified (e.g., "Contacts_Datagrid")
// Tag context correctly detected
// BUT findComponent() returns undefined
// - Root cause: Component not indexed by the indexing system
//
// POSSIBLE REASONS:
// 1. Component file not in workspace or not discovered during indexing
// 2. Component definition syntax not matching regex in componentIndex.ts
// 3. File watcher didn't detect the file creation/modification
// 4. Index hasn't run yet (extension just activated)
//
// WHEN THIS RETURNS UNDEFINED:
// VS Code falls back to built-in text search providers, which may find
// the component name in CSS class names (.Contacts_Datagrid), causing
// navigation to wrong files.
//
// NEXT DIAGNOSTIC STEPS:
// 1. Check if component file exists and is in workspace
// 2. Verify Define tag syntax matches indexing regex
// 3. Check file watcher is working (create new component, see if indexed)
// 4. Manually trigger reindex and check if component appears
console.log(`JQHTML: Component '${word}' not found in index`);
console.log(`JQHTML: RETURNING UNDEFINED - VS Code may fall back to other definition providers!`);
return undefined;
}
// Verify the file still exists (catches stale index entries)
try {
yield vscode.workspace.fs.stat(componentDef.uri);
}
catch (error) {
// File no longer exists - trigger reindex and return undefined
console.log(`JQHTML: Component '${word}' definition file no longer exists: ${componentDef.uri.fsPath}`);
console.log(`JQHTML: Triggering workspace reindex...`);
this.componentIndex.reindexWorkspace(); // Async, non-blocking
return undefined;
}
console.log(`JQHTML: Found definition for '${word}' at ${componentDef.uri.fsPath}:${componentDef.position.line + 1}`);
console.log(`JQHTML: RETURNING LOCATION - This should be the ONLY result!`);
console.log(`========== JQHTML: provideDefinition done ==========\n`);
// Return the location of the component definition
return new vscode.Location(componentDef.uri, componentDef.position);
});
}
/**
* Check if cursor is in a $ attribute with unquoted value like $handler=Controller.method
* Returns the parsed segments and position info, or undefined if not in such context
*/
checkDollarAttributeContext(document, position, line) {
var _a;
const char = position.character;
const beforeCursor = line.substring(0, char);
const afterCursor = line.substring(char);
// Look for pattern: $attributeName=FirstSegment.secondSegment
// Match: $ followed by word, =, then identifier chains
const dollarAttrMatch = beforeCursor.match(/\$\w+\s*=\s*([a-zA-Z_$][a-zA-Z0-9_$]*(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)*)$/);
if (!dollarAttrMatch) {
return undefined;
}
// Get the full expression (before cursor + until space or >)
const expressionBeforeCursor = dollarAttrMatch[1];
const expressionAfterCursor = ((_a = afterCursor.match(/^([a-zA-Z0-9_$]*)/)) === null || _a === void 0 ? void 0 : _a[1]) || '';
const fullExpression = expressionBeforeCursor + expressionAfterCursor;
console.log(`JQHTML: Full $ attribute expression: "${fullExpression}"`);
// Split by dots
const segments = fullExpression.split('.');
// Determine which segment we're on based on cursor position
const expressionStartChar = char - expressionBeforeCursor.length;
const cursorOffsetInExpression = char - expressionStartChar;
let currentSegmentIndex = 0;
let charCount = 0;
for (let i = 0; i < segments.length; i++) {
const segmentLength = segments[i].length;
if (cursorOffsetInExpression <= charCount + segmentLength) {
currentSegmentIndex = i;
break;
}
charCount += segmentLength + 1; // +1 for the dot
}
console.log(`JQHTML: Cursor on segment ${currentSegmentIndex}: "${segments[currentSegmentIndex]}"`);
// Handle "this" keyword - resolve to containing Define component
let className = segments[0];
if (className === 'this') {
const containingComponent = this.findContainingDefineComponent(document, position.line);
if (!containingComponent) {
console.log(`JQHTML: "this" used but no containing Define component found`);
return undefined;
}
className = containingComponent;
console.log(`JQHTML: Resolved "this" to component: ${className}`);
}
if (currentSegmentIndex === 0) {
// First segment - just the class name
return { className, isFirstSegment: true };
}
else {
// Second or later segment - class + member
return {
className,
memberName: segments[currentSegmentIndex],
isFirstSegment: false
};
}
}
/**
* Find the containing <Define:ComponentName> for a given line
*/
findContainingDefineComponent(document, currentLine) {
// Search backwards from current line to find <Define:ComponentName>
for (let i = currentLine; i >= 0; i--) {
const lineText = document.lineAt(i).text;
const defineMatch = lineText.match(/<Define:([A-Z][A-Za-z0-9_]*)/);
if (defineMatch) {
return defineMatch[1];
}
}
return undefined;
}
/**
* Handle goto definition for $ attribute values
*
* SEARCH PRIORITY MATRIX:
*
* Single Segment (e.g., $handler=Controller):
* 1. PHP class
* 2. JS class
* 3. Standalone JS function (only if first segment is not "this")
*
* Multiple Segments - First Segment (e.g., $handler=Controller.method, click on "Controller"):
* 1. PHP class
* 2. JS class (if no PHP class found, or if first segment is "this")
* 3. Standalone JS function (only if not "this")
*
* Multiple Segments - Second+ Segment (e.g., $handler=Controller.method, click on "method"):
* 1. PHP method in PHP class → Fall back to PHP class if method not found
* 2. JS method in JS class → Fall back to JS class if method not found (if no PHP class found, or if "this")
* (No standalone function search for second+ segments)
*
* Special Case: "this" keyword
* - Resolves to containing <Define:ComponentName>
* - Only searches JS (PHP search skipped)
*/
handleDollarAttributeDefinition(document, position, context) {
return __awaiter(this, void 0, void 0, function* () {
console.log(`JQHTML: Looking for class "${context.className}"${context.memberName ? `, member "${context.memberName}"` : ''}`);
const isThisKeyword = context.className === 'this';
// Priority 1: Search PHP classes/methods (skip if "this" keyword)
if (!isThisKeyword) {
const phpResult = yield this.searchPhpDefinition(context);
if (phpResult) {
return phpResult;
}
}
// Priority 2: Search JS classes/methods
const jsClassResult = yield this.searchJsClassDefinition(context);
if (jsClassResult) {
return jsClassResult;
}
// Priority 3: Search standalone JS functions (only for single segment, not "this")
if (context.isFirstSegment && !context.memberName && !isThisKeyword) {
const jsFunctionResult = yield this.searchStandaloneJsFunction(context.className);
if (jsFunctionResult) {
return jsFunctionResult;
}
}
console.log(`JQHTML: No definition found for "${context.className}"${context.memberName ? `.${context.memberName}` : ''}`);
return undefined;
});
}
/**
* Search for PHP class and optionally method
*
* IMPLEMENTATION: Uses VS Code's workspace symbol provider API to query Intelephense's symbol index.
*
* This approach:
* - Leverages Intelephense's existing indexed symbol database
* - No temporary documents or window management issues
* - Fast symbol lookup via vscode.executeWorkspaceSymbolProvider
* - Gracefully falls back if Intelephense not installed
* - No manual indexing or file scanning required
*
* We query workspace symbols by name (class or method), then filter results
* to find PHP symbols and navigate to their definitions.
*/
searchPhpDefinition(context) {
return __awaiter(this, void 0, void 0, function* () {
try {
// Check if Intelephense is installed
const intelephenseExt = vscode.extensions.getExtension('bmewburn.vscode-intelephense-client');
if (!intelephenseExt) {
console.log(`JQHTML: Intelephense extension not installed, skipping PHP lookup`);
return undefined;
}
// Search for the class first
console.log(`JQHTML: Searching workspace symbols for PHP class: ${context.className}`);
const classSymbols = yield vscode.commands.executeCommand('vscode.executeWorkspaceSymbolProvider', context.className);
if (!classSymbols || classSymbols.length === 0) {
console.log(`JQHTML: No workspace symbols found for class: ${context.className}`);
return undefined;
}
// Filter to PHP class symbols
const phpClassSymbol = classSymbols.find(s => s.name === context.className &&
s.kind === vscode.SymbolKind.Class &&
s.location.uri.fsPath.endsWith('.php'));
if (!phpClassSymbol) {
console.log(`JQHTML: No PHP class symbol found for: ${context.className}`);
return undefined;
}
console.log(`JQHTML: Found PHP class ${context.className} in ${phpClassSymbol.location.uri.fsPath}`);
// If we're looking for the class itself (first segment, no member)
if (context.isFirstSegment && !context.memberName) {
return phpClassSymbol.location;
}
// If we're looking for a method within the class
if (context.memberName) {
console.log(`JQHTML: Searching for method: ${context.memberName} in class ${context.className}`);
// Search for the method name in workspace symbols
const methodSymbols = yield vscode.commands.executeCommand('vscode.executeWorkspaceSymbolProvider', context.memberName);
// Filter to methods in the same PHP file as the class
const phpMethodSymbol = methodSymbols === null || methodSymbols === void 0 ? void 0 : methodSymbols.find(s => s.name === context.memberName &&
s.kind === vscode.SymbolKind.Method &&
s.location.uri.toString() === phpClassSymbol.location.uri.toString());
if (phpMethodSymbol) {
console.log(`JQHTML: Found PHP method ${context.memberName} in ${phpMethodSymbol.location.uri.fsPath}`);
return phpMethodSymbol.location;
}
// Method not found - fall back to class definition
console.log(`JQHTML: Method ${context.memberName} not found, falling back to class definition`);
return phpClassSymbol.location;
}
return phpClassSymbol.location;
}
catch (error) {
console.error(`JQHTML: Error using workspace symbol provider:`, error);
return undefined;
}
});
}
/**
* Search for JS class and optionally method
*/
searchJsClassDefinition(context) {
return __awaiter(this, void 0, void 0, function* () {
const jsFiles = yield vscode.workspace.findFiles('**/*.js', '**/node_modules/**');
for (const fileUri of jsFiles) {
const fileDoc = yield vscode.workspace.openTextDocument(fileUri);
const fileText = fileDoc.getText();
// Look for class definition: class ClassName
const classRegex = new RegExp(`^\\s*(?:export\\s+)?class\\s+${context.className}\\b`, 'm');
const classMatch = classRegex.exec(fileText);
if (classMatch) {
console.log(`JQHTML: Found JS class ${context.className} in ${fileUri.fsPath}`);
// If we're on the first segment, go to the class definition
if (context.isFirstSegment && !context.memberName) {
const classPos = fileDoc.positionAt(classMatch.index + classMatch[0].indexOf(context.className));
return new vscode.Location(fileUri, classPos);
}
// If we're on a later segment, try to find the method/property in the class
if (context.memberName) {
const memberLocation = this.findJsClassMember(fileDoc, fileText, classMatch.index, context.memberName);
if (memberLocation) {
console.log(`JQHTML: Found JS method ${context.memberName} in class ${context.className}`);
return new vscode.Location(fileUri, memberLocation);
}
// Method not found, but we found the class - fall back to class definition
console.log(`JQHTML: JS method ${context.memberName} not found, falling back to JS class definition`);
const classPos = fileDoc.positionAt(classMatch.index + classMatch[0].indexOf(context.className));
return new vscode.Location(fileUri, classPos);
}
}
}
return undefined;
});
}
/**
* Search for standalone JS function (not in a class)
* Only called for single-segment expressions where first segment is not "this"
*/
searchStandaloneJsFunction(functionName) {
return __awaiter(this, void 0, void 0, function* () {
const jsFiles = yield vscode.workspace.findFiles('**/*.js', '**/node_modules/**');
for (const fileUri of jsFiles) {
const fileDoc = yield vscode.workspace.openTextDocument(fileUri);
const fileText = fileDoc.getText();
// Look for function declaration: function functionName
// or const/let/var functionName = function
const functionRegex = new RegExp(`^\\s*(?:export\\s+)?(?:async\\s+)?function\\s+${functionName}\\b`, 'm');
const functionMatch = functionRegex.exec(fileText);
if (functionMatch) {
console.log(`JQHTML: Found standalone JS function ${functionName} in ${fileUri.fsPath}`);
const functionPos = fileDoc.positionAt(functionMatch.index + functionMatch[0].indexOf(functionName));
return new vscode.Location(fileUri, functionPos);
}
// Also check for: const functionName = ...
const constFunctionRegex = new RegExp(`^\\s*(?:export\\s+)?(?:const|let|var)\\s+${functionName}\\s*=`, 'm');
const constMatch = constFunctionRegex.exec(fileText);
if (constMatch) {
console.log(`JQHTML: Found standalone JS function ${functionName} (const/let/var) in ${fileUri.fsPath}`);
const functionPos = fileDoc.positionAt(constMatch.index + constMatch[0].indexOf(functionName));
return new vscode.Location(fileUri, functionPos);
}
}
return undefined;
});
}
/**
* Find a method or property within a JS class definition
*/
findJsClassMember(document, fileText, classStartIndex, memberName) {
// Find the class body (starts at { after class declaration)
const classBodyStart = fileText.indexOf('{', classStartIndex);
if (classBodyStart === -1)
return undefined;
// Find matching closing brace
let braceCount = 1;
let classBodyEnd = classBodyStart + 1;
while (classBodyEnd < fileText.length && braceCount > 0) {
if (fileText[classBodyEnd] === '{')
braceCount++;
if (fileText[classBodyEnd] === '}')
braceCount--;
classBodyEnd++;
}
const classBody = fileText.substring(classBodyStart, classBodyEnd);
// Look for method: methodName() { or property: methodName =
const methodRegex = new RegExp(`^\\s*(?:async\\s+)?${memberName}\\s*[=(]`, 'm');
const methodMatch = methodRegex.exec(classBody);
if (methodMatch) {
const absoluteIndex = classBodyStart + methodMatch.index + methodMatch[0].indexOf(memberName);
return document.positionAt(absoluteIndex);
}
return undefined;
}
}
exports.JqhtmlDefinitionProvider = JqhtmlDefinitionProvider;
/**
* JQHTML Hover Provider
*
* Provides hover information for JQHTML components.
* Shows the file and line where the component is defined.
*/
class JqhtmlHoverProvider {
constructor(componentIndex) {
this.componentIndex = componentIndex;
}
provideHover(document, position, token) {
return __awaiter(this, void 0, void 0, function* () {
const line = document.lineAt(position.line).text;
const char = position.character;
// Check for $redrawable attribute
const redrawableMatch = line.match(/\$redrawable(?=\s|>|\/)/);
if (redrawableMatch && line.indexOf('$redrawable') <= char && char <= line.indexOf('$redrawable') + '$redrawable'.length) {
const markdown = new vscode.MarkdownString();
markdown.appendMarkdown(`**\`$redrawable\` Attribute**\n\n`);
markdown.appendMarkdown(`Converts this tag into an anonymous component class, allowing it to be redrawn on demand.\n\n`);
markdown.appendMarkdown(`**Usage:**\n\`\`\`javascript\nthis.$id('element_id').render()\n\`\`\`\n\n`);
markdown.appendMarkdown(`Call \`render()\` on the element's scoped ID to trigger a re-render of just this element without affecting the rest of the component.`);
const wordRange = new vscode.Range(new vscode.Position(position.line, line.indexOf('$redrawable')), new vscode.Position(position.line, line.indexOf('$redrawable') + '$redrawable'.length));
return new vscode.Hover(markdown, wordRange);
}
// Check for tag="" attribute on components (Define tags or component invocations)
// Look backwards from cursor to find if we're in a tag="" attribute
const beforeCursor = line.substring(0, char);
const afterCursor = line.substring(char);
// Check if we're hovering over "tag" attribute name or its value
const tagAttrMatch = beforeCursor.match(/<(Define:[A-Z][A-Za-z0-9_]*|[A-Z][A-Za-z0-9_]*)[^>]*\btag\s*=\s*["']?(\w*)$/);
if (tagAttrMatch) {
// We're in or near a tag attribute
const markdown = new vscode.MarkdownString();
markdown.appendMarkdown(`**\`tag\` Attribute**\n\n`);
markdown.appendMarkdown(`Sets the HTML element type for this component.\n\n`);
markdown.appendMarkdown(`**Default:** \`div\`\n\n`);
markdown.appendMarkdown(`**Examples:**\n`);
markdown.appendMarkdown(`- \`tag="button"\` - Creates a \`<button>\` element\n`);
markdown.appendMarkdown(`- \`tag="span"\` - Creates a \`<span>\` element\n`);
markdown.appendMarkdown(`- \`tag="a"\` - Creates an \`<a>\` element\n\n`);
markdown.appendMarkdown(`Use this when your component should be a specific HTML element instead of the default \`<div>\`.`);
return new vscode.Hover(markdown);
}
// Original component hover logic
// Get the word at the cursor position
const wordRange = document.getWordRangeAtPosition(position, /[A-Z][A-Za-z0-9_]*/);
if (!wordRange) {
return undefined;
}
const word = document.getText(wordRange);
// Check if this looks like a component reference
if (!componentIndex_1.JqhtmlComponentIndex.isComponentReference(word)) {
return undefined;
}
// Verify this is in a tag context (same logic as definition provider)
// line already declared at top of function
const beforeWord = line.substring(0, wordRange.start.character);
let isInTagContext = false;
if (beforeWord.match(/<\s*$/) || beforeWord.match(/<Define:\s*$/) ||
beforeWord.match(/<\/\s*$/) || beforeWord.match(/<\/Define:\s*$/)) {
isInTagContext = true;
}
if (!isInTagContext) {
const afterWord = line.substring(wordRange.end.character);
if ((afterWord.match(/^[\s>]/) || afterWord.length === 0) && beforeWord.includes('<')) {
const lastLessThan = beforeWord.lastIndexOf('<');
const lastGreaterThan = beforeWord.lastIndexOf('>');
if (lastLessThan > lastGreaterThan) {
isInTagContext = true;
}
}
}
if (!isInTagContext) {
return undefined;
}
// Look up the component in our index
const componentDef = this.componentIndex.findComponent(word);
if (!componentDef) {
// Show that component is not defined
const markdown = new vscode.MarkdownString();
markdown.appendMarkdown(`**JQHTML Component:** \`${word}\`\n\n`);
markdown.appendMarkdown(`⚠️ *Component definition not found in workspace*`);
return new vscode.Hover(markdown, wordRange);
}
// Create hover content
const markdown = new vscode.MarkdownString();
markdown.appendMarkdown(`**JQHTML Component:** \`${word}\`\n\n`);
// Show file location
const relativePath = vscode.workspace.asRelativePath(componentDef.uri);
markdown.appendMarkdown(`📁 **Defined in:** \`${relativePath}:${componentDef.position.line + 1}\`\n\n`);
// Show the definition line
if (componentDef.line) {
markdown.appendCodeblock(componentDef.line, 'jqhtml');
}
// Make the file path clickable
markdown.isTrusted = true;
return new vscode.Hover(markdown, wordRange);
});
}
}
exports.JqhtmlHoverProvider = JqhtmlHoverProvider;
//# sourceMappingURL=definitionProvider.js.map

File diff suppressed because one or more lines are too long

159
node_modules/@jqhtml/vscode-extension/out/extension.js generated vendored Executable file
View File

@@ -0,0 +1,159 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.activate = activate;
exports.deactivate = deactivate;
const vscode = __importStar(require("vscode"));
const formatter_1 = require("./formatter");
const componentIndex_1 = require("./componentIndex");
const definitionProvider_1 = require("./definitionProvider");
function activate(context) {
console.log('JQHTML extension activated');
// Initialize component index
const componentIndex = new componentIndex_1.JqhtmlComponentIndex();
context.subscriptions.push({
dispose: () => componentIndex.dispose()
});
// Register the formatter
const formatter = new formatter_1.JqhtmlFormattingEditProvider();
const formatterProvider = vscode.languages.registerDocumentFormattingEditProvider('jqhtml', formatter);
context.subscriptions.push(formatterProvider);
// Register definition provider for goto definition (Ctrl+Click, F12)
const definitionProvider = new definitionProvider_1.JqhtmlDefinitionProvider(componentIndex);
const definitionProviderDisposable = vscode.languages.registerDefinitionProvider('jqhtml', definitionProvider);
context.subscriptions.push(definitionProviderDisposable);
// Register hover provider for component information
const hoverProvider = new definitionProvider_1.JqhtmlHoverProvider(componentIndex);
const hoverProviderDisposable = vscode.languages.registerHoverProvider('jqhtml', hoverProvider);
context.subscriptions.push(hoverProviderDisposable);
// Register auto-closing tag functionality
const autoCloseDisposable = vscode.workspace.onDidChangeTextDocument((event) => {
if (event.document.languageId !== 'jqhtml') {
return;
}
// Check if we should auto-close
const activeEditor = vscode.window.activeTextEditor;
if (!activeEditor || activeEditor.document !== event.document) {
return;
}
// Only process single character changes (typing)
if (event.contentChanges.length !== 1) {
return;
}
const change = event.contentChanges[0];
const text = change.text;
// Check if user typed '>'
if (text === '>') {
const position = change.range.start;
const line = event.document.lineAt(position.line);
const lineText = line.text.substring(0, position.character + 1);
// Match opening tags: <ComponentName>, <Define:Name>, or regular HTML tags
// Look for self-closing indicators /> or existing closing tags
const openingTagMatch = lineText.match(/<(\/?)(Define:|#)?([A-Z][A-Za-z0-9_]*|\w+)(?:\s+[^>]*)?>$/);
if (openingTagMatch && !openingTagMatch[1]) { // Not a closing tag (no /)
const tagPrefix = openingTagMatch[2] || ''; // 'Define:' or '#' or ''
const tagName = openingTagMatch[3];
// Check if it's self-closing or already has a closing tag
const beforeTag = lineText.substring(0, lineText.lastIndexOf('<'));
if (beforeTag.endsWith('/')) {
return; // Self-closing tag
}
// Check if this is a slot tag (starts with #)
const isSlot = tagPrefix === '#';
// For slots, check if it's self-closing syntax
if (isSlot && lineText.match(/<#\w+\s*\/?>$/)) {
// Don't auto-close self-closing slots
if (lineText.endsWith('/>')) {
return;
}
}
// Check if we should auto-close this tag
// Component tags (start with capital), Define: tags, and slot tags
const shouldAutoClose = tagName[0] === tagName[0].toUpperCase() ||
tagPrefix === 'Define:' ||
isSlot ||
isHtmlTag(tagName);
if (shouldAutoClose) {
// Build the closing tag
let closingTag = '';
if (isSlot) {
closingTag = `</#${tagName}>`;
}
else {
closingTag = `</${tagPrefix}${tagName}>`;
}
// Insert the closing tag
activeEditor.edit((editBuilder) => {
const insertPosition = position.translate(0, 1);
editBuilder.insert(insertPosition, closingTag);
}, { undoStopBefore: false, undoStopAfter: false }).then(() => {
// Move cursor between the tags
const newPosition = position.translate(0, 1);
activeEditor.selection = new vscode.Selection(newPosition, newPosition);
});
}
}
}
});
context.subscriptions.push(autoCloseDisposable);
// Register format on save if enabled
const config = vscode.workspace.getConfiguration('editor');
if (config.get('formatOnSave')) {
console.log('JQHTML: Format on save is enabled');
}
console.log('JQHTML: All features registered (formatter, auto-close, goto definition, hover)');
// Return public API for other extensions
return {
findComponent: (name) => componentIndex.findComponent(name),
getAllComponentNames: () => componentIndex.getAllComponentNames(),
reindexWorkspace: () => componentIndex.reindexWorkspace()
};
}
// Helper function to check if a tag is a standard HTML tag
function isHtmlTag(tagName) {
const htmlTags = [
'div', 'span', 'p', 'a', 'button', 'input', 'form', 'header', 'footer',
'section', 'article', 'nav', 'main', 'aside', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'ul', 'ol', 'li', 'table', 'tr', 'td', 'th', 'thead', 'tbody', 'tfoot',
'img', 'video', 'audio', 'canvas', 'svg', 'iframe', 'label', 'select', 'option',
'textarea', 'fieldset', 'legend', 'details', 'summary', 'dialog', 'template',
'blockquote', 'pre', 'code', 'em', 'strong', 'small', 'mark', 'del', 'ins', 'sub', 'sup'
];
return htmlTags.includes(tagName.toLowerCase());
}
function deactivate() {
console.log('JQHTML extension deactivated');
}
//# sourceMappingURL=extension.js.map

1
node_modules/@jqhtml/vscode-extension/out/extension.js.map generated vendored Executable file
View File

@@ -0,0 +1 @@
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"}

313
node_modules/@jqhtml/vscode-extension/out/formatter.js generated vendored Executable file
View File

@@ -0,0 +1,313 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.JqhtmlFormattingEditProvider = void 0;
const vscode = __importStar(require("vscode"));
class JqhtmlFormattingEditProvider {
constructor() {
this.indentSize = 2;
// IMPORTANT: DO NOT USE REGEX FOR PARSING IN THIS FORMATTER
// This formatter uses string manipulation and indexOf for reliability
// Regex should only be used in the syntax highlighter, not here
// Based on the RS3 formatter (reformat_html.php) logic
// Patterns that increase indent on the NEXT line
this.indentIncrease = [': %>', ': ?>', '{ %>', '{ ?>'];
// Patterns that decrease indent
this.indentDecrease = [
'<% end; %>',
'<% endif; %>',
'<% endfor; %>',
'<% endforeach; %>',
'<% endfunction; %>',
'<% } %>',
'<% }); %>',
'<% } else',
'<% else'
];
// Known self-closing HTML tags
this.selfClosingTags = [
'area', 'base', 'br', 'embed', 'hr', 'iframe',
'img', 'input', 'link', 'meta', 'param', 'source', 'track'
];
}
provideDocumentFormattingEdits(document, options) {
this.indentSize = options.tabSize || 2;
const formatted = this.formatDocument(document);
const fullRange = new vscode.Range(document.positionAt(0), document.positionAt(document.getText().length));
return [vscode.TextEdit.replace(fullRange, formatted)];
}
formatDocument(document) {
const text = document.getText();
const safeCode = [];
let working = text;
let reading = text;
// Step 1: Escape HTML comments
working = '';
while (reading.indexOf('<!--') !== -1) {
const pos = reading.indexOf('<!--');
working += reading.substring(0, pos);
reading = reading.substring(pos);
const closePos = reading.indexOf('-->');
if (closePos === -1) {
// Parse error, return original
return text;
}
safeCode.push(reading.substring(0, closePos + 3));
reading = reading.substring(closePos + 3);
working += '@@__SAFE__(' + (safeCode.length - 1) + ')';
}
working += reading;
reading = working;
// Step 2: Escape multiline <% %> blocks
working = '';
while (reading.indexOf('<%') !== -1) {
const pos = reading.indexOf('<%');
working += reading.substring(0, pos);
reading = reading.substring(pos);
const closePos = reading.indexOf('%>');
if (closePos === -1) {
// Parse error, return original
return text;
}
const nlPos = reading.indexOf('\n');
if (nlPos === -1 || nlPos > closePos) {
// Not multiline, keep it
working += reading.substring(0, closePos + 2);
reading = reading.substring(closePos + 2);
continue;
}
// It's multiline, escape it
safeCode.push(reading.substring(0, closePos + 2));
reading = reading.substring(closePos + 2);
working += '@@__SAFE__(' + (safeCode.length - 1) + ')';
}
working += reading;
// Step 3: Split into lines with indent levels
const lines = [];
const splitLines = working.split('\n');
for (const line of splitLines) {
lines.push([0, line.trim()]);
}
// Step 4: Handle JS/control flow indents (if:, endif;, etc)
let jsIndent = 0;
for (let i = 0; i < lines.length; i++) {
const trimmedLine = lines[i][1];
let plus = 0;
let minus = 0;
// Check for indent increase patterns
for (const pattern of this.indentIncrease) {
if (trimmedLine.indexOf(pattern) !== -1) {
plus++;
}
}
// Check for indent decrease patterns
for (const pattern of this.indentDecrease) {
if (trimmedLine.indexOf(pattern) !== -1) {
minus++;
}
}
// Apply indent changes
if (plus > minus) {
lines[i][0] = jsIndent;
jsIndent += plus;
jsIndent -= minus;
}
else {
jsIndent += plus;
jsIndent -= minus;
lines[i][0] = jsIndent;
}
// Special handling for else statements
if (trimmedLine.startsWith('<% else') ||
trimmedLine.startsWith('<% } else')) {
lines[i][0]--;
}
}
// Step 5: Escape remaining single-line code blocks
for (let i = 0; i < lines.length; i++) {
reading = lines[i][1];
working = '';
// Escape <% %> blocks
while (reading.indexOf('<%') !== -1) {
const pos = reading.indexOf('<%');
working += reading.substring(0, pos);
reading = reading.substring(pos);
const closePos = reading.indexOf('%>');
if (closePos === -1) {
working += reading;
reading = '';
continue;
}
safeCode.push(reading.substring(0, closePos + 2));
reading = reading.substring(closePos + 2);
working += '@@__SAFE__(' + (safeCode.length - 1) + ')';
}
working += reading;
lines[i][1] = working;
}
// Step 6: Handle HTML tag indents
let htmlIndent = 0;
for (let i = 0; i < lines.length; i++) {
const line = lines[i][1];
let thisIndent = 0;
// Count opening tags
thisIndent += this.countOccurrences(line, '<');
// Subtract self-closing tags
thisIndent -= this.countOccurrences(line, '/>');
// Subtract closing tags (count double)
thisIndent -= this.countOccurrences(line, '</') * 2;
// Handle known self-closing tags
for (const tag of this.selfClosingTags) {
const searchStr = '<' + tag;
if (line.indexOf(searchStr) !== -1) {
// Split by this tag and check each occurrence
const parts = line.split(searchStr);
for (let j = 1; j < parts.length; j++) {
// Check if it's not self-closed with />
if (parts[j].indexOf('/>') === -1 && parts[j].indexOf('>') !== -1) {
thisIndent--;
}
else if (parts[j].indexOf('/>') !== -1 &&
parts[j].indexOf('>') !== -1 &&
parts[j].indexOf('/>') > parts[j].indexOf('>')) {
// Has both > and />, but > comes first
thisIndent--;
}
}
}
}
// Special case for DOCTYPE
if (line.indexOf('<!DOCTYPE') !== -1) {
thisIndent--;
}
// Apply indent changes
if (thisIndent < 0) {
// Negative change - apply before this line
htmlIndent += thisIndent;
lines[i][0] += htmlIndent;
}
else {
// Positive/zero change - apply after this line
lines[i][0] += htmlIndent;
htmlIndent += thisIndent;
}
// Multiline self-closing tag (line has /> but no <)
if (line.indexOf('/>') !== -1 && line.indexOf('<') === -1) {
lines[i][0]++;
}
}
// Step 7: Build result with proper indentation
let result = '';
for (const [indent, line] of lines) {
const finalIndent = Math.max(0, indent);
if (line.length > 0) {
result += ' '.repeat(finalIndent * this.indentSize) + line + '\n';
}
else {
result += '\n';
}
}
// Step 8: Restore safe blocks
for (let attempt = 0; attempt < 10; attempt++) {
let hasChanges = false;
for (let i = 0; i < safeCode.length; i++) {
const placeholder = '@@__SAFE__(' + i + ')';
if (result.indexOf(placeholder) !== -1) {
result = result.replace(placeholder, safeCode[i]);
hasChanges = true;
}
}
if (!hasChanges || result.indexOf('@@__SAFE__') === -1) {
break;
}
}
// Step 9: Add blank lines around Define tag contents
result = this.addDefineTagSpacing(result);
return result.trim();
}
addDefineTagSpacing(text) {
const lines = text.split('\n');
const resultLines = [];
for (let i = 0; i < lines.length; i++) {
const currentLine = lines[i];
const trimmedCurrent = currentLine.trim();
// Check if this is an opening Define tag
if (trimmedCurrent.startsWith('<Define:') && trimmedCurrent.endsWith('>') && !trimmedCurrent.includes('</')) {
resultLines.push(currentLine);
// Check if next line exists and is not already blank
if (i + 1 < lines.length) {
const nextLine = lines[i + 1];
const trimmedNext = nextLine.trim();
// Only add blank line if:
// 1. Next line is not already blank
// 2. Next line is not the closing Define tag
if (trimmedNext.length > 0 && !trimmedNext.startsWith('</Define:')) {
resultLines.push('');
}
}
}
// Check if this is a closing Define tag
else if (trimmedCurrent.startsWith('</Define:') && trimmedCurrent.endsWith('>')) {
// Check if previous line exists and is not already blank
if (i > 0) {
const prevLine = lines[i - 1];
const trimmedPrev = prevLine.trim();
// Only add blank line if:
// 1. Previous line is not already blank
// 2. Previous line is not the opening Define tag
if (trimmedPrev.length > 0 && !trimmedPrev.startsWith('<Define:') && resultLines[resultLines.length - 1].trim().length > 0) {
resultLines.push('');
}
}
resultLines.push(currentLine);
}
else {
resultLines.push(currentLine);
}
}
return resultLines.join('\n');
}
countOccurrences(str, search) {
let count = 0;
let pos = 0;
while ((pos = str.indexOf(search, pos)) !== -1) {
count++;
pos += search.length;
}
return count;
}
}
exports.JqhtmlFormattingEditProvider = JqhtmlFormattingEditProvider;
//# sourceMappingURL=formatter.js.map

1
node_modules/@jqhtml/vscode-extension/out/formatter.js.map generated vendored Executable file

File diff suppressed because one or more lines are too long