diff options
| author | netop://ウィビ <paul@webb.page> | 2026-04-24 12:38:19 -0700 |
|---|---|---|
| committer | netop://ウィビ <paul@webb.page> | 2026-04-24 12:38:19 -0700 |
| commit | 5edb72ac0dfa94dc6184cc694e63c35fb373f317 (patch) | |
| tree | 5674ce17896569e5c2a60dc6bd5197d74d7ac9b2 | |
| parent | 51b4f405d5080bffcd17b00c6b75d3320f9736bd (diff) | |
| download | gq-5edb72ac0dfa94dc6184cc694e63c35fb373f317.tar.gz gq-5edb72ac0dfa94dc6184cc694e63c35fb373f317.zip | |
fixes dynamic imports
| -rw-r--r-- | deno.json | 2 | ||||
| -rw-r--r-- | source/import.ts | 78 |
2 files changed, 39 insertions, 41 deletions
@@ -8,5 +8,5 @@ }, "license": "MIT", "name": "@eol/gq", - "version": "0.1.6" + "version": "0.2.0" } diff --git a/source/import.ts b/source/import.ts index a9692bf..41786b9 100644 --- a/source/import.ts +++ b/source/import.ts @@ -3,14 +3,15 @@ /*** IMPORT ------------------------------------------- ***/ -import { dirname, join } from "@std/path"; +import { dirname, resolve } from "@std/path"; /*** UTILITY ------------------------------------------ ***/ -const { cwd, readFileSync } = Deno; +const { readFileSync } = Deno; +const DYNAMIC_IMPORT_MARKER = "# DYNAMIC_IMPORTS"; const DYNAMIC_IMPORT_REGEX = /^#\s(DYNAMIC_IMPORTS)/gm; const ENCODING = "utf-8"; -const FILE_REGEX = /\w*(.graphql)/g; +const IMPORT_PATH_REGEX = /"([^"]+\.graphql)"/; const IMPORT_REGEX = /^#\s(import)\s.*(.graphql")/gm; /*** EXPORT ------------------------------------------- ***/ @@ -24,68 +25,65 @@ const IMPORT_REGEX = /^#\s(import)\s.*(.graphql")/gm; * 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. + * `.graphql` file found one level below the entry file’s directory is + * inlined at that marker. Useful for feature-folder layouts. * - * Errors are logged and an empty string is returned so boot doesn't crash. + * All paths are resolved relative to the entry file itself, so consumers are + * free to place their schema wherever they like. * - * @param path - Path to the entry `.graphql` file, relative to `Deno.cwd()`. + * Errors are logged and an empty string is returned so boot doesn’t crash. + * + * @param path - Path to the entry `.graphql` file. Absolute paths are used + * as-is; relative paths are resolved against `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); + const entryPath = resolve(String(path)); + const entryDir = dirname(entryPath); + const mainContent = decoder.decode(readFileSync(entryPath)); + const imports = mainContent.match(IMPORT_REGEX) || []; + const shouldTryDynamicallyImporting = DYNAMIC_IMPORT_REGEX.test(mainContent); + let parsedFile = mainContent; /*** `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); + for (const imp of imports) { + const matched = imp.match(IMPORT_PATH_REGEX); - if (!matchedFilename || !matchedFilename.length || matchedFilename.length < 1) - return; + if (!matched || !matched[1]) + continue; - const filename = matchedFilename[0]; - const importedFileDecoder = new TextDecoder(ENCODING); - const importedFile = Deno.readFileSync(join(dirname(String(path)), filename)); - const decodedFile = importedFileDecoder.decode(importedFile); + const importedFile = readFileSync(resolve(entryDir, matched[1])); + const decodedFile = decoder.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`. ***/ + /*** With dynamic importing, we look one level below the entry + file’s directory to find `.graphql` files and automatically + bring them in, if `# DYNAMIC_IMPORTS` exists in the entry. ***/ if (shouldTryDynamicallyImporting) { - const graphqlFiles = []; - - for await (const dirEntry of Deno.readDir(SCHEMA_DIRECTORY)) { - const { isDirectory } = dirEntry; + const graphqlFiles: string[] = []; - if (isDirectory) { - const DIR = join(SCHEMA_DIRECTORY, dirEntry.name); + for await (const dirEntry of Deno.readDir(entryDir)) { + if (!dirEntry.isDirectory) + continue; - for await (const dirEntry of Deno.readDir(DIR)) { - const { isFile } = dirEntry; + const subDir = resolve(entryDir, dirEntry.name); - if (isFile && dirEntry.name.match(FILE_REGEX)) - graphqlFiles.push(join(DIR, dirEntry.name)); - } + for await (const sub of Deno.readDir(subDir)) { + if (sub.isFile && sub.name.endsWith(".graphql")) + graphqlFiles.push(resolve(subDir, sub.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"); + const decodedFile = decoder.decode(readFileSync(file)); + const insertPosition = parsedFile.indexOf(DYNAMIC_IMPORT_MARKER); if (insertPosition !== -1) { parsedFile = |