@purview-dev/astroc4 1.0.0-prerelease.2 → 1.0.0-prerelease.4

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/src/index.mjs DELETED
@@ -1,228 +0,0 @@
1
- // index.mjs
2
- // path: src/index.mjs
3
- // Starlight plugin that renders LikeC4 architecture diagrams:
4
- //
5
- // import astroc4 from '@purview-dev/astroc4';
6
- // starlight({ plugins: [astroc4()] })
7
- //
8
- // It wires up everything a site previously had to configure by hand:
9
- // - LikeC4VitePlugin, which compiles every .c4 project under the site root
10
- // into the `likec4:model` / `likec4:icons` / `likec4:projects` modules;
11
- // - the ```likec4 fence transform (./fences.mjs), appended to the site's
12
- // Sätteri processor;
13
- // - the build-time preload that avoids a Windows-only crash (see
14
- // `preloadLikeC4` in ./fences.mjs);
15
- // - LikeC4 syntax highlighting, resolved from the live Langium grammar and
16
- // injected into the site's Expressive Code options (see below);
17
- // - the component UI strings, through Starlight's i18n system.
18
- //
19
- // The highlighting injection is why this is a Starlight plugin and not just an
20
- // integration: Starlight runs plugin `config:setup` hooks *before* it builds
21
- // its Expressive Code integration, and a plugin can `updateConfig` the
22
- // `expressiveCode` option — so the grammar reaches Shiki without the site
23
- // having to create an `ec.config.mjs`. Expressive Code concatenates
24
- // `shiki.langs` when it merges integration options with an `ec.config.mjs`, so
25
- // a site that has one keeps its own languages too.
26
-
27
- import { fileURLToPath } from 'node:url';
28
-
29
- import { LikeC4VitePlugin } from 'likec4/vite-plugin';
30
-
31
- import { likec4Fences, preloadLikeC4 } from './fences.mjs';
32
- import { resolveLikeC4Grammar } from './grammar/source.mjs';
33
- import { LANGUAGE_ALIASES, LANGUAGE_NAME } from './grammar/textmate.mjs';
34
- import { translations } from './translations.mjs';
35
-
36
- /**
37
- * The published package name. Scoped because npm refuses the unscoped
38
- * `astroc4` — "too similar to existing package astro" — and because the scope
39
- * makes the specifiers this plugin writes into a site's pages unambiguous.
40
- */
41
- const PACKAGE_NAME = '@purview-dev/astroc4';
42
-
43
- /** @typedef {import('./index.d.mts').StarlightLikeC4Options} StarlightLikeC4Options */
44
- /** @typedef {import('./index.d.mts').LikeC4HighlightingOptions} LikeC4HighlightingOptions */
45
-
46
- /**
47
- * @param {StarlightLikeC4Options} [options]
48
- * @returns {import('@astrojs/starlight/types').StarlightPlugin}
49
- */
50
- export default function starlightLikeC4(options = {}) {
51
- return {
52
- name: PACKAGE_NAME,
53
- hooks: {
54
- 'i18n:setup'({ injectTranslations }) {
55
- injectTranslations(translations);
56
- },
57
- async 'config:setup'({ config, astroConfig, updateConfig, addIntegration, logger }) {
58
- addIntegration(likec4Integration(options));
59
-
60
- if (options.highlighting === false) return;
61
-
62
- await injectHighlighting({
63
- // `config` is the Starlight config, `astroConfig` the Astro one:
64
- // the site root and the cache directory live on the latter.
65
- root: fileURLToPath(astroConfig.root),
66
- expressiveCode: config.expressiveCode,
67
- updateConfig,
68
- logger,
69
- options: options.highlighting ?? {},
70
- });
71
- },
72
- },
73
- };
74
- }
75
-
76
- /**
77
- * Register the LikeC4 grammar with whatever Expressive Code the site ends up
78
- * with.
79
- *
80
- * This is deliberately not wrapped in a try/catch: a ref that does not exist,
81
- * or a grammar that cannot be read, fails `astro dev`, `astro build`,
82
- * `astro check` and `astro sync` exactly like any other build error. Sites that
83
- * cannot reach github.com on every build opt out with `offline: true` or
84
- * `onError: 'warn'`.
85
- *
86
- * @param {{
87
- * root: string,
88
- * expressiveCode: unknown,
89
- * updateConfig: (config: { expressiveCode?: unknown }) => void,
90
- * logger: import('astro').AstroIntegrationLogger,
91
- * options: LikeC4HighlightingOptions,
92
- * }} context
93
- */
94
- async function injectHighlighting({ root, expressiveCode, updateConfig, logger, options }) {
95
- if (expressiveCode === false) {
96
- logger.warn(
97
- 'LikeC4 syntax highlighting is skipped: `expressiveCode: false` disables the code blocks it ' +
98
- 'would highlight. Diagrams are unaffected.',
99
- );
100
- return;
101
- }
102
-
103
- const source = await resolveLikeC4Grammar({ root, ...options, logger });
104
-
105
- const registration = {
106
- ...source.grammar,
107
- name: LANGUAGE_NAME,
108
- aliases: [...LANGUAGE_ALIASES],
109
- };
110
-
111
- updateConfig({ expressiveCode: withLikeC4Language(expressiveCode, registration) });
112
-
113
- const { repo, ref, sha, source: from } = source.meta;
114
- logger.info(
115
- `LikeC4 grammar ${repo}@${ref} (${sha})${from === 'network' ? '' : ` from ${from}`} — ` +
116
- 'highlighting ```c4 and ```likec4 fences',
117
- );
118
- }
119
-
120
- /**
121
- * Add the LikeC4 language to a site's Expressive Code options without
122
- * disturbing anything already set.
123
- *
124
- * Replacing an existing entry rather than appending matters: a site that
125
- * pinned `likec4Language` from `@purview-dev/astroc4/expressive-code` should get the
126
- * grammar for the ref it configured here, not two grammars for the same scope.
127
- * Expressive Code concatenates `shiki.langs` when it merges these options with
128
- * an `ec.config.mjs`, so a site's own languages survive either way.
129
- *
130
- * @param {unknown} expressiveCode The site's `expressiveCode` option.
131
- * @param {Record<string, unknown>} registration Shiki language registration.
132
- * @returns {Record<string, unknown> & { shiki: { langs: unknown[] } }}
133
- */
134
- export function withLikeC4Language(expressiveCode, registration) {
135
- const current = isObject(expressiveCode) ? expressiveCode : {};
136
- const shiki = isObject(current.shiki) ? current.shiki : {};
137
- const langs = Array.isArray(shiki.langs) ? [...shiki.langs] : [];
138
- const existing = langs.findIndex(isLikeC4Language);
139
-
140
- if (existing === -1) langs.push(registration);
141
- else langs[existing] = registration;
142
-
143
- return /** @type {Record<string, unknown> & { shiki: { langs: unknown[] } }} */ ({
144
- ...current,
145
- shiki: { ...shiki, langs },
146
- });
147
- }
148
-
149
- /** A Shiki `langs` entry that already covers LikeC4, as an id or a registration. */
150
- function isLikeC4Language(entry) {
151
- if (typeof entry === 'string') return entry === LANGUAGE_NAME || LANGUAGE_ALIASES.includes(entry);
152
- if (!isObject(entry)) return false;
153
-
154
- if (entry.name === LANGUAGE_NAME || entry.scopeName === 'source.likec4') return true;
155
-
156
- return Array.isArray(entry.aliases) && entry.aliases.some((alias) => LANGUAGE_ALIASES.includes(alias));
157
- }
158
-
159
- function isObject(value) {
160
- return typeof value === 'object' && value !== null && !Array.isArray(value);
161
- }
162
-
163
-
164
- /**
165
- * @param {StarlightLikeC4Options} options
166
- * @returns {import('astro').AstroIntegration}
167
- */
168
- function likec4Integration({ vitePlugin = {}, fences = true }) {
169
- return {
170
- name: `${PACKAGE_NAME}/integration`,
171
- hooks: {
172
- 'astro:config:setup': async ({ command, config, updateConfig, logger }) => {
173
- updateConfig({
174
- vite: {
175
- plugins: [LikeC4VitePlugin(vitePlugin)],
176
- // The components ship as .astro/.tsx source, so Vite has to
177
- // transform them rather than hand them to Node as-is.
178
- ssr: { noExternal: [PACKAGE_NAME] },
179
- },
180
- });
181
-
182
- if (fences) {
183
- await registerFences(config, updateConfig, logger);
184
- }
185
-
186
- // `command` is only available here, not in `astro:config:done` — and
187
- // this must stay build-only; see `loadLikeC4` in ./fences.mjs.
188
- if (command === 'build') {
189
- await preloadLikeC4();
190
- }
191
- },
192
- },
193
- };
194
- }
195
-
196
- /**
197
- * Append the fence transform to the site's existing Sätteri processor, keeping
198
- * whatever Starlight and other integrations already registered on it.
199
- */
200
- async function registerFences(config, updateConfig, logger) {
201
- const { satteri, isSatteriProcessor } = await import('@astrojs/markdown-satteri');
202
- const existing = config.markdown?.processor;
203
-
204
- // No processor configured means Astro's default, which is Sätteri.
205
- if (existing === undefined) {
206
- updateConfig({ markdown: { processor: satteri({ mdastPlugins: [likec4Fences()] }) } });
207
- return;
208
- }
209
-
210
- if (!isSatteriProcessor(existing)) {
211
- logger.warn(
212
- '```likec4 fences are disabled: the site is not using the Sätteri Markdown processor. ' +
213
- '<LikeC4View /> still works.',
214
- );
215
- return;
216
- }
217
-
218
- const existingOptions = existing.options ?? {};
219
-
220
- updateConfig({
221
- markdown: {
222
- processor: satteri({
223
- ...existingOptions,
224
- mdastPlugins: [...(existingOptions.mdastPlugins ?? []), likec4Fences()],
225
- }),
226
- },
227
- });
228
- }
package/src/types.d.ts DELETED
@@ -1,12 +0,0 @@
1
- // types.d.ts
2
- // path: src/types.d.ts
3
- // Ambient types for the package source: the `likec4:*` virtual modules created
4
- // by LikeC4VitePlugin, and the plugin's keys in Starlight's `t()`.
5
-
6
- /// <reference types="likec4/vite-plugin-modules" />
7
-
8
- declare namespace StarlightApp {
9
- type LikeC4UIStrings = (typeof import('./translations.mjs'))['translations']['en'];
10
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- declaration merging
11
- interface I18n extends LikeC4UIStrings {}
12
- }
File without changes
File without changes