Skip to content

Commit 1480c3b

Browse files
Infrastructure for building unversioned docs pages for the latest stable version (#1107)
Fixes #1108
1 parent 57dbe7b commit 1480c3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+606
-225
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ packages/lit-dev-content/site/fonts/manrope
1111
packages/lit-dev-content/temp
1212
packages/lit-dev-content/samples/js
1313
packages/lit-dev-content/src/public-vars.ts
14+
# The unversioned docs are generated by:
15+
#
16+
# `npm run build:unversioned-docs -w lit-dev-content`
17+
packages/lit-dev-content/site/docs/unversioned
1418

1519
packages/lit-dev-api/api-data/*/repo/
1620
packages/lit-dev-api/api-data/*/INSTALLED

packages/lit-dev-api/api-data/lit-2/pages.json

+15-15
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"name": "LitElement",
1313
"comment": {
1414
"shortText": "Base element class that manages element properties and attributes, and\nrenders a lit-html template.",
15-
"text": "To define a component, subclass `LitElement` and implement a\n`render` method to provide the component's template. Define properties\nusing the [`properties`](/docs/api/LitElement/#LitElement.properties) property or the\n[`property`](/docs/api/decorators/#property) decorator.\n"
15+
"text": "To define a component, subclass `LitElement` and implement a\n`render` method to provide the component's template. Define properties\nusing the [`properties`](/docs/v2/api/LitElement/#LitElement.properties) property or the\n[`property`](/docs/v2/api/decorators/#property) decorator.\n"
1616
},
1717
"sources": [
1818
{
@@ -949,7 +949,7 @@
949949
"tag": "@nocollapse"
950950
}
951951
],
952-
"shortText": "Creates a property accessor on the element prototype if one does not exist\nand stores a [`PropertyDeclaration`](/docs/api/ReactiveElement/#PropertyDeclaration) for the property with the\ngiven options. The property setter calls the property's `hasChanged`\nproperty option or uses a strict identity check to determine whether or not\nto request an update.",
952+
"shortText": "Creates a property accessor on the element prototype if one does not exist\nand stores a [`PropertyDeclaration`](/docs/v2/api/ReactiveElement/#PropertyDeclaration) for the property with the\ngiven options. The property setter calls the property's `hasChanged`\nproperty option or uses a strict identity check to determine whether or not\nto request an update.",
953953
"text": "This method may be overridden to customize properties; however,\nwhen doing so, it's important to call `super.createProperty` to ensure\nthe property is setup correctly. This method calls\n`getPropertyDescriptor` internally to get a descriptor to install.\nTo customize what properties do when they are get or set, override\n`getPropertyDescriptor`. To customize the options for a property,\nimplement `createProperty` like this:\n```ts\nstatic createProperty(name, options) {\n options = Object.assign(options, {myOption: true});\n super.createProperty(name, options);\n}\n```\n"
954954
},
955955
"sources": [
@@ -1222,7 +1222,7 @@
12221222
}
12231223
],
12241224
"shortText": "Returns the property options associated with the given property.\nThese options are defined with a `PropertyDeclaration` via the `properties`\nobject or the `@property` decorator and are registered in\n`createProperty(...)`.",
1225-
"text": "Note, this method should be considered \"final\" and not overridden. To\ncustomize the options for a given property, override\n[`createProperty`](/docs/api/LitElement/#LitElement.createProperty).\n"
1225+
"text": "Note, this method should be considered \"final\" and not overridden. To\ncustomize the options for a given property, override\n[`createProperty`](/docs/v2/api/LitElement/#LitElement.createProperty).\n"
12261226
},
12271227
"sources": [
12281228
{
@@ -1760,7 +1760,7 @@
17601760
"tag": "@nocollapse"
17611761
}
17621762
],
1763-
"shortText": "Array of styles to apply to the element. The styles should be defined\nusing the [`css`](/docs/api/styles/#css) tag function, via constructible stylesheets, or\nimported from native CSS module scripts.",
1763+
"shortText": "Array of styles to apply to the element. The styles should be defined\nusing the [`css`](/docs/v2/api/styles/#css) tag function, via constructible stylesheets, or\nimported from native CSS module scripts.",
17641764
"text": "Note on Content Security Policy:\nElement styles are implemented with `<style>` tags when the browser doesn't\nsupport adopted StyleSheets. To use such `<style>` tags with the style-src\nCSP directive, the style-src value must either include 'unsafe-inline' or\n`nonce-<base64-value>` with `<base64-value>` replaced be a server-generated\nnonce.\nTo provide a nonce to use on generated `<style>` elements, set\n`window.litNonce` to a server-generated nonce in your page's HTML, before\nloading application code:\n```html\n<script>\n // Generated and unique per request:\n window.litNonce = 'a1b2c3d4';\n</script>\n```\n"
17651765
},
17661766
"sources": [
@@ -3974,7 +3974,7 @@
39743974
"tag": "@nocollapse"
39753975
}
39763976
],
3977-
"shortText": "Creates a property accessor on the element prototype if one does not exist\nand stores a [`PropertyDeclaration`](/docs/api/ReactiveElement/#PropertyDeclaration) for the property with the\ngiven options. The property setter calls the property's `hasChanged`\nproperty option or uses a strict identity check to determine whether or not\nto request an update.",
3977+
"shortText": "Creates a property accessor on the element prototype if one does not exist\nand stores a [`PropertyDeclaration`](/docs/v2/api/ReactiveElement/#PropertyDeclaration) for the property with the\ngiven options. The property setter calls the property's `hasChanged`\nproperty option or uses a strict identity check to determine whether or not\nto request an update.",
39783978
"text": "This method may be overridden to customize properties; however,\nwhen doing so, it's important to call `super.createProperty` to ensure\nthe property is setup correctly. This method calls\n`getPropertyDescriptor` internally to get a descriptor to install.\nTo customize what properties do when they are get or set, override\n`getPropertyDescriptor`. To customize the options for a property,\nimplement `createProperty` like this:\n```ts\nstatic createProperty(name, options) {\n options = Object.assign(options, {myOption: true});\n super.createProperty(name, options);\n}\n```\n"
39793979
},
39803980
"sources": [
@@ -4215,7 +4215,7 @@
42154215
}
42164216
],
42174217
"shortText": "Returns the property options associated with the given property.\nThese options are defined with a `PropertyDeclaration` via the `properties`\nobject or the `@property` decorator and are registered in\n`createProperty(...)`.",
4218-
"text": "Note, this method should be considered \"final\" and not overridden. To\ncustomize the options for a given property, override\n[`createProperty`](/docs/api/ReactiveElement/#ReactiveElement.createProperty).\n"
4218+
"text": "Note, this method should be considered \"final\" and not overridden. To\ncustomize the options for a given property, override\n[`createProperty`](/docs/v2/api/ReactiveElement/#ReactiveElement.createProperty).\n"
42194219
},
42204220
"sources": [
42214221
{
@@ -4620,7 +4620,7 @@
46204620
"tag": "@nocollapse"
46214621
}
46224622
],
4623-
"shortText": "Array of styles to apply to the element. The styles should be defined\nusing the [`css`](/docs/api/styles/#css) tag function, via constructible stylesheets, or\nimported from native CSS module scripts.",
4623+
"shortText": "Array of styles to apply to the element. The styles should be defined\nusing the [`css`](/docs/v2/api/styles/#css) tag function, via constructible stylesheets, or\nimported from native CSS module scripts.",
46244624
"text": "Note on Content Security Policy:\nElement styles are implemented with `<style>` tags when the browser doesn't\nsupport adopted StyleSheets. To use such `<style>` tags with the style-src\nCSP directive, the style-src value must either include 'unsafe-inline' or\n`nonce-<base64-value>` with `<base64-value>` replaced be a server-generated\nnonce.\nTo provide a nonce to use on generated `<style>` elements, set\n`window.litNonce` to a server-generated nonce in your page's HTML, before\nloading application code:\n```html\n<script>\n // Generated and unique per request:\n window.litNonce = 'a1b2c3d4';\n</script>\n```\n"
46254625
},
46264626
"sources": [
@@ -6963,7 +6963,7 @@
69636963
"name": "css",
69646964
"comment": {
69656965
"shortText": "A template literal tag which can be used with LitElement's\n`styles` property to set element styles.",
6966-
"text": "For security reasons, only literal string values and number may be used in\nembedded expressions. To incorporate non-literal values [`unsafeCSS`](/docs/api/styles/#unsafeCSS)\nmay be used inside an expression.\n"
6966+
"text": "For security reasons, only literal string values and number may be used in\nembedded expressions. To incorporate non-literal values [`unsafeCSS`](/docs/v2/api/styles/#unsafeCSS)\nmay be used inside an expression.\n"
69676967
},
69686968
"sources": [
69696969
{
@@ -7295,7 +7295,7 @@
72957295
{
72967296
"name": "unsafeCSS",
72977297
"comment": {
7298-
"shortText": "Wrap a value for interpolation in a [`css`](/docs/api/styles/#css) tagged template literal.",
7298+
"shortText": "Wrap a value for interpolation in a [`css`](/docs/v2/api/styles/#css) tagged template literal.",
72997299
"text": "This is unsafe because untrusted CSS text can be used to phone home\nor exfiltrate data to an attacker controlled site. Take care to only use\nthis with trusted input.\n"
73007300
},
73017301
"sources": [
@@ -7723,7 +7723,7 @@
77237723
"tag": "@ExportDecoratedItems"
77247724
}
77257725
],
7726-
"shortText": "A property decorator which creates a reactive property that reflects a\ncorresponding attribute value. When a decorated property is set\nthe element will update and render. A [`PropertyDeclaration`](/docs/api/ReactiveElement/#PropertyDeclaration) may\noptionally be supplied to configure property features.",
7726+
"shortText": "A property decorator which creates a reactive property that reflects a\ncorresponding attribute value. When a decorated property is set\nthe element will update and render. A [`PropertyDeclaration`](/docs/v2/api/ReactiveElement/#PropertyDeclaration) may\noptionally be supplied to configure property features.",
77277727
"text": "This decorator should only be used for public fields. As public fields,\nproperties should be considered as primarily settable by element users,\neither via attribute or the property itself.\nGenerally, properties that are changed by the element should be private or\nprotected fields and should use the `state` decorator.\nHowever, sometimes element code does need to set a public property. This\nshould typically only be done in response to user interaction, and an event\nshould be fired informing the user; for example, a checkbox sets its\n`checked` property when clicked and fires a `changed` event. Mutating public\nproperties should typically not be done for non-primitive (object or array)\nproperties. In other cases when an element needs to manage state, a private\nproperty decorated via the `state` decorator should be used. When\nneeded, state properties can be initialized via public properties to\nfacilitate complex interactions.\n```ts\nclass MyElement {\n @property({ type: Boolean })\n clicked = false;\n}\n```\n"
77287728
},
77297729
"sources": [
@@ -8082,7 +8082,7 @@
80828082
"name": "queryAssignedElements",
80838083
"comment": {
80848084
"shortText": "A property decorator that converts a class property into a getter that\nreturns the `assignedElements` of the given `slot`. Provides a declarative\nway to use\n[`HTMLSlotElement.assignedElements`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/assignedElements).",
8085-
"text": "Can be passed an optional [`QueryAssignedElementsOptions`](/docs/api/decorators/#QueryAssignedElementsOptions) object.\nExample usage:\n```ts\nclass MyElement {\n @queryAssignedElements({ slot: 'list' })\n listItems!: Array<HTMLElement>;\n @queryAssignedElements()\n unnamedSlotEls!: Array<HTMLElement>;\n render() {\n return html`\n <slot name=\"list\"></slot>\n <slot></slot>\n `;\n }\n}\n```\nNote, the type of this property should be annotated as `Array<HTMLElement>`.\n"
8085+
"text": "Can be passed an optional [`QueryAssignedElementsOptions`](/docs/v2/api/decorators/#QueryAssignedElementsOptions) object.\nExample usage:\n```ts\nclass MyElement {\n @queryAssignedElements({ slot: 'list' })\n listItems!: Array<HTMLElement>;\n @queryAssignedElements()\n unnamedSlotEls!: Array<HTMLElement>;\n render() {\n return html`\n <slot name=\"list\"></slot>\n <slot></slot>\n `;\n }\n}\n```\nNote, the type of this property should be annotated as `Array<HTMLElement>`.\n"
80868086
},
80878087
"sources": [
80888088
{
@@ -8198,7 +8198,7 @@
81988198
"name": "queryAssignedNodes",
81998199
"comment": {
82008200
"shortText": "A property decorator that converts a class property into a getter that\nreturns the `assignedNodes` of the given `slot`.",
8201-
"text": "Can be passed an optional [`QueryAssignedNodesOptions`](/docs/api/decorators/#QueryAssignedNodesOptions) object.\nExample usage:\n```ts\nclass MyElement {\n @queryAssignedNodes({slot: 'list', flatten: true})\n listItems!: Array<Node>;\n render() {\n return html`\n <slot name=\"list\"></slot>\n `;\n }\n}\n```\nNote the type of this property should be annotated as `Array<Node>`.\n"
8201+
"text": "Can be passed an optional [`QueryAssignedNodesOptions`](/docs/v2/api/decorators/#QueryAssignedNodesOptions) object.\nExample usage:\n```ts\nclass MyElement {\n @queryAssignedNodes({slot: 'list', flatten: true})\n listItems!: Array<Node>;\n render() {\n return html`\n <slot name=\"list\"></slot>\n `;\n }\n}\n```\nNote the type of this property should be annotated as `Array<Node>`.\n"
82028202
},
82038203
"sources": [
82048204
{
@@ -8709,7 +8709,7 @@
87098709
{
87108710
"name": "QueryAssignedElementsOptions",
87118711
"comment": {
8712-
"shortText": "Options for the [`queryAssignedElements`](/docs/api/decorators/#queryAssignedElements) decorator. Extends the\noptions that can be passed into\n[HTMLSlotElement.assignedElements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/assignedElements)."
8712+
"shortText": "Options for the [`queryAssignedElements`](/docs/v2/api/decorators/#queryAssignedElements) decorator. Extends the\noptions that can be passed into\n[HTMLSlotElement.assignedElements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/assignedElements)."
87138713
},
87148714
"children": [
87158715
{
@@ -8830,7 +8830,7 @@
88308830
{
88318831
"name": "QueryAssignedNodesOptions",
88328832
"comment": {
8833-
"shortText": "Options for the [`queryAssignedNodes`](/docs/api/decorators/#queryAssignedNodes) decorator. Extends the options\nthat can be passed into [HTMLSlotElement.assignedNodes](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/assignedNodes)."
8833+
"shortText": "Options for the [`queryAssignedNodes`](/docs/v2/api/decorators/#queryAssignedNodes) decorator. Extends the options\nthat can be passed into [HTMLSlotElement.assignedNodes](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/assignedNodes)."
88348834
},
88358835
"children": [
88368836
{
@@ -28227,7 +28227,7 @@
2822728227
{
2822828228
"name": "PropertyValueMap",
2822928229
"comment": {
28230-
"shortText": "Do not use, instead prefer [`PropertyValues`](/docs/api/ReactiveElement/#PropertyValues)."
28230+
"shortText": "Do not use, instead prefer [`PropertyValues`](/docs/v2/api/ReactiveElement/#PropertyValues)."
2823128231
},
2823228232
"children": [
2823328233
{

packages/lit-dev-content/.eleventy.js

+63-3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ const DEV = ENV.eleventyMode === 'dev';
4242

4343
const cspInlineScriptHashes = new Set();
4444

45+
/**
46+
* @param {import("@11ty/eleventy/src/UserConfig")} eleventyConfig
47+
* @returns {ReturnType<import("@11ty/eleventy/src/defaultConfig")>}
48+
*/
4549
module.exports = function (eleventyConfig) {
4650
// https://github.com/JordanShurmer/eleventy-plugin-toc#readme
4751
eleventyConfig.addPlugin(pluginTOC, {
@@ -158,6 +162,48 @@ ${content}
158162
return content.replace(/<a class="anchor".*<\/a>/g, '');
159163
});
160164

165+
/**
166+
* For the latest versioned urls, this filter returns the unversioned url
167+
* which is used in the rel=canonical link.
168+
*/
169+
eleventyConfig.addFilter(
170+
'removeLatestVersionFromUrl',
171+
function (url, latestVersion) {
172+
if (!latestVersion) {
173+
throw new Error(
174+
`No latestVersion provided to 'removeLatestVersionFromUrl`
175+
);
176+
}
177+
if (!url.includes(`/${latestVersion}/`)) {
178+
throw new Error(
179+
`'${url}' does not include the latestVersion versioned path segment`
180+
);
181+
}
182+
return url.replace(`/${latestVersion}/`, '/');
183+
}
184+
);
185+
186+
/**
187+
* All docs/* content on lit.dev is versioned. So all cross links are
188+
* versioned. We automatically generate unversioned docs from the latest Lit
189+
* version. This filter fixes the cross linking such that links on unversioned
190+
* pages link to other unversioned pages.
191+
*/
192+
eleventyConfig.addFilter(
193+
'fixUnversionedCrossLinks',
194+
function (content, isUnversionedUrl, latestVersion) {
195+
if (!isUnversionedUrl) {
196+
return content;
197+
}
198+
if (!latestVersion) {
199+
throw new Error(
200+
`latestVersion not provided to 'fixUnversionedCrossLinks`
201+
);
202+
}
203+
return content.replaceAll(`/docs/${latestVersion}/`, '/docs/');
204+
}
205+
);
206+
161207
eleventyConfig.addFilter('removeExtension', function (url) {
162208
const extension = path.extname(url);
163209
return url.substring(0, url.length - extension.length);
@@ -194,7 +240,19 @@ ${content}
194240

195241
eleventyConfig.addCollection('docs-v2', function (collection) {
196242
const docs = collection
197-
.getFilteredByGlob(['site/docs/*', 'site/docs/!(v1)/**'])
243+
.getFilteredByGlob(['site/docs/v2/**'])
244+
.sort(sortDocs);
245+
for (const page of docs) {
246+
documentByUrl.set(page.url, page);
247+
}
248+
return docs;
249+
});
250+
251+
// Collection that contains the built duplicate docs for the current
252+
// recommended version of Lit.
253+
eleventyConfig.addCollection('docs-unversioned', function (collection) {
254+
const docs = collection
255+
.getFilteredByGlob(['site/docs/unversioned/**'])
198256
.sort(sortDocs);
199257
for (const page of docs) {
200258
documentByUrl.set(page.url, page);
@@ -379,7 +437,7 @@ ${content}
379437

380438
addApiShortcode(
381439
'api',
382-
'/docs/api',
440+
'/docs/v2/api',
383441
// Don't use require() because of Node caching in watch mode.
384442
JSON.parse(
385443
fsSync.readFileSync('../lit-dev-api/api-data/lit-2/symbols.json', 'utf8')
@@ -487,8 +545,10 @@ ${content}
487545
ENV.eleventyOutDir + '/docs/*/index.html',
488546
ENV.eleventyOutDir + '/docs/v1/introduction.html',
489547
ENV.eleventyOutDir + '/docs/v1/*/index.html',
548+
ENV.eleventyOutDir + '/docs/v2/introduction.html',
549+
ENV.eleventyOutDir + '/docs/v2/*/index.html',
490550
],
491-
{ignore: ENV.eleventyOutDir + '/docs/v1/index.html'}
551+
{ignore: ENV.eleventyOutDir + '/docs/(v1|v2)/index.html'}
492552
)
493553
).filter(
494554
// TODO(aomarks) This is brittle, we need a way to annotate inside an md

0 commit comments

Comments
 (0)