Skip to content

feat: updated handling of export signature and multi-line and multi-enclosing type usage without duplication#12

Merged
Coderrob merged 26 commits intomainfrom
feat/barrel-enhancements
Feb 11, 2026
Merged

feat: updated handling of export signature and multi-line and multi-enclosing type usage without duplication#12
Coderrob merged 26 commits intomainfrom
feat/barrel-enhancements

Conversation

@Coderrob
Copy link
Owner

@Coderrob Coderrob commented Feb 9, 2026

Pull Request

Description

This pull request introduces several improvements to repository documentation and packaging configuration, focusing on clarity, maintainability, and ensuring only the intended files are included in published VSIX artifacts. The most important changes are grouped below.

Documentation improvements:

  • AGENTS.md: Expanded to cover CI checks, packaging conventions, and a publish allowlist; clarified test conventions and added guidance for updating docs alongside automation changes.
  • ARCHITECTURE.md: Rewritten for clarity, reflecting current module structure, command flow, barrel generation orchestration, and extensibility points.

Packaging configuration:

  • .vscodeignore: Switched to an allowlist strategy, ignoring everything by default and explicitly including only essential files for VSIX publishing.

Linting configuration:

  • .markdownlint.yml: Disabled duplicate heading checks to accommodate common changelog patterns.

Changelog update:

  • CHANGELOG.md: Added detailed entries for v1.1.1 and v1.1.0, documenting fixes, new features, test coverage, and packaging changes.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring

Checklist

  • I have tested my changes locally
  • I have added/updated tests as needed
  • I have updated documentation as needed
  • My code follows the project's coding standards
  • I have run npm run lint and npm run format:check

Related Issues

…trol

feat: add file size validation in FileSystemService
test: add contract validation tests for Barrel types and enums
chore: update ESLint rules for TypeScript annotations
…r concurrency control

- Added unit tests for array utilities, including `isEmptyArray`.
- Implemented comprehensive tests for custom assertion utilities.
- Created tests for error handling utilities, including `getErrorMessage` and `formatErrorForLog`.
- Developed tests for ESLint plugin helpers and string utilities.
- Introduced a Semaphore class to manage concurrency with a limit on concurrent operations.
- Added tests for the Semaphore class to ensure correct behavior in queuing and releasing permits.
- Updated string utility functions with improved sorting logic and added tests for various scenarios.
- Added type definitions for Logger and OutputChannel interfaces.
…access types; add hardening plan for test coverage
- Bump version in package.json from 1.1.0 to 1.1.1.
- Enhance BarrelContentBuilder to support TypeScript 4.5+ mixed export syntax, combining value and type exports in a single statement.
- Refactor export patterns to handle comments and whitespace variations in export statements.
- Update tests to validate new export handling, including mixed exports and comments.
- Remove deprecated test files and clean up unused imports in various modules.
- Improve logging module exports for better clarity and organization.
Copilot AI review requested due to automatic review settings February 9, 2026 22:25
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors and hardens barrel generation (deduplication, multiline export handling, caching + concurrency), reorganizes the test suite around Node’s node:test, and tightens VSIX packaging via an allowlist-based .vscodeignore. It also updates docs/changelog and bumps the extension version to 1.1.1.

Changes:

  • Add export-pattern parsing + content sanitization + export caching to prevent duplicate exports and preserve direct index.ts declarations during updates.
  • Introduce concurrency helpers (semaphore + concurrent processing) and serialize extension command execution.
  • Restructure tests under src/test/{unit,integration}, update test runner globs/flags, and refresh documentation/packaging metadata.

Reviewed changes

