gutterpress 0.10.7 → 0.10.8
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 +10 -3
- package/dist/README-aaqapam1.md +186 -0
- package/dist/README-mdq34cmb.md +155 -0
- package/dist/api/index.d.ts +6 -2
- package/dist/api/index.js +30 -2
- package/dist/{audit-19e2431j.js → audit-m3ce9pvq.js} +4 -4
- package/dist/base-ypqh9n7f.css +123 -0
- package/dist/book-ted3tzrp.css +58 -0
- package/dist/{build-gqqew2vr.js → build-qnecb3a1.js} +4 -4
- package/dist/callout-hv56m16h.md +7 -0
- package/dist/{cli-kzf64c2g.js → cli-1hx14cgk.js} +946 -401
- package/dist/{cli-s8q42x3r.js → cli-4vtgt2ng.js} +78 -2
- package/dist/{cli-h8ejbtyr.js → cli-vcv5ewqj.js} +1 -1
- package/dist/{cli-pvk2s9d7.js → cli-vxf151ea.js} +1 -1
- package/dist/cli.js +16 -16
- package/dist/components-0mmswvvm.yaml +51 -0
- package/dist/components-aam0fe2z.css +94 -0
- package/dist/{doctor-3ccz35yz.js → doctor-qvqye1wd.js} +2 -2
- package/dist/{engine-pb6h089e.js → engine-daad33qn.js} +1 -1
- package/dist/{engine-88mynx9a.js → engine-db8632w6.js} +2 -2
- package/dist/expected-ycmacem8.html +9 -0
- package/dist/fixture-2qnyqgb5.md +10 -0
- package/dist/gutterpress-m98e2w2d.json +8 -0
- package/dist/gutterpress-x2ycdsb8.json +17 -0
- package/dist/{index-837htyjy.js → index-9pbaznww.js} +78 -2
- package/dist/{index-r4ny4fyr.js → index-dfw8hn8q.js} +1147 -523
- package/dist/{index-a0xpm188.js → index-rpt4vtby.js} +1 -1
- package/dist/index.js +31 -3
- package/dist/lib/build-runner.d.ts +52 -0
- package/dist/lib/extension-manifest.d.ts +164 -0
- package/dist/lib/extension-scaffold.d.ts +65 -0
- package/dist/lib/lint-runner.d.ts +12 -0
- package/dist/lib/markdown/assemble.d.ts +12 -0
- package/dist/lib/markdown/markers.d.ts +20 -0
- package/dist/lib/markdown/plugins.d.ts +1 -1
- package/dist/lib/markdown/renderer.d.ts +99 -0
- package/dist/lib/snippets.d.ts +121 -5
- package/dist/lib/theme-import.d.ts +8 -4
- package/dist/lib/theme-manager.d.ts +52 -39
- package/dist/lib/validation-exec.d.ts +12 -0
- package/dist/{lint-mpz7vfc8.js → lint-3p1s8agk.js} +4 -4
- package/dist/{manifest.schema-kwnrwv8b.json → manifest.schema-1q35yxs9.json} +2 -2
- package/dist/{new-nbrpsw7t.js → new-xffarp40.js} +111 -6
- package/dist/package-rm9d2tht.json +29 -0
- package/dist/page-rules-nsj3aw42.css +128 -0
- package/dist/page-templates-7md4ev7d.css +60 -0
- package/dist/{plugin-gg5mk26h.js → plugin-b05ck7zd.js} +4 -4
- package/dist/plugin-m2w7g47v.css +114 -0
- package/dist/plugin.js-aszz0zgh.tpl +172 -0
- package/dist/plugin.test.js-mv0ghv5n.tpl +232 -0
- package/dist/{preflight-jnmd4mg2.js → preflight-z6xpty9w.js} +4 -4
- package/dist/{preview-hsr9d12d.js → preview-xa1n7why.js} +4 -4
- package/dist/{publish-pcrrn6fd.js → publish-zgmr99kd.js} +4 -4
- package/dist/render.js +275 -8
- package/dist/term-box-4y0w7y32.md +7 -0
- package/dist/{theme-6fa0yjzq.js → theme-m9dtxkhj.js} +4 -4
- package/dist/tokens-e4xk3x4v.css +86 -0
- package/dist/{validate-7n25fx0g.js → validate-43hqgzz5.js} +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,18 +8,22 @@ import {
|
|
|
8
8
|
AUTO_SYNC_PUSH_INTERVAL_MINUTES,
|
|
9
9
|
BUILT_IN_TEMPLATE_IDS,
|
|
10
10
|
BUILT_IN_THEME_IDS,
|
|
11
|
+
EXTENSION_KINDS,
|
|
12
|
+
EXTENSION_MANIFEST_FILENAME,
|
|
11
13
|
FileTokenStore,
|
|
12
14
|
GDRIVE_HOST,
|
|
13
15
|
GITHUB_HOST,
|
|
14
16
|
GOOGLE_NOT_CONFIGURED_MESSAGE,
|
|
15
17
|
GitHubAuthProvider,
|
|
16
18
|
GoogleAuthProvider,
|
|
19
|
+
LEGACY_THEME_MANIFEST_FILENAME,
|
|
17
20
|
MANIFEST_FILENAMES,
|
|
18
21
|
PLUGINS_DIR,
|
|
19
22
|
PRESETS,
|
|
20
23
|
PRESET_IDS,
|
|
21
24
|
PublishSelectionsStore,
|
|
22
25
|
RECOMMENDED_PLUGINS,
|
|
26
|
+
RESERVED_PREFIX,
|
|
23
27
|
SNIPPETS_DIR,
|
|
24
28
|
SYNC_SNAPSHOT_MESSAGE,
|
|
25
29
|
TARGETS,
|
|
@@ -29,6 +33,7 @@ import {
|
|
|
29
33
|
addNpmPlugin,
|
|
30
34
|
adoptFolder,
|
|
31
35
|
applyTheme,
|
|
36
|
+
assertExtensionContained,
|
|
32
37
|
autoSnapshotDelayMs,
|
|
33
38
|
autoSyncDelayMs,
|
|
34
39
|
checkCss,
|
|
@@ -45,6 +50,8 @@ import {
|
|
|
45
50
|
escapeYamlScalar,
|
|
46
51
|
executeAndReport,
|
|
47
52
|
executeValidation,
|
|
53
|
+
extensionEngineStyleList,
|
|
54
|
+
extensionStyleList,
|
|
48
55
|
extractUrlCredential,
|
|
49
56
|
extractVariables,
|
|
50
57
|
forgeKindForHost,
|
|
@@ -68,6 +75,7 @@ import {
|
|
|
68
75
|
listCustomTemplates,
|
|
69
76
|
listGitHubBranches,
|
|
70
77
|
listGitHubRepositories,
|
|
78
|
+
listMergedSnippets,
|
|
71
79
|
listProjectPlugins,
|
|
72
80
|
listProjectStyles,
|
|
73
81
|
listProjectThemes,
|
|
@@ -80,11 +88,14 @@ import {
|
|
|
80
88
|
log,
|
|
81
89
|
openPath,
|
|
82
90
|
parseRemoteOrigin,
|
|
91
|
+
pathEscapesFolder,
|
|
83
92
|
pkceChallengeFromVerifier,
|
|
84
93
|
publishConnectionStatus,
|
|
85
94
|
publishCredentialKey,
|
|
86
95
|
publishProviderFor,
|
|
87
96
|
publishTargetFor,
|
|
97
|
+
readExtensionMeta,
|
|
98
|
+
readExtensionSnippet,
|
|
88
99
|
readManifestFields,
|
|
89
100
|
readPublishSettings,
|
|
90
101
|
readSnippet,
|
|
@@ -96,6 +107,8 @@ import {
|
|
|
96
107
|
resolveBuiltInTheme,
|
|
97
108
|
resolveCheckSelectors,
|
|
98
109
|
resolveConfig,
|
|
110
|
+
resolveExtension,
|
|
111
|
+
resolveExtensionPrefix,
|
|
99
112
|
resolveGitHubClientId,
|
|
100
113
|
resolveGoogleClientId,
|
|
101
114
|
resolveGoogleClientSecret,
|
|
@@ -113,6 +126,7 @@ import {
|
|
|
113
126
|
sanitizeCloneFolderName,
|
|
114
127
|
saveProjectAsTemplate,
|
|
115
128
|
saveSnippet,
|
|
129
|
+
scaffoldExtension,
|
|
116
130
|
scaffoldProject,
|
|
117
131
|
setActiveStyles,
|
|
118
132
|
setManifestFields,
|
|
@@ -125,15 +139,15 @@ import {
|
|
|
125
139
|
syncProject,
|
|
126
140
|
testRemoteAccess,
|
|
127
141
|
validateProjectPlugins
|
|
128
|
-
} from "./index-
|
|
142
|
+
} from "./index-dfw8hn8q.js";
|
|
129
143
|
import {
|
|
130
144
|
BUILD_DIAGNOSTIC_CODES
|
|
131
|
-
} from "./index-
|
|
145
|
+
} from "./index-rpt4vtby.js";
|
|
132
146
|
import {
|
|
133
147
|
BuildError,
|
|
134
148
|
DEFAULT_PRINT_OPTS,
|
|
135
149
|
readyProbeExpr
|
|
136
|
-
} from "./index-
|
|
150
|
+
} from "./index-9pbaznww.js";
|
|
137
151
|
import {
|
|
138
152
|
AUTO_SNAPSHOT_MESSAGE,
|
|
139
153
|
HISTORY_PAGE_LIMIT,
|
|
@@ -164,6 +178,7 @@ export {
|
|
|
164
178
|
setManifestFields,
|
|
165
179
|
setActiveStyles,
|
|
166
180
|
scaffoldProject,
|
|
181
|
+
scaffoldExtension,
|
|
167
182
|
saveSnippet,
|
|
168
183
|
saveProjectAsTemplate,
|
|
169
184
|
sanitizeCloneFolderName,
|
|
@@ -183,6 +198,8 @@ export {
|
|
|
183
198
|
resolveGoogleClientSecret,
|
|
184
199
|
resolveGoogleClientId,
|
|
185
200
|
resolveGitHubClientId,
|
|
201
|
+
resolveExtensionPrefix,
|
|
202
|
+
resolveExtension,
|
|
186
203
|
resolveConfig,
|
|
187
204
|
resolveCheckSelectors,
|
|
188
205
|
resolveBuiltInTheme,
|
|
@@ -197,12 +214,15 @@ export {
|
|
|
197
214
|
readSnippet,
|
|
198
215
|
readPublishSettings,
|
|
199
216
|
readManifestFields,
|
|
217
|
+
readExtensionSnippet,
|
|
218
|
+
readExtensionMeta,
|
|
200
219
|
publishTargetFor,
|
|
201
220
|
publishProviderFor,
|
|
202
221
|
publishCredentialKey,
|
|
203
222
|
publishConnectionStatus,
|
|
204
223
|
providerFor,
|
|
205
224
|
pkceChallengeFromVerifier,
|
|
225
|
+
pathEscapesFolder,
|
|
206
226
|
parseRemoteOrigin,
|
|
207
227
|
openPath,
|
|
208
228
|
log,
|
|
@@ -215,6 +235,7 @@ export {
|
|
|
215
235
|
listProjectThemes,
|
|
216
236
|
listProjectStyles,
|
|
217
237
|
listProjectPlugins,
|
|
238
|
+
listMergedSnippets,
|
|
218
239
|
listGitHubRepositories,
|
|
219
240
|
listGitHubBranches,
|
|
220
241
|
listCustomTemplates,
|
|
@@ -240,6 +261,8 @@ export {
|
|
|
240
261
|
findEnclosingRepoDir,
|
|
241
262
|
extractVariables,
|
|
242
263
|
extractUrlCredential,
|
|
264
|
+
extensionStyleList,
|
|
265
|
+
extensionEngineStyleList,
|
|
243
266
|
executeValidation,
|
|
244
267
|
executeAndReport,
|
|
245
268
|
escapeYamlScalar,
|
|
@@ -258,6 +281,7 @@ export {
|
|
|
258
281
|
capabilitiesFor,
|
|
259
282
|
autoSyncDelayMs,
|
|
260
283
|
autoSnapshotDelayMs,
|
|
284
|
+
assertExtensionContained,
|
|
261
285
|
applyTheme,
|
|
262
286
|
adoptFolder,
|
|
263
287
|
addNpmPlugin,
|
|
@@ -268,12 +292,14 @@ export {
|
|
|
268
292
|
SYNC_SNAPSHOT_MESSAGE,
|
|
269
293
|
SNIPPETS_DIR,
|
|
270
294
|
RESTORE_BACKUP_MESSAGE,
|
|
295
|
+
RESERVED_PREFIX,
|
|
271
296
|
RECOMMENDED_PLUGINS,
|
|
272
297
|
PublishSelectionsStore,
|
|
273
298
|
PRESET_IDS,
|
|
274
299
|
PRESETS,
|
|
275
300
|
PLUGINS_DIR,
|
|
276
301
|
MANIFEST_FILENAMES,
|
|
302
|
+
LEGACY_THEME_MANIFEST_FILENAME,
|
|
277
303
|
HISTORY_PAGE_LIMIT,
|
|
278
304
|
GoogleAuthProvider,
|
|
279
305
|
GitHubAuthProvider,
|
|
@@ -281,6 +307,8 @@ export {
|
|
|
281
307
|
GITHUB_HOST,
|
|
282
308
|
GDRIVE_HOST,
|
|
283
309
|
FileTokenStore,
|
|
310
|
+
EXTENSION_MANIFEST_FILENAME,
|
|
311
|
+
EXTENSION_KINDS,
|
|
284
312
|
DEFAULT_PRINT_OPTS,
|
|
285
313
|
BuildError,
|
|
286
314
|
BUILT_IN_THEME_IDS,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveConfig } from "./manifest";
|
|
2
|
+
import { type LoadedPluginsWithCss } from "./markdown/plugins";
|
|
2
3
|
import { RENDER_TIMEOUT_MS } from "./browser-pool";
|
|
3
4
|
import { BuildError } from "./build-error";
|
|
4
5
|
import type { BuildDiagnostic } from "../engine/compiler/build.ts";
|
|
@@ -165,6 +166,29 @@ export interface BuildContext {
|
|
|
165
166
|
* warning from the final render path.
|
|
166
167
|
*/
|
|
167
168
|
prevalidatedLayoutWarningKeys: Set<string>;
|
|
169
|
+
/**
|
|
170
|
+
* The build's ONE plugin load (#262). `null` until {@link loadBuildPlugins}
|
|
171
|
+
* runs; every stage that needs plugins (the lint gate and preValidate gate
|
|
172
|
+
* in {@link runQualityGates}, and {@link renderBook}) calls that function
|
|
173
|
+
* and gets the SAME resolved `{ plugins, pluginCss, pluginStylePaths }`
|
|
174
|
+
* back, whichever of them runs first.
|
|
175
|
+
*
|
|
176
|
+
* Before this, `runQualityGates`'s lint gate and `renderBook` each called
|
|
177
|
+
* `loadPluginsWithCss` independently for the identical manifest. For an
|
|
178
|
+
* npm-vendored plugin, EVERY load re-runs `verifyVendoredPlugin` ->
|
|
179
|
+
* `computeVendorTreeDigest` (plugin-vendor.ts) — a recursive walk of the
|
|
180
|
+
* vendored tree plus a full read-and-SHA-256 of every file, with no cache
|
|
181
|
+
* anywhere in that module BY DESIGN (the digest exists to detect tampering
|
|
182
|
+
* with the vendored tree; a cache keyed on anything less than the file
|
|
183
|
+
* contents themselves — e.g. the receipt's mtime — would not notice an
|
|
184
|
+
* edited vendored file). A `gutterpress build` with the lint gate on
|
|
185
|
+
* therefore paid that cost twice for no reason: same manifest, same
|
|
186
|
+
* `renderDir` anchor (see that field's doc comment — the two call sites'
|
|
187
|
+
* base dirs were the historical risk here, and they are now provably the
|
|
188
|
+
* same value), same plugin list. Memoizing the ONE load on the context
|
|
189
|
+
* removes the duplicate work without caching anything security-relevant.
|
|
190
|
+
*/
|
|
191
|
+
plugins: LoadedPluginsWithCss | null;
|
|
168
192
|
}
|
|
169
193
|
/**
|
|
170
194
|
* Stage 1 — load the manifest, merge CLI overrides into the resolved config,
|
|
@@ -173,6 +197,34 @@ export interface BuildContext {
|
|
|
173
197
|
* flags-ignored notice. Everything downstream reads from the returned context.
|
|
174
198
|
*/
|
|
175
199
|
export declare function resolveBuildContext(opts: BuildRunnerOptions): Promise<BuildContext>;
|
|
200
|
+
/**
|
|
201
|
+
* Load every plugin the manifest configures, exactly once for the whole
|
|
202
|
+
* build (#262). Memoized on `ctx.plugins`: the lint gate, the preValidate
|
|
203
|
+
* gate (both in {@link runQualityGates}), and {@link renderBook} each call
|
|
204
|
+
* this instead of `loadPluginsWithCss` directly, and only the first caller
|
|
205
|
+
* does real work — the rest get the cached result back, however the gates
|
|
206
|
+
* are configured and whichever stage happens to run first (a test calling
|
|
207
|
+
* {@link renderBook} directly, without going through `runQualityGates`, gets
|
|
208
|
+
* a fresh load here exactly as it would have before this existed).
|
|
209
|
+
*
|
|
210
|
+
* Fail-fast (no `onError`), matching `renderBook`'s pre-existing behavior:
|
|
211
|
+
* a build/export must never silently omit author-configured formatting (see
|
|
212
|
+
* `loadPlugins`'s doc comment in markdown/plugins.ts on the two failure
|
|
213
|
+
* modes). One consequence: a plugin that fails to load now aborts the build
|
|
214
|
+
* as soon as quality gates start, instead of (as before) the lint gate's own
|
|
215
|
+
* degrade-and-report call warning-and-skipping that same plugin only for
|
|
216
|
+
* `renderBook` to hard-fail on it moments later — the build failed either
|
|
217
|
+
* way, this just stops wasting the lint pass first.
|
|
218
|
+
*
|
|
219
|
+
* Resolves plugin `path:` entries against `ctx.renderDir`, which is by
|
|
220
|
+
* construction identical to `ctx.manifestDir` for the life of one
|
|
221
|
+
* `BuildContext` (see {@link BuildContext.renderDir}'s doc comment and
|
|
222
|
+
* build-runner.output-dir.test.ts's anchor tests) — so hoisting this load
|
|
223
|
+
* ahead of the gates cannot resolve a plugin against a different root than
|
|
224
|
+
* `renderBook` used to, including under an explicit `--manifest` outside
|
|
225
|
+
* `--input`.
|
|
226
|
+
*/
|
|
227
|
+
export declare function loadBuildPlugins(ctx: BuildContext): Promise<LoadedPluginsWithCss>;
|
|
176
228
|
/**
|
|
177
229
|
* Stage 3 — load configured plugins, render the markdown chapters to
|
|
178
230
|
* `outDir/book.html`, and copy user asset directories. Returns the path to the
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/** The unified package's metadata filename — checked before the legacy
|
|
2
|
+
* theme-only filename by {@link readExtensionMeta}. */
|
|
3
|
+
export declare const EXTENSION_MANIFEST_FILENAME = "gutterpress.json";
|
|
4
|
+
/** The pre-#241 theme-only metadata filename. Still fully supported: a folder
|
|
5
|
+
* with only this file (no `gutterpress.json`) is a theme, i.e. "an extension
|
|
6
|
+
* with only styles" — see {@link readExtensionMeta}. */
|
|
7
|
+
export declare const LEGACY_THEME_MANIFEST_FILENAME = "theme.json";
|
|
8
|
+
/**
|
|
9
|
+
* Parsed extension metadata — a superset of the pre-#241 theme metadata
|
|
10
|
+
* shape. Every field is optional, and a folder declaring only the theme-era
|
|
11
|
+
* fields (`name`/`author`/`description`/`preview`/`styles`/`engineStyles`/
|
|
12
|
+
* `tokensFile`) IS a valid extension: "theme ≡ extension with only styles."
|
|
13
|
+
* Symmetrically, a bare `.js` plugin file (no metadata file at all) never
|
|
14
|
+
* constructs one of these — "plugin ≡ extension with only markdown" needs no
|
|
15
|
+
* metadata file until it wants more than a function (see `plugins.ts`'s
|
|
16
|
+
* `loadExtensionFromDir`, which only reaches this type for a `path` that
|
|
17
|
+
* names a folder).
|
|
18
|
+
*/
|
|
19
|
+
export interface ExtensionMetadata {
|
|
20
|
+
name?: string;
|
|
21
|
+
author?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
/** Optional preview image path (relative to the extension folder). */
|
|
24
|
+
preview?: string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Ordered stylesheets, relative to the extension folder. Absent/empty means
|
|
27
|
+
* "no styles declared" here — {@link extensionStyleList} does NOT default
|
|
28
|
+
* to `["theme.css"]`; that default is theme-manager.ts's OWN, layered on
|
|
29
|
+
* top for its theme-shaped callers (a plain markdown-only extension folder
|
|
30
|
+
* has no reason to require a `theme.css` it never declared).
|
|
31
|
+
*/
|
|
32
|
+
styles?: string[];
|
|
33
|
+
/** Engine-conditional sheets, relative to the extension folder, appended
|
|
34
|
+
* after `styles` (mirrors the manifest's own `engineStyles.native`). */
|
|
35
|
+
engineStyles?: {
|
|
36
|
+
native?: string[];
|
|
37
|
+
};
|
|
38
|
+
/** Which declared sheet (a path from `styles`) carries the author-facing
|
|
39
|
+
* `:root` token surface for the Design panel's guided editor. Purely
|
|
40
|
+
* advisory — nothing in this module enforces or existence-checks it,
|
|
41
|
+
* matching the pre-#241 theme behavior it generalizes. */
|
|
42
|
+
tokensFile?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Markdown-it entry, relative to the extension folder — a path to a JS
|
|
45
|
+
* module exporting a plugin function exactly like a bare-file plugin
|
|
46
|
+
* (`export default function (md, options) { ... }`, optionally `metadata`/
|
|
47
|
+
* `css`/`styles`, #238). Absent means "no markdown behavior" — the
|
|
48
|
+
* degenerate case that makes a styles-only folder indistinguishable from a
|
|
49
|
+
* theme. CLAUDE.md §5 is unaffected: this field is DATA a loader resolves
|
|
50
|
+
* to a file, then loads through the exact same plain-markdown-it-plugin
|
|
51
|
+
* contract every other plugin module does — no new plugin API is
|
|
52
|
+
* introduced.
|
|
53
|
+
*/
|
|
54
|
+
markdown?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Component catalog file, relative to the extension folder (the CSS
|
|
57
|
+
* architecture review's `components.yaml`, #242). Parsed for existence/
|
|
58
|
+
* containment only by this module — the catalog SCHEMA and the registry
|
|
59
|
+
* that reads it are #242's scope, not this one's.
|
|
60
|
+
*/
|
|
61
|
+
components?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Snippets folder, relative to the extension folder, merged into the
|
|
64
|
+
* project's snippet picker under the extension's name (#240). Parsed for
|
|
65
|
+
* existence/containment only by this module — the merge itself is #240's
|
|
66
|
+
* scope, not this one's.
|
|
67
|
+
*/
|
|
68
|
+
snippets?: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Read an extension folder's metadata: `gutterpress.json` when present,
|
|
72
|
+
* otherwise the legacy `theme.json` — ONE reader for both filenames, which is
|
|
73
|
+
* what makes "the theme verbs keep working on the extension format" true
|
|
74
|
+
* everywhere a real on-disk extension/theme folder is read (project themes,
|
|
75
|
+
* apply, import, revert). `gutterpress.json` wins outright when present (no
|
|
76
|
+
* silent merge with a sibling `theme.json` — a package declares itself
|
|
77
|
+
* through exactly one file), matching {@link readJsonMetaFile}'s tolerant
|
|
78
|
+
* contract when that one file is missing or broken.
|
|
79
|
+
*/
|
|
80
|
+
export declare function readExtensionMeta(dir: string): Promise<ExtensionMetadata>;
|
|
81
|
+
/**
|
|
82
|
+
* An extension's declared stylesheets, relative to its folder, in cascade
|
|
83
|
+
* order. UNLIKE `theme-manager.ts`'s `themeStyleList` (which layers a
|
|
84
|
+
* `["theme.css"]` default on top of this for its theme-shaped callers), an
|
|
85
|
+
* absent/empty `styles` here means exactly "none declared" — a markdown-only
|
|
86
|
+
* extension folder must not be forced to carry a `theme.css` it never wanted.
|
|
87
|
+
*/
|
|
88
|
+
export declare function extensionStyleList(meta: ExtensionMetadata): string[];
|
|
89
|
+
/** An extension's declared engine-conditional sheets, relative to its folder. */
|
|
90
|
+
export declare function extensionEngineStyleList(meta: ExtensionMetadata): string[];
|
|
91
|
+
/**
|
|
92
|
+
* True when a declared relative path escapes its own folder (absolute, or a
|
|
93
|
+
* `..` segment) — the traversal shape every containment check in this
|
|
94
|
+
* package rejects.
|
|
95
|
+
*
|
|
96
|
+
* Exported (#242) for `snippets.ts`'s installed-extension snippet merge,
|
|
97
|
+
* which needs this SAME single-field check but cannot use
|
|
98
|
+
* {@link assertExtensionContained}: that guard throws on ANY escaping field
|
|
99
|
+
* (styles/markdown/components/tokensFile too), which is correct for a
|
|
100
|
+
* write-boundary check at install/apply time but wrong for a tolerant
|
|
101
|
+
* listing — an extension with a broken, unrelated `styles` entry must not
|
|
102
|
+
* make its perfectly fine `snippets` folder disappear from the picker (the
|
|
103
|
+
* same "one hand-edited file must not take down listing everyone else's"
|
|
104
|
+
* doctrine {@link readExtensionMeta}'s tolerant JSON parse already follows).
|
|
105
|
+
*/
|
|
106
|
+
export declare function pathEscapesFolder(rel: string): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Every path an extension declares must live INSIDE its own folder — an
|
|
109
|
+
* extension is self-contained by contract (apply/install copies the whole
|
|
110
|
+
* folder), and an imported/vendored package is untrusted input: a `../` or
|
|
111
|
+
* absolute entry would make apply/load read a file from anywhere on disk.
|
|
112
|
+
*
|
|
113
|
+
* Generalizes the pre-#241 theme-only `assertThemeSheetsContained` (still
|
|
114
|
+
* exported under that name from `theme-manager.ts`, now a re-export of this
|
|
115
|
+
* function) to the three new fields: a `gutterpress.json`-formatted theme
|
|
116
|
+
* folder can declare `markdown`/`components`/`snippets` too, so the SAME
|
|
117
|
+
* write-boundary guard must cover them, not just `styles`/`engineStyles`.
|
|
118
|
+
* `tokensFile` is included even though it is advisory/unenforced elsewhere —
|
|
119
|
+
* defense in depth against a future consumer reading it unchecked.
|
|
120
|
+
*
|
|
121
|
+
* A WRITE-BOUNDARY guard, not a read-path check (mirrors the theme-only
|
|
122
|
+
* predecessor): callers invoke this before copying anything or wiring a
|
|
123
|
+
* manifest, never from a plain listing/read path, so one hand-edited
|
|
124
|
+
* metadata file cannot take down listing every extension.
|
|
125
|
+
*/
|
|
126
|
+
export declare function assertExtensionContained(meta: ExtensionMetadata): void;
|
|
127
|
+
/**
|
|
128
|
+
* An extension's declared paths, resolved to absolute, existence-checked
|
|
129
|
+
* filesystem paths — every list/single-path field goes through the SAME
|
|
130
|
+
* {@link resolveDeclaredStyles} a plugin's `styles` export and a theme's
|
|
131
|
+
* `styles`/`engineStyles.native` already resolve through, so a broken
|
|
132
|
+
* declaration (a missing file) throws HERE, at load/apply time, instead of
|
|
133
|
+
* failing silently deep in the render pipeline (or never, for `components`/
|
|
134
|
+
* `snippets`, which nothing yet reads — #240/#242).
|
|
135
|
+
*
|
|
136
|
+
* `tokensFile` is the one exception, kept as declared (relative, not
|
|
137
|
+
* existence-checked) — it stays purely advisory, matching
|
|
138
|
+
* `ThemeInfo.tokensFile`'s pre-#241 contract.
|
|
139
|
+
*/
|
|
140
|
+
export interface ResolvedExtension {
|
|
141
|
+
/** Absolute path to the markdown-it entry module, when declared. */
|
|
142
|
+
markdown?: string;
|
|
143
|
+
/** Absolute paths, in cascade order, when any are declared. */
|
|
144
|
+
styles?: string[];
|
|
145
|
+
/** Absolute paths, in cascade order, when any are declared. */
|
|
146
|
+
engineStyles?: string[];
|
|
147
|
+
/** Declared-relative path of the `:root` token surface — advisory. */
|
|
148
|
+
tokensFile?: string;
|
|
149
|
+
/** Absolute path to the component catalog file, when declared (#242). */
|
|
150
|
+
components?: string;
|
|
151
|
+
/** Absolute path to the snippets folder, when declared (#240). */
|
|
152
|
+
snippets?: string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Resolve every path {@link ExtensionMetadata} declares, relative to `dir`
|
|
156
|
+
* (the extension's own folder). `subject` names the declaring thing for a
|
|
157
|
+
* resolution error, e.g. `Plugin "my-extension"` — passed straight through to
|
|
158
|
+
* `resolveDeclaredStyles`, so a broken `markdown`/`components`/`snippets`
|
|
159
|
+
* entry throws the same "declares stylesheet ... but no file exists" shape a
|
|
160
|
+
* broken `styles` entry always has (the wording says "stylesheet" for every
|
|
161
|
+
* field — a small, accepted cost of resolving all of them through one
|
|
162
|
+
* function rather than inventing per-field messages).
|
|
163
|
+
*/
|
|
164
|
+
export declare function resolveExtension(dir: string, meta: ExtensionMetadata, subject: string): ResolvedExtension;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** Which starter package to create. */
|
|
2
|
+
export type ExtensionKind = "plugin" | "theme";
|
|
3
|
+
/** The kinds `--kind` accepts, for CLI help text and pickers. */
|
|
4
|
+
export declare const EXTENSION_KINDS: readonly ["plugin", "theme"];
|
|
5
|
+
/**
|
|
6
|
+
* The class/property prefix a scaffolded extension is FORBIDDEN to take.
|
|
7
|
+
* `gp-` is Gutterpress core's own vocabulary (CLAUDE.md §6); an extension
|
|
8
|
+
* using it does not conflict with core, it silently overrides it.
|
|
9
|
+
*/
|
|
10
|
+
export declare const RESERVED_PREFIX = "gp-";
|
|
11
|
+
/** Inputs the CLI / desktop collect. Only `name`, `kind` and `parentDir` are
|
|
12
|
+
* required; everything else is derived. */
|
|
13
|
+
export interface ScaffoldExtensionOptions {
|
|
14
|
+
/** Human-friendly package name, e.g. "Field Notes". Required. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Which starter to create. Required. */
|
|
17
|
+
kind: ExtensionKind;
|
|
18
|
+
/** Absolute path to the PARENT directory the folder is created in. */
|
|
19
|
+
parentDir: string;
|
|
20
|
+
/** Folder name under `parentDir`. Defaults to a slug of `name`. */
|
|
21
|
+
folderName?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Class / custom-property / marker prefix this package claims. Defaults to
|
|
24
|
+
* the slug plus a hyphen (`field-notes-`). A trailing hyphen is added when
|
|
25
|
+
* missing — the templates concatenate it directly onto a name, so
|
|
26
|
+
* `.${PREFIX}callout` has to produce `.field-notes-callout`.
|
|
27
|
+
*/
|
|
28
|
+
prefix?: string;
|
|
29
|
+
/** Author display name. Defaults to "Anonymous". */
|
|
30
|
+
author?: string;
|
|
31
|
+
/** One-line description for the metadata and the README. */
|
|
32
|
+
description?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface ScaffoldExtensionResult {
|
|
35
|
+
/** Absolute path of the created folder. */
|
|
36
|
+
extensionDir: string;
|
|
37
|
+
/** Absolute path of its `gutterpress.json`. */
|
|
38
|
+
manifestPath: string;
|
|
39
|
+
kind: ExtensionKind;
|
|
40
|
+
/** Folder name / package name that was used. */
|
|
41
|
+
slug: string;
|
|
42
|
+
/** The prefix baked into the scaffolded files. */
|
|
43
|
+
prefix: string;
|
|
44
|
+
/** Absolute path of the file worth opening first. */
|
|
45
|
+
openFile: string;
|
|
46
|
+
/** Every file written, relative to `extensionDir`, in write order. */
|
|
47
|
+
files: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Normalize an author-supplied prefix, or derive one from the slug.
|
|
51
|
+
*
|
|
52
|
+
* The prefix is the single most load-bearing convention an extension has
|
|
53
|
+
* (#245's "which conventions are load-bearing and why"), so it is validated
|
|
54
|
+
* here rather than left to fail as a puzzling CSS bug later: it must read
|
|
55
|
+
* like a CSS identifier, and it must not be core's.
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveExtensionPrefix(slug: string, requested?: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Create a plugin or theme starter package.
|
|
60
|
+
*
|
|
61
|
+
* Resolves with a {@link ScaffoldExtensionResult}; throws a
|
|
62
|
+
* {@link CreateProjectError} (the SAME error type `scaffoldProject` throws, so
|
|
63
|
+
* one `catch` handles both) on any precondition failure.
|
|
64
|
+
*/
|
|
65
|
+
export declare function scaffoldExtension(options: ScaffoldExtensionOptions): Promise<ScaffoldExtensionResult>;
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
export interface LintRunnerOptions {
|
|
2
2
|
files?: string;
|
|
3
3
|
manifest?: string;
|
|
4
|
+
/**
|
|
5
|
+
* Pre-loaded, absolute plugin `styles` file paths (#262) — supplied by the
|
|
6
|
+
* build pipeline (`build-runner.ts`'s `runQualityGates`, via
|
|
7
|
+
* `loadBuildPlugins`) so this call does not load plugins a second time in
|
|
8
|
+
* the same build. `undefined` (the default — every standalone
|
|
9
|
+
* `gutterpress lint` invocation) makes this function load plugins itself,
|
|
10
|
+
* exactly as before, with the same degrade-and-report (warn-and-skip)
|
|
11
|
+
* behavior for a plugin that fails to load. An explicit `[]` from a caller
|
|
12
|
+
* that already knows there is nothing to add is honored as-is, not treated
|
|
13
|
+
* as "unset".
|
|
14
|
+
*/
|
|
15
|
+
pluginStylePaths?: string[];
|
|
4
16
|
}
|
|
5
17
|
export interface LintRunnerResult {
|
|
6
18
|
ok: boolean;
|
|
@@ -12,6 +12,18 @@ export type ReadText = (relPath: string) => Promise<string>;
|
|
|
12
12
|
* emitted by `gp-pin-scope.js`'s `gp_pin_scope_check`, same as
|
|
13
13
|
* `pin_outside_page`, see #226).
|
|
14
14
|
*
|
|
15
|
+
* #240 (declarative container components) adds three more, all emitted by
|
|
16
|
+
* `markers.js`'s `layout_transform`/`scanForUnknownDeclaredMarkers` for a
|
|
17
|
+
* plugin-DECLARED marker: `deprecated_marker` (a `{ deprecated: "…" }`
|
|
18
|
+
* marker, or its `@end-` form, was used), `declared_marker_close_without_open`
|
|
19
|
+
* (an `@end-<name>` with nothing of that kind open — the declared-marker
|
|
20
|
+
* twin of `continue_without_section`), and `declared_marker_eof_close` (an
|
|
21
|
+
* open declared container reached EOF without `autoCloseAt: ["eof"]` — the
|
|
22
|
+
* declared-marker twin of `spread_eof_close`). `unknown_marker` above is
|
|
23
|
+
* reused, not duplicated: a typo close to a DECLARED name warns through the
|
|
24
|
+
* same type, via a second, unconditional check modeled on `unknown_gp_class`
|
|
25
|
+
* rather than the core-only `scanForMistypedMarkers`.
|
|
26
|
+
*
|
|
15
27
|
* `section_without_page` and `implicit_page` were REMOVED 2026-08-12: a
|
|
16
28
|
* @section with no open @page is valid authoring (audited, 17/17 false
|
|
17
29
|
* positives across two real books), and the `implicitPage` option that
|
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge every loaded plugin's `markers` export into ONE flat, resolved
|
|
3
|
+
* registry — `Map<name, ResolvedDecl>` — validating collisions at LOAD TIME
|
|
4
|
+
* (#240 / P2): a declared name that shadows a core reserved name, or that
|
|
5
|
+
* two different plugins both declare, throws immediately, naming both
|
|
6
|
+
* sides, instead of the pre-#240 silent-skip footgun (core claims its
|
|
7
|
+
* `@`-names during block parsing, before any plugin runs, so a colliding
|
|
8
|
+
* plugin marker used to never run and never warn — see the header comment
|
|
9
|
+
* on `KNOWN_KINDS`).
|
|
10
|
+
*
|
|
11
|
+
* @param {{ pluginName: string, markers: Record<string, unknown> }[]} sources
|
|
12
|
+
* One entry per LOADED plugin that declared a non-empty `markers` export,
|
|
13
|
+
* in plugin load order. A plugin with no `markers` export is simply
|
|
14
|
+
* omitted by the caller — this function never sees it.
|
|
15
|
+
* @returns {Map<string, object>} empty when `sources` is empty.
|
|
16
|
+
*/
|
|
17
|
+
export function buildDeclaredMarkerRegistry(sources: {
|
|
18
|
+
pluginName: string;
|
|
19
|
+
markers: Record<string, unknown>;
|
|
20
|
+
}[]): Map<string, object>;
|
|
1
21
|
export default function plugin(md: any, pluginOptions?: {}): void;
|
|
2
22
|
/**
|
|
3
23
|
* The minimal CSS the DOM this module emits requires. Author utility
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ResolvedPluginConfig } from "../../schema/manifest.types";
|
|
2
2
|
import type { LoadedPlugin } from "./renderer";
|
|
3
|
-
export type { GutterpressPlugin, GutterpressPluginMetadata, GutterpressPluginExport, LoadedPlugin, } from "./renderer";
|
|
3
|
+
export type { GutterpressMarkerDeclaration, GutterpressMarkerLabel, GutterpressMarkerTable, GutterpressPlugin, GutterpressPluginMetadata, GutterpressPluginExport, LoadedPlugin, } from "./renderer";
|
|
4
4
|
export { applyPlugins, collectPluginCss, collectPluginStylePaths } from "./renderer";
|
|
5
5
|
/** Test-only mutation seam between snapshot completion and snapshot verification. */
|
|
6
6
|
export declare function __setVendorSnapshotHookForTests(hook?: (sourceRoot: string, snapshotRoot: string) => void | Promise<void>): void;
|