@citestyle/registry 0.0.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -55
- package/package.json +20 -6
- package/src/format.js +70 -0
- package/src/index.js +4 -0
- package/types.d.ts +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @citestyle/registry
|
|
2
2
|
|
|
3
|
-
Citation registry
|
|
3
|
+
Citation registry for managing cross-reference state across a document. When you have multiple citations and need them to interact — numbered references, year-suffix disambiguation (Smith 2024a, 2024b), cite collapsing ([1-3, 5]), sorted bibliographies — the registry handles it.
|
|
4
|
+
|
|
5
|
+
For one-off formatting where citations don't interact, this package also exports a simpler `format()` API that needs no setup.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
@@ -8,16 +10,14 @@ Citation registry that manages cross-citation state for a compiled CSL style. Ha
|
|
|
8
10
|
npm install @citestyle/registry
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
##
|
|
13
|
+
## Quick start
|
|
12
14
|
|
|
13
|
-
```
|
|
15
|
+
```javascript
|
|
14
16
|
import { createRegistry } from '@citestyle/registry'
|
|
15
17
|
import * as apa from '@citestyle/styles/apa'
|
|
16
18
|
|
|
17
|
-
// Create a registry bound to a compiled style
|
|
18
19
|
const registry = createRegistry(apa)
|
|
19
20
|
|
|
20
|
-
// Add items (assigns citation numbers, triggers disambiguation)
|
|
21
21
|
registry.addItems([
|
|
22
22
|
{
|
|
23
23
|
id: 'smith2024',
|
|
@@ -40,84 +40,129 @@ registry.addItems([
|
|
|
40
40
|
},
|
|
41
41
|
])
|
|
42
42
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
console.log(citation.html) // <span class="csl-citation">(Smith, 2024)</span>
|
|
43
|
+
// Inline citation
|
|
44
|
+
registry.cite([{ id: 'smith2024' }])
|
|
45
|
+
// → { text: '(Smith, 2024)', html: '<span class="csl-citation">...</span>' }
|
|
47
46
|
|
|
48
|
-
// Citation with locator
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
])
|
|
52
|
-
console.log(withPage.text) // (Smith, 2024, p. 105)
|
|
47
|
+
// Citation with page locator
|
|
48
|
+
registry.cite([{ id: 'smith2024', locator: '105', label: 'page' }])
|
|
49
|
+
// → { text: '(Smith, 2024, p. 105)', html: '...' }
|
|
53
50
|
|
|
54
|
-
// Multi-cite
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{ id: 'doe2023' },
|
|
58
|
-
])
|
|
59
|
-
console.log(multi.text) // (Doe, 2023; Smith, 2024)
|
|
51
|
+
// Multi-cite (sorted per style rules)
|
|
52
|
+
registry.cite([{ id: 'smith2024' }, { id: 'doe2023' }])
|
|
53
|
+
// → { text: '(Doe, 2023; Smith, 2024)', html: '...' }
|
|
60
54
|
|
|
61
|
-
//
|
|
55
|
+
// Full bibliography — sorted, numbered, disambiguated
|
|
62
56
|
const entries = registry.getBibliography()
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
entries[0].text // Plain text
|
|
58
|
+
entries[0].html // Semantic HTML with CSS classes and linked DOIs
|
|
59
|
+
entries[0].parts // Decomposed fields for custom layouts
|
|
60
|
+
entries[0].links // Extracted DOI, URL links
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Simple API (no registry)
|
|
64
|
+
|
|
65
|
+
When you just need to format one or a few items and don't need cross-reference features:
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
```javascript
|
|
68
|
+
import { format, formatAll, formatCitation } from '@citestyle/registry'
|
|
69
|
+
import * as apa from '@citestyle/styles/apa'
|
|
70
|
+
|
|
71
|
+
// Single bibliography entry
|
|
72
|
+
const entry = format(apa, item)
|
|
73
|
+
// → { html, text, parts, links }
|
|
74
|
+
|
|
75
|
+
// Multiple entries (sorted per style rules, auto-numbered)
|
|
76
|
+
const entries = formatAll(apa, [item1, item2, item3])
|
|
77
|
+
|
|
78
|
+
// Single inline citation
|
|
79
|
+
const cite = formatCitation(apa, [{ item, locator: '42', label: 'page' }])
|
|
80
|
+
// → { html, text }
|
|
70
81
|
```
|
|
71
82
|
|
|
72
|
-
|
|
83
|
+
Use `createRegistry()` instead when you need any of the cross-reference features below.
|
|
73
84
|
|
|
74
|
-
|
|
85
|
+
## When to use the registry vs. `format()`
|
|
75
86
|
|
|
76
|
-
|
|
87
|
+
| Feature | `format()` | `createRegistry()` |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| Format a bibliography entry | Yes | Yes |
|
|
90
|
+
| Format a citation | Yes | Yes |
|
|
91
|
+
| Sort bibliography | Yes | Yes |
|
|
92
|
+
| Citation numbering (IEEE, Vancouver) | No | Yes |
|
|
93
|
+
| Year-suffix disambiguation (2024a, 2024b) | No | Yes |
|
|
94
|
+
| Name disambiguation (expand initials/names) | No | Yes |
|
|
95
|
+
| Cite collapsing ([1-3] or "Smith 2020, 2021") | No | Yes |
|
|
96
|
+
| Subsequent-author-substitute (em-dash) | No | Yes |
|
|
77
97
|
|
|
78
|
-
|
|
79
|
-
- `options.subsequentAuthorSubstitute` (string) -- Override the style's substitute string (e.g., `"---"`)
|
|
98
|
+
**Rule of thumb**: use `format()` for publication lists, portfolio pages, and anywhere each entry stands alone. Use `createRegistry()` for documents — papers, articles, blog posts — where citations reference and interact with each other.
|
|
80
99
|
|
|
81
|
-
|
|
100
|
+
## API
|
|
101
|
+
|
|
102
|
+
### `createRegistry(style, options?)`
|
|
103
|
+
|
|
104
|
+
Create a new registry bound to a compiled style.
|
|
82
105
|
|
|
83
|
-
|
|
106
|
+
- `style` — A compiled style module (from `@citestyle/styles/*` or your own compiled `.js`)
|
|
107
|
+
- `options.subsequentAuthorSubstitute` (string) — Override the style's substitute string (e.g., `"---"`)
|
|
84
108
|
|
|
85
|
-
|
|
109
|
+
### `registry.addItems(items)`
|
|
86
110
|
|
|
87
|
-
Add CSL-JSON items
|
|
111
|
+
Add CSL-JSON items. Items are stored by `id` and assigned citation numbers in insertion order. Adding an item with a duplicate ID updates the existing entry.
|
|
88
112
|
|
|
89
|
-
|
|
113
|
+
### `registry.getItem(id)`
|
|
90
114
|
|
|
91
115
|
Look up a single item by ID. Returns `undefined` if not found.
|
|
92
116
|
|
|
93
|
-
|
|
117
|
+
### `registry.cite(cites, ctx?)`
|
|
94
118
|
|
|
95
|
-
Format a citation cluster. Each cite
|
|
119
|
+
Format a citation cluster. Each cite can include:
|
|
96
120
|
|
|
97
121
|
| Property | Type | Description |
|
|
98
122
|
|---|---|---|
|
|
99
|
-
| `id` | string | Item ID (
|
|
123
|
+
| `id` | string | Item ID (looked up from registry) |
|
|
100
124
|
| `item` | CslItem | Pre-resolved item (bypasses lookup) |
|
|
101
|
-
| `locator` | string | Locator value (
|
|
102
|
-
| `label` | string | Locator label
|
|
103
|
-
| `prefix` | string | Text before the citation |
|
|
104
|
-
| `suffix` | string | Text after the citation |
|
|
125
|
+
| `locator` | string | Locator value (page number, chapter, etc.) |
|
|
126
|
+
| `label` | string | Locator label: `'page'`, `'chapter'`, `'section'`, etc. |
|
|
127
|
+
| `prefix` | string | Text inserted before the citation |
|
|
128
|
+
| `suffix` | string | Text appended after the citation |
|
|
105
129
|
|
|
106
130
|
Returns `{ text: string, html: string }`.
|
|
107
131
|
|
|
108
|
-
|
|
132
|
+
### `registry.getBibliography(ctx?)`
|
|
133
|
+
|
|
134
|
+
Get the full formatted bibliography. Items are sorted per the style's sort rules. Returns an array of `FormattedEntry` objects:
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
{
|
|
138
|
+
text: string, // Plain text
|
|
139
|
+
html: string, // Semantic HTML with CSS classes and auto-linked DOIs
|
|
140
|
+
parts: object, // Decomposed fields (authors, year, title, ...)
|
|
141
|
+
links: object, // Extracted links (doi, url)
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `registry.size`
|
|
146
|
+
|
|
147
|
+
Read-only property: number of items in the registry.
|
|
148
|
+
|
|
149
|
+
### `format(style, item, ctx?)`
|
|
150
|
+
|
|
151
|
+
Format a single bibliography entry without a registry. Returns `{ text, html, parts, links }`.
|
|
152
|
+
|
|
153
|
+
### `formatAll(style, items, ctx?)`
|
|
109
154
|
|
|
110
|
-
|
|
155
|
+
Format multiple bibliography entries. Applies the style's sort order and assigns citation numbers. Returns an array of `{ text, html, parts, links }`.
|
|
111
156
|
|
|
112
|
-
|
|
157
|
+
### `formatCitation(style, cites, ctx?)`
|
|
113
158
|
|
|
114
|
-
|
|
159
|
+
Format a single citation cluster without a registry. Each cite must include an `item` property (not an `id`, since there's no registry to look it up from). Returns `{ text, html }`.
|
|
115
160
|
|
|
116
|
-
##
|
|
161
|
+
## What the registry handles automatically
|
|
117
162
|
|
|
118
|
-
- **Citation numbering
|
|
119
|
-
- **Bibliography sorting
|
|
120
|
-
- **Year-suffix
|
|
121
|
-
- **Name disambiguation
|
|
122
|
-
- **Cite collapsing
|
|
123
|
-
- **Subsequent-author-substitute
|
|
163
|
+
- **Citation numbering** — Numeric styles (IEEE, Vancouver) get auto-assigned `[1]`, `[2]`, etc. in insertion order
|
|
164
|
+
- **Bibliography sorting** — Uses the style's compiled sort comparator (alphabetical for APA, insertion-order for IEEE, etc.)
|
|
165
|
+
- **Year-suffix disambiguation** — When two items share the same author(s) and year, the registry assigns suffixes: Smith (2024a), Smith (2024b)
|
|
166
|
+
- **Name disambiguation** — Expands initials or adds names to distinguish ambiguous citations, following the style's `disambiguate-add-givenname` rules (5 rule variants supported)
|
|
167
|
+
- **Cite collapsing** — Numeric ranges: `[1, 2, 3, 5]` → `[1-3, 5]`. Author-date grouping: `(Smith 2020; Smith 2021)` → `(Smith 2020, 2021)`
|
|
168
|
+
- **Subsequent-author-substitute** — Replaces repeated authors in the bibliography with a dash or other substitute string, per the style's rules
|
package/package.json
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@citestyle/registry",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "Citation registry: year-suffixes, numbering, sorting (~5-8KB)",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Citation registry: year-suffixes, numbering, sorting, disambiguation (~5-8KB)",
|
|
5
|
+
"author": "Uniweb",
|
|
6
|
+
"homepage": "https://github.com/uniweb/csl/tree/main/packages/registry",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/uniweb/csl.git",
|
|
10
|
+
"directory": "packages/registry"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"csl",
|
|
14
|
+
"citation",
|
|
15
|
+
"registry",
|
|
16
|
+
"bibliography",
|
|
17
|
+
"disambiguation",
|
|
18
|
+
"year-suffix"
|
|
19
|
+
],
|
|
5
20
|
"type": "module",
|
|
6
21
|
"exports": {
|
|
7
22
|
".": {
|
|
@@ -15,8 +30,8 @@
|
|
|
15
30
|
"README.md"
|
|
16
31
|
],
|
|
17
32
|
"dependencies": {
|
|
18
|
-
"@citestyle/core": "0.0
|
|
19
|
-
"@citestyle/types": "0.0
|
|
33
|
+
"@citestyle/core": "1.0.0",
|
|
34
|
+
"@citestyle/types": "1.0.0"
|
|
20
35
|
},
|
|
21
36
|
"devDependencies": {
|
|
22
37
|
"vitest": "^3.1.1"
|
|
@@ -26,7 +41,6 @@
|
|
|
26
41
|
},
|
|
27
42
|
"license": "MIT",
|
|
28
43
|
"scripts": {
|
|
29
|
-
"test": "vitest run --passWithNoTests"
|
|
30
|
-
"lint": "echo 'TODO: configure linter'"
|
|
44
|
+
"test": "vitest run --passWithNoTests"
|
|
31
45
|
}
|
|
32
46
|
}
|
package/src/format.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple formatting API — format items without a full registry.
|
|
3
|
+
*
|
|
4
|
+
* Use these for one-off formatting where you don't need cross-reference
|
|
5
|
+
* features (year-suffix, citation numbering, disambiguation, collapsing).
|
|
6
|
+
* For documents with multiple citations, use createRegistry() instead.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Format a single bibliography entry.
|
|
11
|
+
*
|
|
12
|
+
* @param {import('@citestyle/types').CompiledStyle} style - A compiled CSL style module
|
|
13
|
+
* @param {import('@citestyle/types').CslItem} item - CSL-JSON item
|
|
14
|
+
* @param {import('@citestyle/types').FormatContext} [ctx] - Optional format context
|
|
15
|
+
* @returns {import('@citestyle/types').FormattedEntry}
|
|
16
|
+
*/
|
|
17
|
+
export function format(style, item, ctx = {}) {
|
|
18
|
+
if (!style?.bibliography) {
|
|
19
|
+
throw new Error('format() requires a compiled style with a bibliography() function')
|
|
20
|
+
}
|
|
21
|
+
return style.bibliography(item, ctx)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Format multiple bibliography entries with basic sorting.
|
|
26
|
+
*
|
|
27
|
+
* Items are sorted using the style's sort comparator (if any) and assigned
|
|
28
|
+
* citation numbers in order. Does NOT perform year-suffix disambiguation,
|
|
29
|
+
* name disambiguation, or subsequent-author-substitute — use createRegistry()
|
|
30
|
+
* for those features.
|
|
31
|
+
*
|
|
32
|
+
* @param {import('@citestyle/types').CompiledStyle} style - A compiled CSL style module
|
|
33
|
+
* @param {import('@citestyle/types').CslItem[]} items - CSL-JSON items
|
|
34
|
+
* @param {import('@citestyle/types').FormatContext} [ctx] - Optional format context
|
|
35
|
+
* @returns {import('@citestyle/types').FormattedEntry[]}
|
|
36
|
+
*/
|
|
37
|
+
export function formatAll(style, items, ctx = {}) {
|
|
38
|
+
if (!style?.bibliography) {
|
|
39
|
+
throw new Error('formatAll() requires a compiled style with a bibliography() function')
|
|
40
|
+
}
|
|
41
|
+
let sorted = [...items]
|
|
42
|
+
if (style.bibliographySort) {
|
|
43
|
+
sorted.sort(style.bibliographySort)
|
|
44
|
+
}
|
|
45
|
+
// Assign citation numbers (shallow-clone to avoid mutating user's items)
|
|
46
|
+
sorted = sorted.map((item, i) => ({ ...item, 'citation-number': i + 1 }))
|
|
47
|
+
return sorted.map(item => style.bibliography(item, ctx))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Format a single inline citation.
|
|
52
|
+
*
|
|
53
|
+
* @param {import('@citestyle/types').CompiledStyle} style - A compiled CSL style module
|
|
54
|
+
* @param {import('@citestyle/types').CiteRef[]} cites - Citation references with items
|
|
55
|
+
* @param {import('@citestyle/types').FormatContext} [ctx] - Optional format context
|
|
56
|
+
* @returns {import('@citestyle/types').FormattedCitation}
|
|
57
|
+
*/
|
|
58
|
+
export function formatCitation(style, cites, ctx = {}) {
|
|
59
|
+
if (!style?.citation) {
|
|
60
|
+
throw new Error('formatCitation() requires a compiled style with a citation() function')
|
|
61
|
+
}
|
|
62
|
+
// Assign citation numbers if not already set (shallow-clone to avoid mutating user's items)
|
|
63
|
+
const safeCites = cites.map((cite, i) => {
|
|
64
|
+
if (cite.item && cite.item['citation-number'] == null) {
|
|
65
|
+
return { ...cite, item: { ...cite.item, 'citation-number': i + 1 } }
|
|
66
|
+
}
|
|
67
|
+
return cite
|
|
68
|
+
})
|
|
69
|
+
return style.citation(safeCites, ctx)
|
|
70
|
+
}
|
package/src/index.js
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
* - Citation number tracking (numeric styles)
|
|
9
9
|
* - Bibliography sorting (using compiled comparator)
|
|
10
10
|
* - Subsequent-author-substitute
|
|
11
|
+
*
|
|
12
|
+
* Also provides simple format/formatAll/formatCitation helpers for
|
|
13
|
+
* one-off formatting without a full registry.
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
16
|
export { createRegistry } from './registry.js'
|
|
17
|
+
export { format, formatAll, formatCitation } from './format.js'
|
package/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { createRegistry, Registry, RegistryOptions } from '@citestyle/types'
|
|
1
|
+
export { createRegistry, format, formatAll, formatCitation, Registry, RegistryOptions } from '@citestyle/types'
|