Copilot reviewed 63 out of 66 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
webpack.config.cjs Adjust webpack externals to keep ts-morph (and subpaths) out of the bundle.
src/vscode.ts Replace prior test-facing exports with a pure re-export of the VS Code API for easier module mocking.
src/extension.ts Switch to ./vscode.js indirection and add a command queue to serialize barrel operations.
src/index.ts Minor formatting cleanup (remove stray blank line).
src/utils/string.ts Adjust sortAlphabetically behavior to avoid passing undefined locale/options unnecessarily.
src/utils/semaphore.ts Add Semaphore + processConcurrently concurrency utilities.
src/utils/index.ts Export the new semaphore utilities.
src/types/logger.ts Add shared logger type contracts for runtime + test doubles.
src/types/index.ts Rework type barrel exports and include new logger types.
src/logging/index.ts Consolidate type/value exports from the logging barrel.
src/core/index.ts Minor formatting cleanup (remove stray blank line).
src/core/io/index.ts Minor formatting cleanup (remove stray blank line).
src/core/io/file-system.service.ts Expand ignored directories, make matching case-insensitive, add file-size guard + getFileStats().
src/core/barrel/index.ts Export new barrel helpers (sanitizer, cache, export-pattern utilities).
src/core/barrel/export-patterns.ts Add robust regex-based parsing helpers for export-path extraction + normalization/detection.
src/core/barrel/content-sanitizer.ts Preserve direct declarations while stripping duplicate/parent re-exports (incl. multiline exports).
src/core/barrel/export-cache.ts Cache parsed exports by mtime with bounded size + eviction.
src/core/barrel/barrel-file.generator.ts Integrate sanitizer + export cache + concurrent processing; add recursion depth guard.
src/core/barrel/barrel-content.builder.ts Emit TS 4.5+ mixed export syntax combining value+type exports in a single statement.
src/test/testTypes.ts Inline minimal VS Code types for tests; re-export logger types from src/types.
src/test/testHarness.ts Remove Jest-compat shim (file deleted).
src/test/runTest.ts Point VS Code test runner entry to ./integration/index.js.
src/test/integration/index.ts Add stable placeholder entry point for VS Code integration tests.
src/test/integration/core/parser/export.parser.integration.test.ts Update integration test paths + add recursive test-file discovery.
src/test/unit/extension.test.ts Update mocking to target ../../vscode.js; update logger stub naming and expectations.
src/test/unit/logging/output-channel.logger.test.ts Fix imports due to test folder restructure.
src/test/unit/utils/*.test.ts Update imports to match new folder layout; add new semaphore tests.
src/test/unit/utils/string.smoke.test.ts Add smoke coverage for sortAlphabetically.
src/test/unit/core/parser/*.test.ts Update imports to match new folder layout.
src/test/unit/core/io/file-system.service.test.ts Drop Jest shim usage; add coverage for new file-size guard behavior.
src/test/unit/core/barrel/*.test.ts Add extensive new tests for export-pattern parsing, sanitizer behavior, cache behavior, and generator idempotency/dedup.
src/test/unit/types/contracts.test.ts Add contract tests validating enums/constants/type expectations.
src/test/unit/core/rules/no-instanceof-error-autofix.test.ts Replace prior RuleTester-based tests with lighter metadata/helpers checks (new file).
src/core/rules/no-instanceof-error-autofix.test.ts Remove old RuleTester-based ESLint rule tests (file deleted).
src/core/barrel/barrel-file.generator.test.ts Remove old test file under src/core/** (moved under src/test/unit/**).
scripts/run-tests.cjs Update test discovery globs and enable --experimental-test-module-mocks.
scripts/eslint-plugin-local.mjs Add new local ESLint rules (no-parent-reexport-from-index, no-index-access-types).
scripts/ast-enums.cjs Add new AST node type constants used by the local ESLint rules.
eslint.config.mjs Adjust restricted syntax rules; add new local rules; add no-restricted-imports to discourage direct fs imports.
.vscodeignore Switch to an allowlist-only VSIX packaging strategy.
.markdownlint.yml Disable duplicate heading rule (MD024) for changelog patterns.
package.json Bump version to 1.1.1, refine keywords, remove Jest-related deps, adjust coverage exclude patterns.
package-lock.json Lockfile updates to match dependency changes + version bump.
.gitignore Ignore .depcheck.json and webpack stats artifacts.
README.md Rewrite/refresh docs (features, commands, packaging allowlist, updated coverage badge).
CONTRIBUTING.md Update contributor guidance to match new test/lint/tooling reality.
AGENTS.md Document CI/test/packaging conventions and the VSIX allowlist.
ARCHITECTURE.md Rewrite architecture doc to match current module structure + execution flow.
CHANGELOG.md Add detailed entries for 1.1.1 and 1.1.0.
hardening.md Add/expand hardening plan and test coverage roadmap.
IDEAS.md Add future enhancements backlog doc.
badges/coverage.svg Update coverage badge asset.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1 to 9
# Ignore everything by default
**

# Include only these files
!LICENSE
!package.json
!README.md
!dist/extension.js
!public/img/barrel-roll-icon.png
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.vscodeignore now allowlists only dist/extension.js, but webpack.config.cjs still uses devtool: 'source-map', which typically emits dist/extension.js.map and leaves a //# sourceMappingURL=... reference in extension.js. Publishing without the .map can cause noisy “failed to load source map” warnings in devtools. Either include the .map in the allowlist, or switch webpack to hidden-source-map / nosources-source-map / devtool: false for production VSIX output.

Copilot uses AI. Check for mistakes.
Comment on lines 26 to 92
* Creates a new semaphore with the specified number of permits.
* @param permits The number of permits to initialize the semaphore with.
*/
constructor(private permits: number) {}

