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
76 changes: 76 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

ember-cli-addon-docs is an Ember addon that generates documentation sites for other Ember addons. It provides components for building doc sites, a build pipeline that extracts API docs and search indexes, and a deploy pipeline for GitHub Pages.

## Commands

- **Install:** `pnpm install`
- **Dev server:** `pnpm start` (serves dummy app at http://localhost:4200)
- **Build:** `pnpm build`
- **Lint all:** `pnpm lint`
- **Lint fix:** `pnpm lint:fix`
- **Run all tests:** `pnpm test`
- **Ember tests only:** `pnpm test:ember`
- **Ember tests in watch mode:** `pnpm test:ember --server`
- **Node tests only:** `pnpm test:node` (mocha, runs tests in `tests-node/`)
- **Test app tests:** `pnpm test:test-apps` (runs tests in `test-apps/new-addon`)

Uses pnpm as the package manager. The workspace includes `test-apps/*`.

## Architecture

### Build Pipeline (lib/)

The core build logic lives in `index.js` and `lib/`. During Ember's build process:

1. **`index.js`** — Main addon entry point. Hooks into Ember CLI's `treeForApp`, `treeForAddon`, `treeForPublic`, and `treeForVendor`. Compiles markdown templates, extracts API docs via plugin registry, and builds a search index.

2. **`lib/broccoli/`** — Broccoli plugins for the build pipeline:
- `docs-compiler.js` — Compiles extracted API documentation into JSON API format
- `search-indexer.js` — Builds a lunr.js search index from docs and template content
- `docs-filter.js` / `hbs-content-filter.js` — Broccoli filters for processing files

3. **`lib/preprocessors/`** — Template preprocessors:
- `markdown-template-compiler.js` — Compiles `.md` files into Handlebars templates
- `hbs-content-extractor.js` — Extracts content from HBS templates for search indexing

4. **`lib/deploy/`** — ember-cli-deploy plugin for deploying docs to GitHub Pages

5. **`lib/models/plugin-registry.js`** — Registry for doc generation plugins (e.g., `ember-cli-addon-docs-yuidoc`)

### Runtime Addon (addon/)

Ember Octane components and services that consuming addons use in their doc sites:

- **Components:** `docs-viewer`, `docs-header`, `docs-hero`, `docs-demo`, `docs-snippet`, `docs-code-highlight`, `api/` (API doc viewer components), etc.
- **Services:** `docs-routes` (navigation), `docs-search` (lunr-based search), `project-version` (version management)
- **Styles:** Uses Tailwind CSS 1.x compiled via PostCSS/Sass pipeline

### App Re-exports (app/)

Standard Ember addon pattern — re-exports addon modules into the consuming app's namespace.

### Blueprints (blueprints/)

- `ember-cli-addon-docs` — Default blueprint run on `ember install`
- `docs-page` — Generator for new documentation pages

### Sandbox (sandbox/)

A "sandbox" addon used as a secondary documented project in the dummy app, demonstrating multi-project documentation support.

### Tests

- `tests/` — Ember tests (acceptance, integration, unit) using QUnit, run via testem in Chrome
- `tests-node/` — Node.js unit tests using Mocha/Chai for the build pipeline code in `lib/`
- `test-apps/new-addon` — Separate test app in the pnpm workspace

### Key Concepts

- **Plugin system:** API doc extraction is pluggable via addons with keyword `ember-cli-addon-docs-plugin`. The default plugin is `ember-cli-addon-docs-yuidoc`.
- **`documentingAddonAt`:** Config option allowing a standalone app (not a dummy app) to document an addon at a specific path.
- **Version support:** The addon manages doc versions for deployment, with a "latest" version concept (`-latest`).
28 changes: 0 additions & 28 deletions addon/adapters/-addon-docs.js

This file was deleted.

1 change: 0 additions & 1 deletion addon/adapters/class.js

This file was deleted.

1 change: 0 additions & 1 deletion addon/adapters/component.js

This file was deleted.

1 change: 0 additions & 1 deletion addon/adapters/module.js

This file was deleted.

1 change: 0 additions & 1 deletion addon/adapters/project.js

This file was deleted.

34 changes: 19 additions & 15 deletions addon/components/api/x-class/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { or } from '@ember/object/computed';
import { capitalize } from '../../../utils/string';
import { memberFilter } from '../../../utils/computed';
import { filterMembers } from '../../../utils/computed';
import { addonDocsConfig } from 'ember-cli-addon-docs/-private/config';

export default class XClass extends Component {
Expand All @@ -13,22 +12,27 @@ export default class XClass extends Component {
@tracked showPrivate = false;
@tracked showDeprecated = false;

@memberFilter('args.class', 'accessors')
accessors;
get accessors() {
return filterMembers(this.args.class, 'accessors', this);
}

@memberFilter('args.class', 'methods')
methods;
get methods() {
return filterMembers(this.args.class, 'methods', this);
}

@memberFilter('args.class', 'fields')
fields;
get fields() {
return filterMembers(this.args.class, 'fields', this);
}

@or(
'component.hasInherited',
'component.hasProtected',
'component.hasPrivate',
'component.hasDeprecated',
)
hasToggles;
get hasToggles() {
let klass = this.args.class;
return !!(
klass.hasInherited ||
klass.hasProtected ||
klass.hasPrivate ||
klass.hasDeprecated
);
}

get hasContents() {
let klass = this.args.class;
Expand Down
46 changes: 26 additions & 20 deletions addon/components/api/x-component/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { alias, or } from '@ember/object/computed';
import { capitalize } from '../../../utils/string';
import { memberFilter } from '../../../utils/computed';
import { filterMembers } from '../../../utils/computed';

export default class XComponent extends Component {
@tracked showInherited = false;
Expand All @@ -12,29 +11,36 @@ export default class XComponent extends Component {
@tracked showPrivate = false;
@tracked showDeprecated = false;

@alias('args.component.overloadedYields')
yields;
get yields() {
return this.args.component.overloadedYields;
}

@memberFilter('args.component', 'arguments')
arguments;
get arguments() {
return filterMembers(this.args.component, 'arguments', this);
}

@memberFilter('args.component', 'accessors')
accessors;
get accessors() {
return filterMembers(this.args.component, 'accessors', this);
}

@memberFilter('args.component', 'methods')
methods;
get methods() {
return filterMembers(this.args.component, 'methods', this);
}

@memberFilter('args.component', 'fields')
fields;
get fields() {
return filterMembers(this.args.component, 'fields', this);
}

@or(
'args.component.hasInherited',
'args.component.hasInternal',
'args.component.hasProtected',
'args.component.hasPrivate',
'args.component.hasDeprecated',
)
hasToggles;
get hasToggles() {
let c = this.args.component;
return !!(
c.hasInherited ||
c.hasInternal ||
c.hasProtected ||
c.hasPrivate ||
c.hasDeprecated
);
}

get hasContents() {
let component = this.args.component;
Expand Down
9 changes: 2 additions & 7 deletions addon/components/docs-header/search-box/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { formElementHasFocus } from 'ember-cli-addon-docs/keyboard-config';
import { addonDocsConfig } from 'ember-cli-addon-docs/-private/config';

export default class DocsHeaderSearchBox extends Component {
@service store;
@service docsStore;

constructor() {
super(...arguments);
Expand All @@ -16,13 +16,8 @@ export default class DocsHeaderSearchBox extends Component {

@addonDocsConfig config;

// TODO: The searchbox doesn't work without the project being fetched.
// We should move this logic (and everywhere else in the code that's fetching
// the project) within a new addonDocs service that wires all that up together.
// I think it's fine if our Docs-* components assume there is a single global
// project.
fetchProject = task(async () => {
await this.store.findRecord('project', this.config.projectName);
await this.docsStore.findRecord('project', this.config.projectName);
});

@action
Expand Down
9 changes: 4 additions & 5 deletions addon/components/docs-header/search-results/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { addonDocsConfig } from 'ember-cli-addon-docs/-private/config';
export default class DocsHeaderSearchResults extends Component {
@service docsSearch;
@service router;
@service store;
@service docsStore;

@tracked selectedIndex = null;
@tracked rawSearchResults = [];
Expand All @@ -25,7 +25,7 @@ export default class DocsHeaderSearchResults extends Component {
}

get project() {
return this.store.peekRecord('project', this.config.projectName);
return this.docsStore.peekRecord('project', this.config.projectName);
}

get trimmedQuery() {
Expand Down Expand Up @@ -91,12 +91,11 @@ export default class DocsHeaderSearchResults extends Component {
}
})

// Add a reference to the Ember Data model to each API item search result
// Add a reference to the model to each API item search result
.map((searchResult) => {
let { document } = searchResult;
if (document.type !== 'template') {
let store = this.store;
searchResult.model = store.peekRecord(
searchResult.model = this.docsStore.peekRecord(
document.type,
document.item.id,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Component from '@glimmer/component';
import { set as _set } from 'lodash';

export default class XAutogeneratedApiDocs extends Component {
@service store;
@service docsStore;

@readOnly('args.project.navigationIndex')
sections;
Expand Down
4 changes: 2 additions & 2 deletions addon/components/docs-viewer/x-nav/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class XNav extends Component {
@localCopy('args.root', 'docs')
root;

@service store;
@service docsStore;

@tracked isShowingMenu;

Expand All @@ -31,6 +31,6 @@ export default class XNav extends Component {
return this.args.project;
}

return this.store.peekRecord('project', this.config.projectName);
return this.docsStore.peekRecord('project', this.config.projectName);
}
}
Loading
Loading