Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 63 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,41 @@ We offer two methods to set up your development environment:
2. Run the following command in the project root:

```
docker compose up -d --build
docker compose up -d --build
```

Run this command everytime you need to verify your modifications.


#### Apple Silicon (ARM64) Compatibility

If you're using an Apple Silicon Mac and encounter Docker build errors, you have several options:

**Option A: Local Override File (Recommended)**
Create a `docker-compose.override.yml` file in the project root:

```yaml
services:
plugin:
platform: linux/amd64
demo:
platform: linux/amd64
```

**Option B: Environment Variable**

```bash
export DOCKER_DEFAULT_PLATFORM=linux/amd64
docker compose up -d --build
```

### Option 2: Manual Setup

If you prefer not to use Docker, follow these steps:

1. Install project dependencies:

```
npm install
npm install
```

2. Set up Playwright:
Expand All @@ -37,9 +59,43 @@ npx playwright install
3. Build the project:

```
npm run build
npm run build
```

## Available Scripts

The project provides several npm scripts for development:

```bash
# Format code with Biome
npm run format

# Run Docker build process
npm run docker

# Format code and run Docker build (combines both above)
npm run build:docker

# Run full build pipeline (TypeScript, tests, linting, mutation testing)
npm run build
```

## Code Formatting

To format the entire codebase, you can use either:

```bash
npm run format
```

Or directly:

```bash
npx biome format --write .
```

This will automatically format all files according to the project's style guidelines.

## Code Coverage and Testing