/**
* Acquires a permit from the semaphore.
* If no permits are available, the promise will wait until one is released.
* @returns Promise that resolves when a permit is acquired.
*/
async acquire(): Promise<void> {
if (this.permits > 0) {
this.permits--;
return;
}

return new Promise((resolve) => {
this.waiting.push(resolve);
});
}

/**
* Releases a permit back to the semaphore.
* If there are waiting callers, the first one in the queue will be resolved.
*/
release(): void {
this.permits++;
if (this.waiting.length === 0) {
return;
}

const resolve = this.waiting.shift()!;
this.permits--;
resolve();
}

/**
* Returns the current number of available permits.
* @returns The number of available permits.
*/
get availablePermits(): number {
return this.permits;
}

/**
* Returns the number of callers waiting for a permit.
* @returns The number of waiting callers.
*/
get waitingCount(): number {
return this.waiting.length;
}
}

/**
* Processes items concurrently with a specified limit.
* @param items Array of items to process.
* @param concurrencyLimit Maximum number of concurrent operations.
* @param processor Function to process each item.
* @returns Promise that resolves to array of results.
*/
export async function processConcurrently<T, R>(
items: T[],
concurrencyLimit: number,
processor: (item: T) => Promise<R>,
): Promise<R[]> {
const semaphore = new Semaphore(concurrencyLimit);

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semaphore / processConcurrently() accept any permits / concurrencyLimit value, including 0 or negative numbers. With concurrencyLimit <= 0, acquire() will never resolve and processConcurrently() will hang forever. Add input validation (e.g., throw a RangeError) to ensure the limit is a positive integer.

Copilot uses AI. Check for mistakes.
Comment on lines 78 to 91
async getExports(filePath: string): Promise<IParsedExport[]> {
const stats = await this.fileSystemService.getFileStats(filePath);
const currentMtime = stats.mtime.getTime();

// Check cache first
const cached = this.cache.get(filePath);
if (cached?.mtime === currentMtime) {
return cached.exports;
}

// Parse and cache the exports
const content = await this.fileSystemService.readFile(filePath);
const exports = this.exportParser.extractExports(content);

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExportCache.getExports() calls fileSystemService.getFileStats() and then fileSystemService.readFile(). In this PR, FileSystemService.readFile() also performs its own stat() call for the size check, so each cache miss does two stat() syscalls per file. Consider returning size (and possibly mtime) from getFileStats() and allowing readFile() to accept pre-fetched stats (or provide a readFileUnchecked() used by the cache) to avoid the duplicate IO while keeping the size guard.

Copilot uses AI. Check for mistakes.
Comment on lines 135 to 154
private async buildBarrelContent(
directoryPath: string,
entries: Map<string, BarrelEntry>,
barrelFilePath: string,
hasExistingIndex: boolean,
options: NormalizedGenerationOptions,
tsFiles: string[],
subdirectories: string[],
): Promise<string> {
// Determine what extension to use for exports
const exportExtension = await this.determineExportExtension(barrelFilePath, hasExistingIndex);

const newContent = await this.barrelContentBuilder.buildContent(
entries,
directoryPath,
exportExtension,
);

if (!hasExistingIndex || options.mode !== BarrelGenerationMode.UpdateExisting) {
if (!hasExistingIndex) {
return newContent;
}

return this.mergeWithSanitizedExistingContent(
newContent,
barrelFilePath,
directoryPath,
tsFiles,
subdirectories,
);
return this.mergeWithSanitizedExistingContent(newContent, barrelFilePath);
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildBarrelContent() now merges existing barrel content whenever index.ts exists, regardless of generation mode. Because BarrelContentSanitizer preserves any non-parent re-export that won’t be regenerated, this can keep stale/invalid re-export lines (e.g., pointing at files that were deleted) during the default CreateOrUpdate flow. If CreateOrUpdate is intended to “refresh exports”, consider only preserving direct definitions/comments (not old re-exports) unless mode === UpdateExisting, or validate preserved re-export targets still exist before keeping them.

Copilot uses AI. Check for mistakes.
Comment on lines 90 to 98
/**
* Checks if a line is an export statement using AST parsing.
* @param line The line to check.
* @returns True if the line is an export statement.
*/
export function isExportLine(line: string): boolean {
const path = extractExportPath(line);
return path !== null;
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring for isExportLine() says it checks export statements “using AST parsing”, but the implementation is regex-based via extractExportPath(). Update the comment to match the actual approach so readers don’t assume an AST dependency/behavior.

Copilot uses AI. Check for mistakes.
@Coderrob Coderrob merged commit 519de36 into main Feb 11, 2026
6 checks passed
@Coderrob Coderrob deleted the feat/barrel-enhancements branch February 11, 2026 03:27
@Coderrob Coderrob restored the feat/barrel-enhancements branch February 19, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants