@kirchdev/duxt 0.5.0 → 0.5.1-dev-main.48-5d5fca9
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 +3 -3
- package/app/components/DuxtBrand.vue +1 -1
- package/app/components/DuxtBrunoEntries.vue +1 -1
- package/app/components/DuxtCopyPage.vue +1 -1
- package/app/components/DuxtLandingShowcase.vue +1 -1
- package/app/components/DuxtOpenApiCallbacks.vue +1 -1
- package/app/components/DuxtOpenApiClient.vue +1 -1
- package/app/components/DuxtOpenApiMedia.vue +1 -1
- package/app/components/DuxtOpenApiParameters.vue +1 -1
- package/app/components/DuxtOpenApiResponses.vue +1 -1
- package/app/components/DuxtOpenApiSchema.vue +1 -1
- package/app/components/DuxtOpenApiSecurity.vue +1 -1
- package/app/components/content/BrunoOverview.vue +4 -1
- package/app/components/content/BrunoRequest.vue +2 -2
- package/app/components/content/OpenApiOperation.vue +1 -1
- package/app/components/content/OpenApiOperations.vue +1 -1
- package/app/components/content/OpenApiOverview.vue +1 -1
- package/app/components/content/Partial.vue +1 -1
- package/app/components/content/ProseImg.vue +1 -1
- package/app/composables/useDuxtCollection.ts +1 -1
- package/app/composables/useDuxtNavigation.ts +1 -1
- package/app/composables/useDuxtSearch.ts +1 -1
- package/app/types/duxt.d.ts +17 -0
- package/app/utils/duxt-config.ts +5 -5
- package/app/utils/openapi.ts +1 -1
- package/app/utils/search-scope.ts +1 -1
- package/app/utils/version-choices.ts +8 -5
- package/app/utils/version-paths.ts +1 -1
- package/bin/duxt-cache-key.mjs +3 -2
- package/bin/duxt-og-cache.mjs +3 -1
- package/bin/duxt.mjs +2 -2
- package/{bruno-parse.ts → build/bruno/bruno-parse.ts} +1 -1
- package/{bruno-zip.ts → build/bruno/bruno-zip.ts} +1 -1
- package/{report.ts → build/cli/report.ts} +7 -7
- package/{validate-report.ts → build/cli/validate-report.ts} +3 -3
- package/{duxt-app-config.ts → build/config/duxt-app-config.ts} +5 -2
- package/{git-contributors.ts → build/git/git-contributors.ts} +64 -31
- package/{search-records.ts → build/search/search-records.ts} +3 -3
- package/{section-reports.ts → build/sections/section-reports.ts} +2 -2
- package/{sections-bruno.ts → build/sections/sections-bruno.ts} +4 -4
- package/{sections-changelog.ts → build/sections/sections-changelog.ts} +4 -4
- package/{sections-openapi.ts → build/sections/sections-openapi.ts} +3 -3
- package/{sections-resolve.ts → build/sections/sections-resolve.ts} +2 -2
- package/{sections.ts → build/sections/sections.ts} +4 -4
- package/{sources-cache.ts → build/sources/sources-cache.ts} +2 -2
- package/{sources-git.ts → build/sources/sources-git.ts} +46 -31
- package/{sources-resolve.ts → build/sources/sources-resolve.ts} +107 -17
- package/content.config.ts +4 -4
- package/modules/bruno.ts +12 -6
- package/modules/config.ts +9 -6
- package/modules/git-meta.ts +9 -6
- package/modules/redirects.ts +7 -4
- package/modules/search-records.ts +4 -4
- package/modules/validate.ts +9 -6
- package/nuxt.config.ts +1 -1
- package/package.json +22 -85
- package/server/devtools/content.ts +2 -2
- package/server/devtools/preview.ts +3 -3
- package/server/devtools/render/content.ts +2 -2
- package/server/devtools/render/sources.ts +4 -1
- package/server/devtools/sources.ts +1 -1
- package/server/mcp/tools/read-page.ts +1 -1
- package/server/middleware/raw-markdown.ts +2 -2
- package/server/routes/llms-full.txt.get.ts +1 -1
- package/server/utils/llms-pages.ts +1 -1
- package/server/utils/mcp-docs.ts +2 -2
- /package/{bruno-model.ts → build/bruno/bruno-model.ts} +0 -0
- /package/{cli.ts → build/cli/cli.ts} +0 -0
- /package/{content-cache.ts → build/content/content-cache.ts} +0 -0
- /package/{frontmatter.ts → build/content/frontmatter.ts} +0 -0
- /package/{highlight-langs.ts → build/content/highlight-langs.ts} +0 -0
- /package/{og-image-cache.ts → build/og-image/og-image-cache.ts} +0 -0
- /package/{openapi-model.ts → build/openapi/openapi-model.ts} +0 -0
- /package/{openapi-parse.ts → build/openapi/openapi-parse.ts} +0 -0
- /package/{section-input.ts → build/sections/section-input.ts} +0 -0
- /package/{section-markdown.ts → build/sections/section-markdown.ts} +0 -0
- /package/{repository-root.ts → build/sources/repository-root.ts} +0 -0
- /package/{sources.ts → build/sources/sources.ts} +0 -0
- /package/{tfplugindocs.ts → build/sources/tfplugindocs.ts} +0 -0
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ Everything lives under the `duxt` key of `app.config.ts`. The keys most sites to
|
|
|
125
125
|
Every text field takes a literal, an i18n key, or a per-locale record — a single-language site never sees the other two.
|
|
126
126
|
|
|
127
127
|
> [!TIP]
|
|
128
|
-
> The full surface — `navigation`, `sections`, `landing`, `feed`, `footer` and the rest — is typed, and the types are the documentation: [`app/types/duxt.d.ts`](app/types/duxt.d.ts) carries a comment per key explaining what it costs and when it is read.
|
|
128
|
+
> The full surface — `navigation`, `sections`, `landing`, `feed`, `footer` and the rest — is typed, and the types are the documentation: [`packages/duxt/app/types/duxt.d.ts`](packages/duxt/app/types/duxt.d.ts) carries a comment per key explaining what it costs and when it is read.
|
|
129
129
|
|
|
130
130
|
## 🧪 Development
|
|
131
131
|
|
|
@@ -136,7 +136,7 @@ pnpm install # wires the husky hooks
|
|
|
136
136
|
pnpm check # lint + format + typecheck + tests + policy parity + build + a11y
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
A pnpm workspace driven by Turborepo. The layer is [`packages/duxt`](packages/duxt) — `nuxt.config.ts`, `content.config.ts`, `app/`, `modules/`, `server/` and the build-time modules under `build/`. [`apps/www`](apps/www) is the site that consumes it, and the development target: it deliberately carries the awkward cases — two repositories, four refs, one version of each lifecycle. The root holds only the workspace and meta configuration, plus `docs/`, which `apps/www` publishes. It is not a template; the exemplary starting point lives in [`kirchDev/duxt-starter`](https://github.com/kirchDev/duxt-starter).
|
|
140
140
|
|
|
141
141
|
## 🎨 Assets & branding
|
|
142
142
|
|
|
@@ -148,7 +148,7 @@ The mark is the package name with its first letter bracketed — `[d]uxt` — be
|
|
|
148
148
|
Every asset, the colour values, why the icon's brackets are redrawn and the font licensing are in [Conventions → Branding](https://duxt.app/conventions/branding).
|
|
149
149
|
|
|
150
150
|
> [!IMPORTANT]
|
|
151
|
-
> The layer ships **no** branding. `duxt.logo` is unset by default, so `DuxtBrand` falls back to the consumer's own `duxt.title` beside a generic icon: a site extending duxt shows its own name in the header and footer and its own icon in the tab, never this one. These assets belong to this repository and to `www
|
|
151
|
+
> The layer ships **no** branding. `duxt.logo` is unset by default, so `DuxtBrand` falls back to the consumer's own `duxt.title` beside a generic icon: a site extending duxt shows its own name in the header and footer and its own icon in the tab, never this one. These assets belong to this repository and to `apps/www`, not to the published package.
|
|
152
152
|
|
|
153
153
|
## 🤝 Contributing
|
|
154
154
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* THE LAYER STAYS UNBRANDED. `logo` is unset by default and the fallback is a
|
|
10
10
|
* generic book icon beside `title` — a site extending duxt must show its own
|
|
11
|
-
* name, never this one. duxt's own `www/` sets `logo` like any other consumer,
|
|
11
|
+
* name, never this one. duxt's own `apps/www/` sets `logo` like any other consumer,
|
|
12
12
|
* which is also what keeps the option honest: the development site exercises
|
|
13
13
|
* the same path a stranger takes.
|
|
14
14
|
*/
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
DuxtBrunoAuth,
|
|
4
|
+
DuxtBrunoEntry
|
|
5
|
+
} from '../../../build/bruno/bruno-model';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* The collection's front page: what is in it, and how to get it.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { DuxtBrunoRequest } from '../../../bruno-model';
|
|
2
|
+
import type { DuxtBrunoRequest } from '../../../build/bruno/bruno-model';
|
|
3
3
|
import type {
|
|
4
4
|
DuxtOpenApiOperation,
|
|
5
5
|
DuxtOpenApiServer
|
|
6
|
-
} from '../../../openapi-model';
|
|
6
|
+
} from '../../../build/openapi/openapi-model';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* One Bruno request, as the two columns of the reference.
|
|
@@ -101,7 +101,7 @@ const props = withDefaults(
|
|
|
101
101
|
* focus ring and the dialog were all switched off on every image in the
|
|
102
102
|
* site. It survived from the day the component was written because nothing
|
|
103
103
|
* in the repository rendered one: every `![…]` in the reference sits inside
|
|
104
|
-
* a code block. `www/demo/docs/3.images.md` and `check:images` are the two
|
|
104
|
+
* a code block. `apps/www/demo/docs/3.images.md` and `check:images` are the two
|
|
105
105
|
* halves of making sure it cannot again.
|
|
106
106
|
*
|
|
107
107
|
* A default is what suppresses the cast — `isAbsent && !hasDefault` is the
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DuxtResolvedSource } from '../../sources-resolve';
|
|
1
|
+
import type { DuxtResolvedSource } from '../../build/sources/sources-resolve';
|
|
2
2
|
import { searchSources } from '../utils/search-scope';
|
|
3
3
|
// Imported rather than auto-imported, the same as `searchSources` above: this
|
|
4
4
|
// composable is covered by a plain node test, which has no Nuxt globals.
|
package/app/types/duxt.d.ts
CHANGED
|
@@ -271,6 +271,23 @@ declare global {
|
|
|
271
271
|
status?: DuxtSourceStatusInput;
|
|
272
272
|
/** Lifecycle defaults by ref kind; an explicit ref status wins. */
|
|
273
273
|
statusDefaults?: DuxtSourceStatusDefaultsInput;
|
|
274
|
+
/**
|
|
275
|
+
* Discover release tags to publish as versions, beside or instead of
|
|
276
|
+
* `refs`: every release, or the newest one per minor or major line. An
|
|
277
|
+
* explicit ref still overrides a discovered tag's label, lifecycle, default
|
|
278
|
+
* and locales. Pre-releases are left out unless asked for.
|
|
279
|
+
*/
|
|
280
|
+
releases?: {
|
|
281
|
+
select: 'all' | 'minor' | 'major';
|
|
282
|
+
prereleases?: boolean;
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* The one package whose tags this source publishes, in a repository that
|
|
286
|
+
* tags `<component>@vX.Y.Z` — `'duxt'` reads `duxt@v0.4.0` and ignores
|
|
287
|
+
* `duxt-typesense@v0.1.0`. Applies to `latest` and `releases`; plain
|
|
288
|
+
* `vX.Y.Z` tags still count.
|
|
289
|
+
*/
|
|
290
|
+
tagComponent?: string;
|
|
274
291
|
/**
|
|
275
292
|
* The repository a source read off disk lives in, for links back to it.
|
|
276
293
|
* Not `repo`, which is what makes Content download a source.
|
package/app/utils/duxt-config.ts
CHANGED
|
@@ -76,7 +76,7 @@ export const duxtDefaults: DuxtConfig = {
|
|
|
76
76
|
// the INTERFACE and not a tree or a repository. The dropdown that used to
|
|
77
77
|
// sit beside it pointed at duxt's own tech stack — five links belonging to
|
|
78
78
|
// this project and to no site that extends it. It lives in
|
|
79
|
-
// `www/app/app.config.ts` now.
|
|
79
|
+
// `apps/www/app/app.config.ts` now.
|
|
80
80
|
{ label: 'duxt.defaults.navigation.docs', icon: 'lucide:book-open-text' }
|
|
81
81
|
],
|
|
82
82
|
|
|
@@ -96,7 +96,7 @@ export const duxtDefaults: DuxtConfig = {
|
|
|
96
96
|
*
|
|
97
97
|
* Left empty, the row does not render and the sidebar falls back to the whole
|
|
98
98
|
* tree, which is the right shape for a site that has not split its docs into
|
|
99
|
-
* sections at all. duxt's own sections live in `www/app/app.config.ts`.
|
|
99
|
+
* sections at all. duxt's own sections live in `apps/www/app/app.config.ts`.
|
|
100
100
|
*/
|
|
101
101
|
sections: [],
|
|
102
102
|
|
|
@@ -107,7 +107,7 @@ export const duxtDefaults: DuxtConfig = {
|
|
|
107
107
|
* whoever runs the site. Shipping duxt's own repository here gave a stranger
|
|
108
108
|
* extending the layer a GitHub icon pointing at somebody else's project —
|
|
109
109
|
* the same mistake the legal row already settled. kirchDev's own links live
|
|
110
|
-
* in `www/app/app.config.ts`, where they are an example rather than a
|
|
110
|
+
* in `apps/www/app/app.config.ts`, where they are an example rather than a
|
|
111
111
|
* default.
|
|
112
112
|
*
|
|
113
113
|
* Their i18n keys went with them. `duxt.defaults.*` translates the defaults
|
|
@@ -130,7 +130,7 @@ export const duxtDefaults: DuxtConfig = {
|
|
|
130
130
|
// something about the state of a project — "beta", "v2 is out" — and the
|
|
131
131
|
// headline and the paragraph under it say what the project IS. The layer
|
|
132
132
|
// knows none of the three. Those two were duxt's OWN marketing showing
|
|
133
|
-
// through every site that extended it; they live in `www/app/app.config.ts`
|
|
133
|
+
// through every site that extended it; they live in `apps/www/app/app.config.ts`
|
|
134
134
|
// now, in the record form, because the Nitro routes that read them have no
|
|
135
135
|
// i18n — see `server/utils/duxt-server-text.ts`.
|
|
136
136
|
//
|
|
@@ -160,7 +160,7 @@ export const duxtDefaults: DuxtConfig = {
|
|
|
160
160
|
*
|
|
161
161
|
* Their translations left with them — `duxt.defaults.*` translates the
|
|
162
162
|
* interface the layer draws, never content a site writes. duxt's own cards
|
|
163
|
-
* live in `www/app/app.config.ts`, where each one POINTS at the page that
|
|
163
|
+
* live in `apps/www/app/app.config.ts`, where each one POINTS at the page that
|
|
164
164
|
* explains it, which the layer could never know.
|
|
165
165
|
*
|
|
166
166
|
* Left empty, the band does not render: the landing gates the whole section
|
package/app/utils/openapi.ts
CHANGED
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
* rest of it is: every version bug this layer has had came from prefix work
|
|
12
12
|
* done inline in a component, where it could only be checked by clicking.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
compareVersionTags,
|
|
16
|
+
parseVersionTag
|
|
17
|
+
} from '../../build/sources/sources-resolve';
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* What a reader needs to see first: work that may change, the edition they
|
|
@@ -33,11 +36,11 @@ function compareEditions(a: DuxtResolvedSource, b: DuxtResolvedSource): number {
|
|
|
33
36
|
|
|
34
37
|
const aVersion = a.version!;
|
|
35
38
|
const bVersion = b.version!;
|
|
36
|
-
const semver = /^v?\d+\.\d+\.\d+(?:-.+)?$/;
|
|
37
39
|
|
|
38
|
-
// The shared comparator knows full tags
|
|
39
|
-
// deliberately not tags, but still sort
|
|
40
|
-
|
|
40
|
+
// The shared comparator knows full tags, component-prefixed ones included.
|
|
41
|
+
// Demo editions such as `v3.x` are deliberately not tags, but still sort
|
|
42
|
+
// newest-first inside their group.
|
|
43
|
+
return parseVersionTag(aVersion) && parseVersionTag(bVersion)
|
|
41
44
|
? compareVersionTags(aVersion, bVersion)
|
|
42
45
|
: bVersion.localeCompare(aVersion);
|
|
43
46
|
}
|
|
@@ -86,4 +86,4 @@ export function versionSwitchPath(
|
|
|
86
86
|
* Nuxt scans for auto-imports, and `sources-resolve.ts` is plain logic with no
|
|
87
87
|
* Node imports — the same property that lets `app.config.ts` read it.
|
|
88
88
|
*/
|
|
89
|
-
export { versionRelation } from '../../sources-resolve';
|
|
89
|
+
export { versionRelation } from '../../build/sources/sources-resolve';
|
package/bin/duxt-cache-key.mjs
CHANGED
|
@@ -37,8 +37,9 @@ Documentation: ${guide}`);
|
|
|
37
37
|
|
|
38
38
|
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
39
39
|
|
|
40
|
-
const { duxtSourcesCache, runDuxtSourcesCacheCli } =
|
|
41
|
-
|
|
40
|
+
const { duxtSourcesCache, runDuxtSourcesCacheCli } = await jiti.import(
|
|
41
|
+
'../build/sources/sources-cache'
|
|
42
|
+
);
|
|
42
43
|
|
|
43
44
|
try {
|
|
44
45
|
const rootIndex = argv.indexOf('--root');
|
package/bin/duxt-og-cache.mjs
CHANGED
|
@@ -41,7 +41,9 @@ Documentation: ${guide}`);
|
|
|
41
41
|
|
|
42
42
|
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
43
43
|
|
|
44
|
-
const { duxtOgImageCacheCommand } = await jiti.import(
|
|
44
|
+
const { duxtOgImageCacheCommand } = await jiti.import(
|
|
45
|
+
'../build/og-image/og-image-cache'
|
|
46
|
+
);
|
|
45
47
|
|
|
46
48
|
try {
|
|
47
49
|
const { output, exitCode } = duxtOgImageCacheCommand(argv);
|
package/bin/duxt.mjs
CHANGED
|
@@ -26,8 +26,8 @@ process.removeAllListeners('warning');
|
|
|
26
26
|
|
|
27
27
|
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
28
28
|
|
|
29
|
-
const { runDuxtCli } = await jiti.import('../cli');
|
|
30
|
-
const { duxtReport } = await jiti.import('../report');
|
|
29
|
+
const { runDuxtCli } = await jiti.import('../build/cli/cli');
|
|
30
|
+
const { duxtReport } = await jiti.import('../build/cli/report');
|
|
31
31
|
|
|
32
32
|
try {
|
|
33
33
|
// `duxtReport` is passed rather than called: usage has to answer on a site
|
|
@@ -39,7 +39,7 @@ import type {
|
|
|
39
39
|
DuxtBrunoParam,
|
|
40
40
|
DuxtBrunoRequest
|
|
41
41
|
} from './bruno-model';
|
|
42
|
-
import type { DuxtSectionInput } from '
|
|
42
|
+
import type { DuxtSectionInput } from '../sections/sections-resolve';
|
|
43
43
|
|
|
44
44
|
/** The manifest at the root of every Bruno collection. */
|
|
45
45
|
const MANIFEST = 'bruno.json';
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* that rebuilds nightly does not publish a new download for a collection nobody
|
|
24
24
|
* changed — the archive is a function of the files, and of nothing else.
|
|
25
25
|
*/
|
|
26
|
-
import type { DuxtSectionInput } from '
|
|
26
|
+
import type { DuxtSectionInput } from '../sections/sections-resolve';
|
|
27
27
|
import { BRUNO_UNPUBLISHED } from './bruno-parse';
|
|
28
28
|
|
|
29
29
|
/** One file in the archive. */
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
|
-
import { contentCacheFile, readContentCacheAt } from '
|
|
3
|
-
import { readDuxtBuildConfig } from '
|
|
4
|
-
import { duxtManifest, duxtSectionTypes } from '
|
|
5
|
-
import { readSectionReports } from '
|
|
6
|
-
import { resolveLatestRefs } from '
|
|
7
|
-
import { redirectRules } from '
|
|
2
|
+
import { contentCacheFile, readContentCacheAt } from '../content/content-cache';
|
|
3
|
+
import { readDuxtBuildConfig } from '../config/duxt-app-config';
|
|
4
|
+
import { duxtManifest, duxtSectionTypes } from '../sections/sections-resolve';
|
|
5
|
+
import { readSectionReports } from '../sections/section-reports';
|
|
6
|
+
import { resolveLatestRefs } from '../sources/sources-git';
|
|
7
|
+
import { redirectRules } from '../../modules/redirects';
|
|
8
8
|
import type { Collected, PageRecord } from './validate-report';
|
|
9
9
|
import { report, walk } from './validate-report';
|
|
10
|
-
import type { DuxtResolvedSource } from '
|
|
10
|
+
import type { DuxtResolvedSource } from '../sources/sources-resolve';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* The devtools tab's answers, as text a terminal — or a model — can read.
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* can run the SAME checks against the pages the site is actually serving,
|
|
9
9
|
* rather than reprinting a build log that has already scrolled away.
|
|
10
10
|
*/
|
|
11
|
-
import { reservedSegments } from '
|
|
12
|
-
import { packageCommandIssues } from '
|
|
13
|
-
import { resolveDocumentationPath } from '
|
|
11
|
+
import { reservedSegments } from '../sources/sources-resolve';
|
|
12
|
+
import { packageCommandIssues } from '../../app/utils/package-command';
|
|
13
|
+
import { resolveDocumentationPath } from '../../app/utils/documentation-link';
|
|
14
14
|
|
|
15
15
|
export interface PageRecord {
|
|
16
16
|
collection: string;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { createJiti } from 'jiti';
|
|
4
|
-
import type {
|
|
5
|
-
|
|
4
|
+
import type {
|
|
5
|
+
DuxtSource,
|
|
6
|
+
DuxtSourcesOptions
|
|
7
|
+
} from '../sources/sources-resolve';
|
|
8
|
+
import type { DuxtSectionTypes } from '../sections/sections-resolve';
|
|
6
9
|
|
|
7
10
|
/** The build-time half of `app.config`'s `duxt` key. */
|
|
8
11
|
export interface DuxtBuildConfig {
|
|
@@ -107,7 +107,8 @@ const SEPARATOR = '\u001f';
|
|
|
107
107
|
const RECORD = '\u0001';
|
|
108
108
|
|
|
109
109
|
/** The fields one record carries, in order. */
|
|
110
|
-
const FORMAT =
|
|
110
|
+
const FORMAT =
|
|
111
|
+
`${RECORD}%H${SEPARATOR}%P${SEPARATOR}%an` + `${SEPARATOR}%ae${SEPARATOR}%D`;
|
|
111
112
|
|
|
112
113
|
/** What git is asked, and the whole of why each flag is there. */
|
|
113
114
|
const ARGUMENTS = [
|
|
@@ -119,10 +120,9 @@ const ARGUMENTS = [
|
|
|
119
120
|
// bucketing those into the newest tag would credit people for work that has
|
|
120
121
|
// not shipped.
|
|
121
122
|
'--tags',
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
// paying for one `git` process per release.
|
|
123
|
+
// Children before their parents is what lets the pass below propagate a
|
|
124
|
+
// release through the graph. It does NOT make tag ranges contiguous: two
|
|
125
|
+
// parents of one merge may be walked in either order.
|
|
126
126
|
'--topo-order',
|
|
127
127
|
'--decorate=short',
|
|
128
128
|
'--decorate-refs=refs/tags/*',
|
|
@@ -132,12 +132,18 @@ const ARGUMENTS = [
|
|
|
132
132
|
/**
|
|
133
133
|
* Every release tag, with the people whose commits it carries.
|
|
134
134
|
*
|
|
135
|
-
* ONE `git log` FOR THE WHOLE HISTORY, walked
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
135
|
+
* ONE `git log` FOR THE WHOLE HISTORY, walked children-first and reconstructed
|
|
136
|
+
* as a graph in memory. Every tag seeds a release number on its commit; that
|
|
137
|
+
* number flows to its parents, while an older tag replaces a newer number at
|
|
138
|
+
* its own boundary. A commit therefore belongs to the oldest tag that can
|
|
139
|
+
* reach it — exactly the set `<previous tag>..<tag>` names — without paying for
|
|
140
|
+
* one git process per release.
|
|
141
|
+
*
|
|
142
|
+
* THE GRAPH IS LOAD-BEARING. Tag markers do not delimit contiguous slices of a
|
|
143
|
+
* topo-ordered log: where a release merge has the older tag on one parent and
|
|
144
|
+
* new work on another, git may print the older tag before that parallel branch.
|
|
145
|
+
* A mutable "current tag" then gives the work to the release before it and
|
|
146
|
+
* leaves the release that merged it empty.
|
|
141
147
|
*
|
|
142
148
|
* A MERGE COMMIT SETS THE BOUNDARY AND CREDITS NOBODY. It has to be walked,
|
|
143
149
|
* because release-please tags the merge commit its release pull request
|
|
@@ -149,40 +155,67 @@ const ARGUMENTS = [
|
|
|
149
155
|
export function parseReleaseContributors(
|
|
150
156
|
output: string
|
|
151
157
|
): Map<string, DuxtContributor[]> {
|
|
152
|
-
const commits
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
const commits: {
|
|
159
|
+
hash: string;
|
|
160
|
+
parents: string[];
|
|
161
|
+
author: DuxtCommitAuthor;
|
|
162
|
+
merge: boolean;
|
|
163
|
+
tags: string[];
|
|
164
|
+
}[] = [];
|
|
165
|
+
const tagGroups: string[][] = [];
|
|
157
166
|
|
|
158
167
|
for (const record of output.split(RECORD)) {
|
|
159
168
|
if (!record.trim()) continue;
|
|
160
169
|
|
|
161
|
-
const [parents, name, email, decoration] = record
|
|
170
|
+
const [hash, parents, name, email, decoration] = record
|
|
162
171
|
.split('\n')[0]!
|
|
163
172
|
.split(SEPARATOR);
|
|
164
|
-
|
|
165
173
|
const tags = tagsOf(decoration ?? '');
|
|
166
174
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
175
|
+
commits.push({
|
|
176
|
+
hash: hash ?? '',
|
|
177
|
+
parents: (parents ?? '').trim().split(/\s+/).filter(Boolean),
|
|
178
|
+
author: { name: name ?? '', email: email ?? '' },
|
|
179
|
+
merge: (parents ?? '').trim().includes(' '),
|
|
180
|
+
tags
|
|
181
|
+
});
|
|
171
182
|
|
|
172
|
-
if (
|
|
183
|
+
if (tags.length) tagGroups.push(tags);
|
|
184
|
+
}
|
|
173
185
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
186
|
+
/** The release each reachable commit belongs to, newest group numbered 0. */
|
|
187
|
+
const owners = new Map<string, number>();
|
|
188
|
+
const authors = tagGroups.map(() => [] as DuxtCommitAuthor[]);
|
|
189
|
+
let group = 0;
|
|
177
190
|
|
|
178
|
-
|
|
179
|
-
|
|
191
|
+
// Seed every boundary before walking. A newer release reaches an older tag's
|
|
192
|
+
// commit too; the larger number there is what stops that propagation.
|
|
193
|
+
for (const commit of commits) {
|
|
194
|
+
if (!commit.tags.length) continue;
|
|
195
|
+
owners.set(commit.hash, group);
|
|
196
|
+
group += 1;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
for (const commit of commits) {
|
|
200
|
+
const owner = owners.get(commit.hash);
|
|
201
|
+
if (owner === undefined) continue;
|
|
180
202
|
|
|
181
|
-
|
|
203
|
+
// A merge carries more than one parent. It sets and propagates the boundary
|
|
204
|
+
// but says nothing itself; apps are omitted for the same reason as before.
|
|
205
|
+
if (!commit.merge && !isGitHubApp(commit.author)) {
|
|
206
|
+
authors[owner]!.push(commit.author);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
for (const parent of commit.parents) {
|
|
210
|
+
const previous = owners.get(parent);
|
|
211
|
+
if (previous === undefined || owner > previous) owners.set(parent, owner);
|
|
212
|
+
}
|
|
182
213
|
}
|
|
183
214
|
|
|
184
|
-
|
|
185
|
-
|
|
215
|
+
const contributors = new Map<string, DuxtContributor[]>();
|
|
216
|
+
for (const [index, tags] of tagGroups.entries()) {
|
|
217
|
+
const people = contributorsOf(authors[index]!);
|
|
218
|
+
for (const tag of tags) contributors.set(tag, people);
|
|
186
219
|
}
|
|
187
220
|
|
|
188
221
|
return contributors;
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
* run it without a build.
|
|
43
43
|
*/
|
|
44
44
|
import { createHash } from 'node:crypto';
|
|
45
|
-
import type { CachedPage } from '
|
|
46
|
-
import type { DuxtResolvedSource } from '
|
|
47
|
-
import { duxtPageSearchable } from '
|
|
45
|
+
import type { CachedPage } from '../content/content-cache';
|
|
46
|
+
import type { DuxtResolvedSource } from '../sources/sources-resolve';
|
|
47
|
+
import { duxtPageSearchable } from '../../app/utils/page-controls';
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* One entry of an external search index, as duxt hands it over.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
|
-
import type { DuxtResolvedSource } from '
|
|
2
|
+
import type { DuxtResolvedSource } from '../sources/sources-resolve';
|
|
3
3
|
import type { DuxtSectionTypes } from './sections-resolve';
|
|
4
4
|
import {
|
|
5
5
|
duxtSectionTypes,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
sectionArtefactExists,
|
|
12
12
|
sectionInputKind
|
|
13
13
|
} from './section-input';
|
|
14
|
-
import { repositoryRoot } from '
|
|
14
|
+
import { repositoryRoot } from '../sources/repository-root';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Fill in what each LOCAL artefact had to say, for the manifest a module holds.
|