fuse
Version:
The magical GraphQL framework
265 lines (256 loc) • 8.06 kB
JavaScript
// src/next/plugin.ts
import path2 from "path";
import { generate, CodegenContext } from "@graphql-codegen/cli";
import { existsSync as existsSync2, promises as fs2, watch as watch2 } from "fs";
import { resolve } from "path";
import { DateTimeResolver, JSONResolver } from "graphql-scalars";
// src/utils/gql-tada.ts
import { promises as fs, watch, existsSync } from "fs";
import path from "path";
import { buildSchema, introspectionFromSchema } from "graphql";
import { minifyIntrospectionQuery } from "@urql/introspection";
async function isUsingGraphQLTada(cwd) {
const [pkgJson, tsConfig] = await Promise.allSettled([
fs.readFile(path.resolve(cwd, "package.json"), "utf-8"),
fs.readFile(path.resolve(cwd, "tsconfig.json"), "utf-8")
]);
if (pkgJson.status === "rejected" || tsConfig.status === "rejected") {
return false;
}
try {
const parsed = JSON.parse(pkgJson.value);
const merged = Object.keys({
...parsed.dependencies,
...parsed.devDependencies
});
if (!merged.find((x) => x.includes("gql.tada"))) {
return false;
}
if (!merged.find((x) => x.includes("@0no-co/graphqlsp"))) {
return false;
}
} catch (e) {
return false;
}
try {
const parsed = JSON.parse(tsConfig.value);
const lspPlugin = parsed.compilerOptions.plugins.find(
(plugin) => plugin.name === "@0no-co/graphqlsp"
);
if (!lspPlugin) {
return false;
}
if (!lspPlugin.tadaOutputLocation) {
return false;
}
} catch (e) {
return tsConfig.value.includes("@0no-co/graphqlsp") && tsConfig.value.includes("tadaOutputLocation");
}
return true;
}
var tadaGqlContents = `import { initGraphQLTada } from 'gql.tada';
import type { introspection } from './introspection';
export const graphql = initGraphQLTada<{
introspection: typeof introspection;
}>();
export type { FragmentOf, ResultOf, VariablesOf } from 'gql.tada';
export type { FragmentOf as FragmentType } from 'gql.tada';
export { readFragment } from 'gql.tada';
export { readFragment as useFragment } from 'gql.tada';
`;
var preambleComments = ["/* eslint-disable */", "/* prettier-ignore */"].join("\n") + "\n";
var tsAnnotationComment = [
"/** An IntrospectionQuery representation of your schema.",
" *",
" * @remarks",
" * This is an introspection of your schema saved as a file by GraphQLSP.",
" * You may import it to create a `graphql()` tag function with `gql.tada`",
" * by importing it and passing it to `initGraphQLTada<>()`.",
" *",
" * @example",
" * ```",
" * import { initGraphQLTada } from 'gql.tada';",
" * import type { introspection } from './introspection';",
" *",
" * export const graphql = initGraphQLTada<{",
" * introspection: typeof introspection;",
" * scalars: {",
" * DateTime: string;",
" * Json: any;",
" * };",
" * }>();",
" * ```",
" */"
].join("\n");
// src/next/plugin.ts
var isRunningCodegen = false;
function nextFusePlugin(options = {}) {
return (nextConfig = {}) => {
if (process.env.NODE_ENV === "development" && !isRunningCodegen) {
isRunningCodegen = true;
isUsingGraphQLTada(process.cwd()).then((isUsing) => {
boostrapFuse(isUsing);
try {
if (isUsing) {
let exitHandler2 = function() {
try {
watcher.close();
} catch (e) {
}
};
var exitHandler = exitHandler2;
let baseDirectory = process.cwd();
const hasSrcDir = existsSync2(resolve(baseDirectory, "src"));
if (hasSrcDir) {
baseDirectory = resolve(baseDirectory, "src");
}
setTimeout(() => {
fetch(
`http://localhost:${options.port || 3e3}/api/${options.path || "fuse"}?query={__typename}`
);
}, 1e3);
const watcher = watch2(
resolve(baseDirectory, "types"),
{ recursive: true },
() => {
setTimeout(() => {
fetch(
`http://localhost:${options.port || 3e3}/api/${options.path || "fuse"}?query={__typename}`
);
}, 1e3);
}
);
process.on("exit", exitHandler2);
process.on("SIGINT", exitHandler2);
process.on("SIGUSR1", exitHandler2);
process.on("SIGUSR2", exitHandler2);
process.on("uncaughtException", exitHandler2);
} else {
setTimeout(() => {
try {
boostrapCodegen(options.port || 3e3, options.path || "fuse");
} catch (e) {
}
}, 1e3);
}
} catch (e) {
}
});
}
const newNextConfig = Object.assign({}, nextConfig, {
webpack(webpackConfig, webpackOptions) {
webpackConfig.module.rules.push({
test: [
/pages[\\/]api[\\/]fuse.ts/,
/app[\\/]api[\\/]fuse[\\/]route.ts/,
/fuse[\\/]server.ts/
],
use: [
webpackOptions.defaultLoaders.babel,
{ loader: "fuse/next/loader" }
]
});
if (typeof nextConfig.webpack === "function") {
return nextConfig.webpack(webpackConfig, webpackOptions);
}
return webpackConfig;
}
});
return newNextConfig;
};
}
async function boostrapFuse(isUsingTada) {
let baseDirectory = process.cwd();
try {
const hasSrcDir = existsSync2(resolve(baseDirectory, "src"));
if (hasSrcDir) {
baseDirectory = resolve(baseDirectory, "src");
}
if (!existsSync2(baseDirectory + "/fuse")) {
await fs2.mkdir(baseDirectory + "/fuse");
}
await Promise.allSettled(
[
fs2.writeFile(
baseDirectory + "/fuse/server.ts",
`// This is a generated file!
export * from 'fuse/next/server'
export { __internal_execute as execute } from 'fuse/next/server'
`
),
fs2.writeFile(
baseDirectory + "/fuse/client.ts",
`// This is a generated file!
export * from 'fuse/next/client'
`
),
fs2.writeFile(
baseDirectory + "/fuse/pages.ts",
`// This is a generated file!
export * from 'fuse/next/pages'
`
),
isUsingTada && fs2.writeFile(
path2.resolve(baseDirectory, "fuse/index.ts"),
`// This is a generated file!
export * from './tada'
`
),
isUsingTada && fs2.writeFile(
path2.resolve(baseDirectory, "fuse/tada.ts"),
tadaGqlContents
)
].filter(Boolean)
);
} catch (e) {
}
}
async function boostrapCodegen(port, path3) {
let baseDirectory = process.cwd();
const hasSrcDir = existsSync2(resolve(baseDirectory, "src"));
if (hasSrcDir) {
baseDirectory = resolve(baseDirectory, "src");
}
const ctx = new CodegenContext({
filepath: "codgen.yml",
config: {
ignoreNoDocuments: true,
errorsOnly: true,
noSilentErrors: true,
watch: [
baseDirectory + "/**/*.{ts,tsx}",
baseDirectory + "/types/**/*.ts",
"!./{node_modules,.next,.git}/**/*"
],
documents: [
hasSrcDir ? "./src/**/*.{ts,tsx}" : "./**/*.{ts,tsx}",
"!./{node_modules,.next,.git}/**/*"
],
schema: `http://localhost:${port}/api/${path3}`,
debug: true,
generates: {
[baseDirectory + "/fuse/"]: {
preset: "client",
config: {
scalars: {
ID: {
input: "string",
output: "string"
},
DateTime: DateTimeResolver.extensions.codegenScalarType,
JSON: JSONResolver.extensions.codegenScalarType
},
avoidOptionals: false,
enumsAsTypes: true,
nonOptionalTypename: true,
skipTypename: false
}
}
}
}
});
await generate(ctx, true);
}
export {
nextFusePlugin
};