Path: blob/main/src/core/handlers/include-standalone.ts
3583 views
/*1* include-standalone.ts2*3* Copyright (C) 2023 Posit Software, PBC4*/56import { IncludeState, LanguageCellHandlerContext } from "./types.ts";78import {9asMappedString,10EitherString,11mappedConcat,12MappedString,13mappedString,14} from "../lib/mapped-text.ts";1516import { rangedLines } from "../lib/ranged-text.ts";17import { isBlockShortcode } from "../lib/parse-shortcode.ts";1819export const standaloneInclude = async (20handlerContext: LanguageCellHandlerContext,21filename: string,22): Promise<MappedString> => {23const source = handlerContext.options.context.target.source;24const retrievedFiles: string[] = [source];2526const textFragments: EitherString[] = [];27if (!handlerContext.options.state) {28handlerContext.options.state = {};29}30if (!handlerContext.options.state.include) {31handlerContext.options.state.include = {32includes: [],33};34}35const includeState = handlerContext.options.state.include as IncludeState;3637const retrieveInclude = async (filename: string) => {38const path = handlerContext.resolvePath(filename);3940if (retrievedFiles.indexOf(path) !== -1) {41throw new Error(42`Include directive found circular include of file ${filename}.`,43);44}4546let includeSrc;47try {48includeSrc = asMappedString(49Deno.readTextFileSync(path),50path,51);52} catch (_e) {53const errMsg: string[] = [`Include directive failed.`];54errMsg.push(...retrievedFiles.map((s) => ` in file ${s}, `));55errMsg.push(56` could not find file ${path57// relative(handlerContext.options.context.target.source, path)58}.`,59);60throw new Error(errMsg.join("\n"));61}6263retrievedFiles.push(filename);6465let rangeStart = 0;66for (const { substring, range } of rangedLines(includeSrc.value)) {67const m = isBlockShortcode(substring);68if (m && m.name.toLocaleLowerCase() === "include") {69textFragments.push(70mappedString(includeSrc, [{71start: rangeStart,72end: range.start,73}]),74);75rangeStart = range.end;76const params = m.params;77if (params.length === 0) {78throw new Error("Include directive needs file parameter");79}8081includeState.includes.push({ source: filename, target: params[0] });82await retrieveInclude(params[0]);83}84}85if (rangeStart !== includeSrc.value.length) {86textFragments.push(87mappedString(includeSrc, [{88start: rangeStart,89end: includeSrc.value.length,90}]),91);92}93textFragments.push(includeSrc.value.endsWith("\n") ? "\n" : "\n\n");9495retrievedFiles.pop();96};9798await retrieveInclude(filename);99100return Promise.resolve(mappedConcat(textFragments));101};102103104