diff options
| author | netop://ウィビ <paul@webb.page> | 2026-04-24 07:43:33 -0700 |
|---|---|---|
| committer | netop://ウィビ <paul@webb.page> | 2026-04-24 07:43:33 -0700 |
| commit | 4c6194c4c2b5506f6d482347b0c13033ef17b5c7 (patch) | |
| tree | 310b315b23487b9a44da94cd21a970f6cc95c831 /source/import.ts | |
| download | gq-4c6194c4c2b5506f6d482347b0c13033ef17b5c7.tar.gz gq-4c6194c4c2b5506f6d482347b0c13033ef17b5c7.zip | |
initial commit
Diffstat (limited to 'source/import.ts')
| -rw-r--r-- | source/import.ts | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/source/import.ts b/source/import.ts new file mode 100644 index 0000000..a9692bf --- /dev/null +++ b/source/import.ts @@ -0,0 +1,104 @@ + + + +/*** IMPORT ------------------------------------------- ***/ + +import { dirname, join } from "@std/path"; + +/*** UTILITY ------------------------------------------ ***/ + +const { cwd, readFileSync } = Deno; +const DYNAMIC_IMPORT_REGEX = /^#\s(DYNAMIC_IMPORTS)/gm; +const ENCODING = "utf-8"; +const FILE_REGEX = /\w*(.graphql)/g; +const IMPORT_REGEX = /^#\s(import)\s.*(.graphql")/gm; + +/*** EXPORT ------------------------------------------- ***/ + +/** + * Reads a `.graphql` file and resolves its imports into a single SDL string. + * + * Two mechanisms are supported, and both can appear in the same file: + * + * 1. **Explicit imports** — lines like `# import "./user.graphql"` are replaced + * inline with the contents of the referenced file, resolved relative to the + * entry file. + * 2. **Dynamic imports** — if the file contains `# DYNAMIC_IMPORTS`, every + * `.graphql` file found one level below `<cwd>/schema/` is inlined at that + * marker. Useful for feature-folder layouts. + * + * Errors are logged and an empty string is returned so boot doesn't crash. + * + * @param path - Path to the entry `.graphql` file, relative to `Deno.cwd()`. + * @returns The fully-expanded schema string. + */ +export async function importQL(path: string): Promise<string> { + const SCHEMA_DIRECTORY = join(cwd(), "schema"); + + try { + const decoder = new TextDecoder(ENCODING); + const file = readFileSync(join(cwd(), String(path))); + const imports = decoder.decode(file).match(IMPORT_REGEX) || []; + const shouldTryDynamicallyImporting = decoder.decode(file).match(DYNAMIC_IMPORT_REGEX) ? true : false; + let parsedFile = decoder.decode(file); + + /*** `import` statements in the supplied schema file + are parsed to dynamically bring in linked files. ***/ + + imports.map((imp: string) => { + const matchedFilename: null | Array<string> = imp.match(FILE_REGEX); + + if (!matchedFilename || !matchedFilename.length || matchedFilename.length < 1) + return; + + const filename = matchedFilename[0]; + const importedFileDecoder = new TextDecoder(ENCODING); + const importedFile = Deno.readFileSync(join(dirname(String(path)), filename)); + const decodedFile = importedFileDecoder.decode(importedFile); + + parsedFile = parsedFile.replace(imp, decodedFile); + }); + + /*** With dynamic importing, we just look inside the `program` + directory to find `.graphql` files and automatically bring + them in, if `# DYNAMIC_IMPORTS` exists in `schema.graphql`. ***/ + + if (shouldTryDynamicallyImporting) { + const graphqlFiles = []; + + for await (const dirEntry of Deno.readDir(SCHEMA_DIRECTORY)) { + const { isDirectory } = dirEntry; + + if (isDirectory) { + const DIR = join(SCHEMA_DIRECTORY, dirEntry.name); + + for await (const dirEntry of Deno.readDir(DIR)) { + const { isFile } = dirEntry; + + if (isFile && dirEntry.name.match(FILE_REGEX)) + graphqlFiles.push(join(DIR, dirEntry.name)); + } + } + } + + for (const file of graphqlFiles) { + const importedFileDecoder = new TextDecoder(ENCODING); + const importedFile = Deno.readFileSync(file); + const decodedFile = importedFileDecoder.decode(importedFile); + const insertPosition = parsedFile.indexOf("# DYNAMIC_IMPORTS"); + + if (insertPosition !== -1) { + parsedFile = + parsedFile.substring(0, insertPosition) + + decodedFile + + parsedFile.substring(insertPosition); + } + } + } + + return parsedFile; + } catch(parseError) { + console.error(new Error(`error parsing file [${String(path)}]`), parseError); + return ""; + } +} |