Path: blob/main/package/src/common/prepare-dist.ts
12925 views
/*1* prepare-dist.ts2*3* Copyright (C) 2020-2022 Posit Software, PBC4*5*/67import { dirname, join } from "../../../src/deno_ral/path.ts";8import { copySync, ensureDirSync, existsSync } from "../../../src/deno_ral/fs.ts";910import { Configuration } from "../common/config.ts";11import { buildFilter } from "./package-filters.ts";12import { bundle } from "../util/deno.ts";13import { info } from "../../../src/deno_ral/log.ts";14import { buildAssets } from "../../../src/command/dev-call/build-artifacts/cmd.ts";15import { initTreeSitter } from "../../../src/core/schema/deno-init-tree-sitter.ts";16import {17Dependency,18configureDependency,19kDependencies,20} from "./dependencies/dependencies.ts";21import { copyQuartoScript } from "./configure.ts";22import { deno } from "./dependencies/deno.ts";23import { buildQuartoPreviewJs } from "./previewjs.ts";2425export async function prepareDist(26config: Configuration,27) {28// run esbuild29// copy from resources dir to the 'share' dir (which is resources)30// config.directoryInfo.share3132// Moving appropriate binaries into place3334// Get each dependency extracted into the 'bin' folder35// Download dependencies3637// Ensure that the pkgWorkingDir is clean38if (existsSync(config.directoryInfo.pkgWorking.root)) {39Deno.removeSync(config.directoryInfo.pkgWorking.root, { recursive: true });40}4142// Ensure that the working directory exists43ensureDirSync(config.directoryInfo.pkgWorking.bin);44ensureDirSync(config.directoryInfo.pkgWorking.share);45const toolsDir = join(46config.directoryInfo.pkgWorking.bin,47"tools",48);49ensureDirSync(toolsDir);5051// binary tools dir52const targetDir = join(53config.directoryInfo.pkgWorking.bin,54"tools",55);5657// Function to wrap architecture specific configuration58const configArchDependency = async (dep: Dependency,59dir: string,60config: Configuration) => {61if (config.os === "darwin") {62// add a secondary config specifically for Mac63await configureDependency(dep, dir, {64os: config.os,65arch: "aarch64",66});6768await configureDependency(dep, dir, {69os: config.os,70arch: "x86_64",71});72} else {73await configureDependency(dep, targetDir, config);74}75}7677// Download Deno78const denoVersion = Deno.env.get("DENO");79if (denoVersion) {80const denoDependency = deno(denoVersion);81await configArchDependency(denoDependency, targetDir, config)82}8384// Download the dependencies85for (const dependency of kDependencies) {86try {87await configArchDependency(dependency, targetDir, config)88} catch (e) {89if (!(e instanceof Error)) { throw e; }90if (91e.message ===92"The architecture aarch64 is missing the dependency deno_dom"93) {94info("\nIgnoring deno_dom dependency on Apple Silicon");95continue;96} else {97throw e;98}99}100}101102// build quarto-preview.js103info("Building Quarto Web UI");104const result = buildQuartoPreviewJs(config.directoryInfo.src, undefined, true);105if (!result.success) {106throw new Error();107}108109110// Place the quarto sciprt111// Move the quarto script into place112info("Moving Quarto script");113copyQuartoScript(config, config.directoryInfo.pkgWorking.bin);114115// Move the supporting files into place116info("\nMoving supporting files");117supportingFiles(config);118info("");119120// Update extension-build import map for distribution121info("Updating extension-build import map");122updateImportMap(config);123info("");124125// Create the deno bundle126// const input = join(config.directoryInfo.src, "quarto.ts");127const output = join(config.directoryInfo.pkgWorking.bin, "quarto.js");128info("\nCreating Deno Bundle");129info(output);130await bundle(131config,132);133info("");134135// Inline the LUA Filters and move them into place136info("\nCreating Inlined LUA Filters");137inlineFilters(config);138info("");139140// Write a version file to share141info(`Writing version: ${config.version}`);142Deno.writeTextFileSync(143join(config.directoryInfo.pkgWorking.share, "version"),144config.version,145);146info("");147148info("\nBuilding JS assets");149await initTreeSitter();150await buildAssets();151const buildAssetFiles = [152"formats/html/ojs/quarto-ojs-runtime.js",153"editor/tools/yaml/yaml-intelligence-resources.json",154"editor/tools/yaml/web-worker.js",155"editor/tools/yaml/yaml.js",156];157for (const file of buildAssetFiles) {158copySync(159join(config.directoryInfo.src, "resources", file),160join(config.directoryInfo.pkgWorking.share, file),161{ overwrite: true },162);163}164165// Copy quarto-types to extension-build directory166// Note: deno.json and import-map.json are copied by supportingFiles() and167// import-map.json is then updated by updateImportMap() for distribution168info("Copying quarto-types.d.ts to extension-build directory");169const extensionBuildDir = join(170config.directoryInfo.pkgWorking.share,171"extension-build",172);173copySync(174join(config.directoryInfo.root, "packages/quarto-types/dist/index.d.ts"),175join(extensionBuildDir, "quarto-types.d.ts"),176{ overwrite: true },177);178179// Remove the config directory, if present180info(`Cleaning config`);181const configDir = join(config.directoryInfo.dist, "config");182info(configDir);183if (existsSync(configDir)) {184Deno.removeSync(configDir, { recursive: true });185}186187info("");188}189190function supportingFiles(config: Configuration) {191// Move information and share resources into place192const filesToCopy = [193{194from: join(config.directoryInfo.root, "COPYING.md"),195to: join(config.directoryInfo.pkgWorking.share, "COPYING.md"),196},197{198from: join(config.directoryInfo.root, "COPYRIGHT"),199to: join(config.directoryInfo.pkgWorking.share, "COPYRIGHT"),200},201{202from: join(config.directoryInfo.src, "resources"),203to: config.directoryInfo.pkgWorking.share,204},205];206207// Gather supporting files208filesToCopy.forEach((fileToCopy) => {209const dir = dirname(fileToCopy.to);210info(`Ensuring dir ${dir} exists`);211ensureDirSync(dir);212213info(`Copying ${fileToCopy.from} to ${fileToCopy.to}`);214copySync(fileToCopy.from, fileToCopy.to, { overwrite: true });215});216217// Cleanup the filters directory, which contains filter source that will be218// compiled later219const pathsToClean = [220join(config.directoryInfo.pkgWorking.share, "filters"),221];222pathsToClean.forEach((path) => Deno.removeSync(path, { recursive: true }));223}224225function updateImportMap(config: Configuration) {226// Read the import map that was copied from src/resources/extension-build/227const importMapPath = join(228config.directoryInfo.pkgWorking.share,229"extension-build",230"import-map.json",231);232const importMapContent = JSON.parse(Deno.readTextFileSync(importMapPath));233234// Read the source import map to get current Deno std versions235const sourceImportMapPath = join(config.directoryInfo.src, "import_map.json");236const sourceImportMap = JSON.parse(Deno.readTextFileSync(sourceImportMapPath));237const sourceImports = sourceImportMap.imports as Record<string, string>;238239// Update the import map for distribution:240// 1. Change @quarto/types path from dev (../../../packages/...) to dist (./quarto-types.d.ts)241// 2. Update all other imports (Deno std versions) from source import map242const updatedImports: Record<string, string> = {243"@quarto/types": "./quarto-types.d.ts",244};245246// Copy all other imports from source, updating versions247for (const key in importMapContent.imports) {248if (key !== "@quarto/types") {249const sourceValue = sourceImports[key];250if (!sourceValue) {251throw new Error(252`Import map key "${key}" not found in source import_map.json`,253);254}255updatedImports[key] = sourceValue;256}257}258259importMapContent.imports = updatedImports;260261// Write back the updated import map262Deno.writeTextFileSync(263importMapPath,264JSON.stringify(importMapContent, null, 2) + "\n",265);266}267268interface Filter {269// The name of the filter (the LUA file and perhaps the directory)270name: string;271272// An optional name of the directory, if it is not the name of the LUA filter273dir?: string;274}275276function inlineFilters(config: Configuration) {277info("Building inlined filters");278const outDir = join(config.directoryInfo.pkgWorking.share, "filters");279const filtersToInline: Filter[] = [280{ name: "main", dir: "." },281{ name: "pagebreak", dir: "rmarkdown" },282{ name: "quarto-init" },283{ name: "crossref" },284{ name: "customwriter" },285{ name: "qmd-reader", dir: "." },286{ name: "llms", dir: "llms" },287{ name: "leveloneanalysis", dir: "quarto-internals"}288];289290filtersToInline.forEach((filter) => {291info(filter);292buildFilter(293join(294config.directoryInfo.src,295"resources",296"filters",297filter.dir || filter.name,298`${filter.name}.lua`,299),300join(outDir, filter.dir || filter.name, `${filter.name}.lua`),301);302});303304const modules = "modules";305const modulesIn = join(306config.directoryInfo.src,307"resources",308"filters", modules);309const modulesOut = join(outDir, modules);310311// move the modules directory312copySync(modulesIn, modulesOut)313314315}316317318