We use Stryker for code coverage verification. If you add new code, you'll likely need to add corresponding tests with Vitest. Pull requests with insufficient code coverage will not pass the build process.
Expand Down
25 changes: 19 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![npm](https://img.shields.io/badge/coverage-blue)](https://ferdodo.github.io/typedoc-plugin-include-example/reports/mutation/mutation.html)
[![npm](https://img.shields.io/badge/demo-green)](https://ferdodo.github.io/typedoc-plugin-include-example/)

Include code examples in your [typedoc](https://typedoc.org/) documentations.
Include code examples in your [typedoc](https://typedoc.org/) documentations with powerful bracket syntax for line selection.

## Installation

Expand All @@ -22,8 +22,8 @@ Write your example in a `*.example.ts` file.
```javascript
// greet.example.ts

import { greet } from "./greet.js"
greet(); // Prints greetings
import { greet } from "./greet.js";
greet(); // Prints greetings
```

Add the @includeExample tag to the actual code.
Expand All @@ -33,11 +33,11 @@ Add the @includeExample tag to the actual code.

/**
* Says hello !
*
*
* @includeExample
*/
export function greet() {
console.log("Hello there.")
console.log("Hello there.");
}
```

Expand All @@ -47,9 +47,22 @@ Then generate your documentation using typedoc using this plugin.
$ npx typedoc --plugin typedoc-plugin-include-example
```

## Line Selection

Control which lines to include with bracket syntax:

```typescript
/**
* @includeExample greet.example.ts // Include entire file
* @includeExample greet.example.ts[5] // Include line 5 only
* @includeExample greet.example.ts[2:8] // Include lines 2-8
* @includeExample greet.example.ts[2:5,10,15:20] // Multiple selections
*/
```

## Features

See the [Documentation](./docs.md) for full usage.
See the [Documentation](./docs.md) for full usage including advanced bracket syntax, exclusions, negative indexing, and troubleshooting.

## Links

Expand Down
2 changes: 1 addition & 1 deletion demo/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ COPY --from=plugin /typedoc-plugin-include-example/plugin /typedoc-plugin-includ
WORKDIR /typedoc-plugin-include-example/plugin
RUN npm pack
WORKDIR /typedoc-plugin-include-example/demo
RUN npm install ../plugin/typedoc-plugin-include-example-2.1.2.tgz
RUN npm install ../plugin/typedoc-plugin-include-example-3.0.0.tgz

COPY . .
RUN npm run build
Expand Down
2 changes: 1 addition & 1 deletion demo/src/Author.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Book } from "./Book";
/**
* A class representing an author.
*
* @includeExample ./src/Author.example.ts:7
* @includeExample ./src/Author.example.ts[7]
*/
export class Author {
books: Book[] = [];
Expand Down
23 changes: 23 additions & 0 deletions demo/src/BookStore.example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Book } from "./Book";
import { BookStore } from "./BookStore";

// Initialize bookstore
const bookstore = new BookStore("The Corner Bookshop", "Downtown");

// Add inventory
const book1 = new Book("1984");
const book2 = new Book("Pride and Prejudice");
// SENSITIVE: Pricing logic - should be excluded from docs
const basePrice = 15.99;
const markup = 0.25;
const finalPrice = basePrice * (1 + markup);
console.log(`Internal pricing: $${finalPrice}`);
// END SENSITIVE SECTION

bookstore.addToInventory(book1);
bookstore.addToInventory(book2);

// Check stock
console.log(`Books in stock: ${bookstore.getInventoryCount()}`);
console.log(`Has '1984': ${bookstore.hasBook("1984")}`);
console.log(`Store: ${bookstore.name} at ${bookstore.location}`);
31 changes: 31 additions & 0 deletions demo/src/BookStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Book } from "./Book";

/**
* A class representing a bookstore with inventory management.
*
* @example Inventory management (excluding pricing logic)
* @includeExample ./src/BookStore.example.ts[!10:15]
*/
export class BookStore {
name: string;
inventory: Book[] = [];
location: string;

constructor(name: string, location: string) {
this.name = name;
this.location = location;
}

addToInventory(book: Book): BookStore {
this.inventory.push(book);
return this;
}

getInventoryCount(): number {
return this.inventory.length;
}

hasBook(title: string): boolean {
return this.inventory.some((book) => book.title === title);
}
}
2 changes: 1 addition & 1 deletion demo/src/Chapter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Class representing a chapter.
*
* @includeExample ./src/Chapter.example.ts:5-7,11,13
* @includeExample ./src/Chapter.example.ts[5:7,11,13]
*/
export class Chapter {}
2 changes: 1 addition & 1 deletion demo/src/Library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Book } from "./Book";
/**
* A class representing a library.
*
* @includeExample ./src/Library.example.ts:5-9
* @includeExample ./src/Library.example.ts[5:9]
*/
export class Library {
books: Book[] = [];
Expand Down
25 changes: 25 additions & 0 deletions demo/src/Magazine.example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Book } from "./Book";
import { Magazine } from "./Magazine";

// Magazine header setup
const magazine = new Magazine("Literary Quarterly", 42);
console.log(`Creating ${magazine.getIssueInfo()}`);

// Initialize featured books
const book1 = new Book("Beloved");
const book2 = new Book("One Hundred Years of Solitude");
// End of header processing section

// Content processing section starts here
magazine.featureBook(book1);
magazine.featureBook(book2);

// Add articles to magazine
magazine.addArticle("The Evolution of Modern Literature");
magazine.addArticle("Magical Realism in Contemporary Fiction");
magazine.addArticle("Interview with Emerging Authors");

// Finalize magazine content
console.log(`Featured books: ${magazine.featuredBooks.length}`);
console.log(`Total articles: ${magazine.articles.length}`);
console.log(`${magazine.getIssueInfo()} ready for publication`);
33 changes: 33 additions & 0 deletions demo/src/Magazine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { Book } from "./Book";

/**
* A class representing a literary magazine with article processing.
*
* @example Article header processing (first 11 lines)
* @includeExample ./src/Magazine.example.ts[:11]
*/
export class Magazine {
title: string;
articles: string[] = [];
featuredBooks: Book[] = [];
issueNumber: number;

constructor(title: string, issueNumber: number) {
this.title = title;
this.issueNumber = issueNumber;
}

addArticle(article: string): Magazine {
this.articles.push(article);
return this;
}

featureBook(book: Book): Magazine {
this.featuredBooks.push(book);
return this;
}

getIssueInfo(): string {
return `${this.title} - Issue #${this.issueNumber}`;
}
}
20 changes: 20 additions & 0 deletions demo/src/Publisher.example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Book } from "./Book";
import { Publisher } from "./Publisher";

// Initialize publisher
const publisher = new Publisher("Penguin Random House", 1927);

// Add books to catalog
const book1 = new Book("The Great Gatsby");
const book2 = new Book("To Kill a Mockingbird");
publisher.publishBook(book1);
publisher.publishBook(book2);

// Validate catalog
const totalBooks = publisher.getPublishedCount();
console.log(`Catalog validated: ${totalBooks} books ready`);

// Final publishing steps (these lines demonstrate negative indexing)
console.log("Finalizing publication process...");
console.log("Updating distribution channels...");
console.log(`${publisher.getInfo()} - Publication complete!`);
33 changes: 33 additions & 0 deletions demo/src/Publisher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { Book } from "./Book";

/**
* A class representing a book publisher.
*
* @example Publishing workflow (last 5 steps)
* @includeExample ./src/Publisher.example.ts[-5:]
*/
export class Publisher {
name: string;
books: Book[] = [];
establishedYear: number;

constructor(name: string, establishedYear: number) {
this.name = name;
this.establishedYear = establishedYear;
}

publishBook(book: Book): Publisher {
this.books.push(book);
return this;
}

getPublishedCount(): number {
return this.books.length;
}

getInfo(): string {
return `${this.name} (Est. ${
this.establishedYear
}) - ${this.getPublishedCount()} books published`;
}
}
24 changes: 24 additions & 0 deletions demo/src/Review.example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Book } from "./Book";
import { Review } from "./Review";

// Setup review data
const book = new Book("The Catcher in the Rye");
// VALIDATION: Input sanitization - should be excluded
const sanitizedComment = "A profound coming-of-age story";
const validatedRating = Math.min(Math.max(5, 1), 5);
console.log(`Validation: Rating ${validatedRating} approved`);
// END VALIDATION SECTION

// Create review instance
const review = new Review(book, 5, sanitizedComment, "Literary Critic");

// Process review
console.log("Processing review...");
const isValidReview = review.isValid();

// Summary and output
console.log("Review processing complete");
console.log(`Valid review: ${isValidReview}`);
console.log(`Formatted: ${review.getFormattedReview()}`);
console.log(`Book: ${review.book.title}`);
console.log("Review ready for publication");
Loading
Loading