Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions news/changelog-1.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ All changes included in 1.8:

- ([#12965](https://github.com/quarto-dev/quarto-cli/issues/12965)): Prevent automatic opening of new editor sessions when creating projects in Posit Workbench context. The `--open` flag is now ignored in this environment to avoid issues with Workbench session management.

## Extensions

- ([#12559](https://github.com/quarto-dev/quarto-cli/issues/12559)): New extension type: `brand` for distributing [brand.yml](https://posit-dev.github.io/brand-yml/) configurations with associated assets.

## Engines

- ([#13171](https://github.com/quarto-dev/quarto-cli/pull/13171/)): Provide execution information to all engines uniformly via QUARTO_EXECUTE_INFO environment variable. It points to a file on disk containing a JSON object describing the execution environment for code cells to use.
Expand Down
1 change: 1 addition & 0 deletions src/command/create/artifacts/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const kExtensionTypes: Array<string | ExtensionType> = [
{ name: "journal format", value: "journal", openfiles: ["template.qmd"] },
{ name: "custom format", value: "format", openfiles: ["template.qmd"] },
{ name: "metadata", value: "metadata", openfiles: [] },
{ name: "brand", value: "brand", openfiles: [] },
];

const kExtensionSubtypes: Record<string, string[]> = {
Expand Down
28 changes: 0 additions & 28 deletions src/command/render/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from "../../deno_ral/fs.ts";
import { dirname, isAbsolute, join, relative } from "../../deno_ral/path.ts";
import { info, warning } from "../../deno_ral/log.ts";
import { mergeProjectMetadata } from "../../config/metadata.ts";

import * as colors from "fmt/colors";

Expand Down Expand Up @@ -80,7 +79,6 @@ import { Format } from "../../config/types.ts";
import { fileExecutionEngine } from "../../execute/engine.ts";
import { projectContextForDirectory } from "../../project/project-context.ts";
import { ProjectType } from "../../project/types/types.ts";
import { Zod } from "../../resources/types/zod/schema-types.ts";

const noMutationValidations = (
projType: ProjectType,
Expand Down Expand Up @@ -242,37 +240,11 @@ const getProjectRenderScripts = async (
return { preRenderScripts, postRenderScripts };
};

const mergeExtensionMetadata = async (
context: ProjectContext,
pOptions: RenderOptions,
) => {
// this will mutate context.config.project to merge
// in any project metadata from extensions
if (context.config) {
const extensions = await pOptions.services.extension.extensions(
undefined,
context.config,
context.isSingleFile ? undefined : context.dir,
{ builtIn: false },
);
const projectMetadata = extensions.filter((extension) =>
extension.contributes.metadata?.project
).map((extension) => {
return Zod.ProjectConfig.parse(extension.contributes.metadata!.project);
});
context.config.project = mergeProjectMetadata(
context.config.project,
...projectMetadata,
);
}
};

export async function renderProject(
context: ProjectContext,
pOptions: RenderOptions,
pFiles?: string[],
): Promise<RenderResult> {
await mergeExtensionMetadata(context, pOptions);
const { preRenderScripts, postRenderScripts } = await getProjectRenderScripts(
context,
);
Expand Down
18 changes: 12 additions & 6 deletions src/extension/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@ export function projectExtensionPathResolver(
return (href: string, projectOffset: string) => {
const projectRelativeHref = relative(projectOffset, href);

if (projectRelativeHref.startsWith("_extensions/")) {
if (projectRelativeHref.startsWith("_extensions/") || projectRelativeHref.startsWith("_extensions\\")) {
const projectTargetHref = projectRelativeHref.replace(
/^_extensions\//,
`${libDir}/quarto-contrib/quarto-project/`,
/^_extensions/,
`${libDir}/quarto-contrib/quarto-project`,
);

copyResourceFile(
Expand Down Expand Up @@ -791,7 +791,7 @@ async function readExtension(
const metadata = contributes?.metadata as Record<string, unknown> | undefined;

// resolve metadata/project pre- and post-render scripts to their full path
for (const key of ["pre-render", "post-render"]) {
for (const key of ["pre-render", "post-render", "brand"]) {
for (const object of [metadata, project]) {
if (!object?.project || typeof object.project !== "object") {
continue;
Expand All @@ -808,8 +808,14 @@ async function readExtension(
[],
);
if (resolved.include.length > 0) {
(object.project as Record<string, unknown>)[key] = resolved
.include;
if (key === "brand") {
(object.project as Record<string, unknown>)[key] = relative(
join(extensionDir, "..", ".."),
resolved.include[0],
);
} else {
(object.project as Record<string, unknown>)[key] = resolved.include;
}
}
}
}
Expand Down
45 changes: 39 additions & 6 deletions src/project/project-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,32 @@ import { createTempContext } from "../core/temp.ts";

import { onCleanup } from "../core/cleanup.ts";
import { once } from "../core/once.ts";
import { Zod } from "../resources/types/zod/schema-types.ts";

const mergeExtensionMetadata = async (
context: ProjectContext,
pOptions: RenderOptions,
) => {
// this will mutate context.config.project to merge
// in any project metadata from extensions
if (context.config) {
const extensions = await pOptions.services.extension.extensions(
undefined,
context.config,
context.isSingleFile ? undefined : context.dir,
{ builtIn: false },
);
const projectMetadata = extensions.filter((extension) =>
extension.contributes.metadata?.project
).map((extension) => {
return Zod.ProjectConfig.parse(extension.contributes.metadata!.project);
});
context.config.project = mergeProjectMetadata(
context.config.project,
...projectMetadata,
);
}
};

export async function projectContext(
path: string,
Expand Down Expand Up @@ -145,6 +171,16 @@ export async function projectContext(
}
};

const returnResult = async (
context: ProjectContext,
) => {
if (renderOptions) {
await mergeExtensionMetadata(context, renderOptions);
}
onCleanup(context.cleanup);
return context;
};

while (true) {
// use the current resolver
const resolver = configResolvers[0];
Expand Down Expand Up @@ -362,8 +398,7 @@ export async function projectContext(
config: configFiles,
configResources: projectConfigResources(dir, projectConfig, type),
};
onCleanup(result.cleanup);
return result;
return await returnResult(result);
} else {
debug(`projectContext: Found Quarto project in ${dir}`);
const temp = createTempContext({
Expand Down Expand Up @@ -431,8 +466,7 @@ export async function projectContext(
config: configFiles,
configResources: projectConfigResources(dir, projectConfig),
};
onCleanup(result.cleanup);
return result;
return await returnResult(result);
}
} else {
const nextDir = dirname(dir);
Expand Down Expand Up @@ -511,8 +545,7 @@ export async function projectContext(
context.files.input = [input];
}
debug(`projectContext: Found Quarto project in ${originalDir}`);
onCleanup(context.cleanup);
return context;
return await returnResult(context);
} else {
return undefined;
}
Expand Down
12 changes: 8 additions & 4 deletions src/project/project-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,10 +560,14 @@ export async function projectResolveBrand(
let fileNames = ["_brand.yml", "_brand.yaml"].map((file) =>
join(project.dir, file)
);
const brand = project?.config?.brand as boolean | string | {
light?: string;
dark?: string;
};
const brand = (project?.config?.brand ??
project?.config?.project.brand) as
| boolean
| string
| {
light?: string;
dark?: string;
};
if (brand === false) {
project.brandCache.brand = undefined;
return project.brandCache.brand;
Expand Down
4 changes: 4 additions & 0 deletions src/resources/create/extensions/brand/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.html
*.pdf
*_files/
/.quarto/
22 changes: 22 additions & 0 deletions src/resources/create/extensions/brand/README.ejs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# <%= title %> Extension For Quarto

_TODO_: Add a short description of your extension.

## Installing

_TODO_: Replace the `<github-organization>` with your GitHub organization.

```bash
quarto add <github-organization>/<%= filesafename %>
```

This will install the extension under the `_extensions` subdirectory.
If you're using version control, you will want to check in this directory.

## Using

This extension installs a [brand.yml](https://posit-dev.github.io/brand-yml/) configuration for _your organization name_.

## Example

Here is the source code for a minimal example: [example.qmd](example.qmd).
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
title: <%= title %>
author: <%= author %>
version: <%= version %>
quarto-required: ">=<%= quartoversion %>"
contributes:
metadata:
project:
brand: brand.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# minimal brand.yml enabling dark mode
# replace with your brand colors, logos, and typography!
color:
background:
light: "#fff"
dark: "#000"
foreground:
light: "#000"
dark: "#fff"
3 changes: 3 additions & 0 deletions src/resources/create/extensions/brand/_quarto.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# currently a quarto project is required for metadata or brand extensions to work
project:
type: default
26 changes: 26 additions & 0 deletions src/resources/create/extensions/brand/example.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: your brand extension
---

# brand.yml extension

Here is some inline code: `def foo(x): return x`{.python} and `y`{.python} and `z`{.python}.

Here is [a link](https://example.com).

Here is a code block:

```{.r}
# | echo: true
fibonacci <- function(n) {
if (n <= 0) {
return(NULL)
} else if (n == 1) {
return(0)
} else if (n == 2) {
return(1)
} else {
return(fibonacci(n - 1) + fibonacci(n - 2))
}
}
```
22 changes: 14 additions & 8 deletions src/resources/editor/tools/vs-code.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20450,6 +20450,12 @@ var require_yaml_intelligence_resources = __commonJS({
description: "Additional file resources to be copied to output directory"
}
},
brand: {
schema: {
ref: "brand-path-bool-light-dark"
},
description: "Branding information to use for this document. If a string, the path to a brand file.\nIf false, don't use branding on this document. If an object, an inline brand\ndefinition, or an object with light and dark brand paths or definitions.\n"
},
preview: {
description: "Options for `quarto preview`",
schema: {
Expand Down Expand Up @@ -22493,6 +22499,9 @@ var require_yaml_intelligence_resources = __commonJS({
"Specification of a light logo",
"Specification of a dark logo",
"Any of the ways a logo can be specified: string, object, or\nlight/dark object of string or object",
"Specification of a light logo",
"Specification of a dark logo",
"Any of the ways a logo can be specified: string, object, or\nlight/dark object of string or object",
"Options for a light logo",
"Options for a dark logo",
"The brand\u2019s custom color palette and theme.",
Expand Down Expand Up @@ -23374,7 +23383,7 @@ var require_yaml_intelligence_resources = __commonJS({
},
"Control the <code>\\pagestyle{}</code> for the document.",
"The paper size for the document.",
"The brand mode to use for rendering the Typst document,\n<code>light</code> or <code>dark</code>.",
"The brand mode to use for rendering the document, <code>light</code>\nor <code>dark</code>.",
{
short: "The options for margins and text layout for this document.",
long: 'The options for margins and text layout for this document.\nSee <a href="https://wiki.contextgarden.net/Layout">ConTeXt\nLayout</a> for additional information.'
Expand Down Expand Up @@ -24669,10 +24678,7 @@ var require_yaml_intelligence_resources = __commonJS({
"Disambiguating year suffix in author-date styles (e.g.&nbsp;\u201Ca\u201D in \u201CDoe,\n1999a\u201D).",
"Manuscript configuration",
"internal-schema-hack",
"List execution engines you want to give priority when determining\nwhich engine should render a notebook. If two engines have support for a\nnotebook, the one listed earlier will be chosen. Quarto\u2019s default order\nis \u2018knitr\u2019, \u2018jupyter\u2019, \u2018markdown\u2019, \u2018julia\u2019.",
"Any of the ways a logo can be specified: string, object, or\nlight/dark object of string or object",
"Specification of a light logo",
"Specification of a dark logo"
"List execution engines you want to give priority when determining\nwhich engine should render a notebook. If two engines have support for a\nnotebook, the one listed earlier will be chosen. Quarto\u2019s default order\nis \u2018knitr\u2019, \u2018jupyter\u2019, \u2018markdown\u2019, \u2018julia\u2019."
],
"schema/external-schemas.yml": [
{
Expand Down Expand Up @@ -24901,12 +24907,12 @@ var require_yaml_intelligence_resources = __commonJS({
mermaid: "%%"
},
"handlers/mermaid/schema.yml": {
_internalId: 197480,
_internalId: 197505,
type: "object",
description: "be an object",
properties: {
"mermaid-format": {
_internalId: 197472,
_internalId: 197497,
type: "enum",
enum: [
"png",
Expand All @@ -24922,7 +24928,7 @@ var require_yaml_intelligence_resources = __commonJS({
exhaustiveCompletions: true
},
theme: {
_internalId: 197479,
_internalId: 197504,
type: "anyOf",
anyOf: [
{
Expand Down

Large diffs are not rendered by default.

Loading
Loading