graphql-jerky 1.0.9 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/build/lib.cjs +70 -32
- package/build/lib.mjs +73 -35
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -31,6 +31,9 @@ By default, the working directory is searched recursively for `*.graphql` files.
|
|
|
31
31
|
All of which are combined into a single schema and rendered to `schema_gen.ts`
|
|
32
32
|
in the same directory.
|
|
33
33
|
|
|
34
|
+
Jerky reads the schema files and the resolver files in the order of their
|
|
35
|
+
paths. Thus, the output is the same on all platforms and file systems.
|
|
36
|
+
|
|
34
37
|
A path to a directory or file can be passed as the first parameter to limit to
|
|
35
38
|
scope of the search.
|
|
36
39
|
|
package/build/lib.cjs
CHANGED
|
@@ -277,6 +277,30 @@ class RequiredPackages {
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Glob options that make Windows paths work as patterns. On Windows, a
|
|
282
|
+
* backslash is a path separator and not an escape character.
|
|
283
|
+
*/
|
|
284
|
+
const globOptions = {
|
|
285
|
+
windowsPathsNoEscape: path.sep === "\\",
|
|
286
|
+
};
|
|
287
|
+
/**
|
|
288
|
+
* Converts native path separators to forward slashes.
|
|
289
|
+
*
|
|
290
|
+
* Glob patterns and module specifiers must use forward slashes, even on
|
|
291
|
+
* Windows.
|
|
292
|
+
*/
|
|
293
|
+
function toPosixPath(p) {
|
|
294
|
+
return path.sep === "\\" ? p.replaceAll("\\", "/") : p;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Compares paths by code unit. The result does not change with the locale
|
|
298
|
+
* or with the order in which the file system returns entries.
|
|
299
|
+
*/
|
|
300
|
+
function comparePaths(a, b) {
|
|
301
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
302
|
+
}
|
|
303
|
+
|
|
280
304
|
function renderSymbolReference(pkgs, ref, alias) {
|
|
281
305
|
const ns = ref.module
|
|
282
306
|
? jen.jen.id(pkgs.addRequires(ref.module, ref.symbol, alias ?? ref.alias))
|
|
@@ -285,10 +309,10 @@ function renderSymbolReference(pkgs, ref, alias) {
|
|
|
285
309
|
}
|
|
286
310
|
|
|
287
311
|
function compareEntryKey([a], [b]) {
|
|
288
|
-
return a.localeCompare(b);
|
|
312
|
+
return a.localeCompare(b, "en");
|
|
289
313
|
}
|
|
290
314
|
function compareName({ name: a }, { name: b }) {
|
|
291
|
-
return a.localeCompare(b);
|
|
315
|
+
return a.localeCompare(b, "en");
|
|
292
316
|
}
|
|
293
317
|
const PRIMITIVE_TYPES = new Set(["ID", "Int", "Float", "String", "Boolean"]);
|
|
294
318
|
function isPrimitiveType(type) {
|
|
@@ -307,8 +331,9 @@ function renderImports(base, imports, aliases, extMode = "omit") {
|
|
|
307
331
|
if (mod.startsWith("file:///")) {
|
|
308
332
|
mod = node_url.fileURLToPath(mod);
|
|
309
333
|
}
|
|
310
|
-
if (
|
|
311
|
-
|
|
334
|
+
if (path.isAbsolute(mod)) {
|
|
335
|
+
// NOTE: module specifiers always use forward slashes, even on Windows.
|
|
336
|
+
mod = toPosixPath(path.relative(base, mod));
|
|
312
337
|
if (!mod.startsWith(".")) {
|
|
313
338
|
mod = `./${mod}`;
|
|
314
339
|
}
|
|
@@ -324,8 +349,8 @@ function renderImports(base, imports, aliases, extMode = "omit") {
|
|
|
324
349
|
}
|
|
325
350
|
return jen.import
|
|
326
351
|
.obj(...Array.from(symbols)
|
|
327
|
-
.sort((a, b) => a.localeCompare(b) ||
|
|
328
|
-
importAlias(a).localeCompare(importAlias(b)))
|
|
352
|
+
.sort((a, b) => a.localeCompare(b, "en") ||
|
|
353
|
+
importAlias(a).localeCompare(importAlias(b), "en"))
|
|
329
354
|
.map((symbol) => symbol in aliases
|
|
330
355
|
? jen.id(aliases[symbol]).as.id(symbol)
|
|
331
356
|
: jen.id(symbol)))
|
|
@@ -1092,9 +1117,9 @@ class GeneratorContext {
|
|
|
1092
1117
|
];
|
|
1093
1118
|
}
|
|
1094
1119
|
renderFile(outfile, renderStatements) {
|
|
1095
|
-
const base =
|
|
1120
|
+
const base = path.resolve(outfile);
|
|
1096
1121
|
const statements = renderStatements.call(this);
|
|
1097
|
-
const [localImports, externalImports] = partition(Object.entries(this._pkgs.requires), ([pkg]) =>
|
|
1122
|
+
const [localImports, externalImports] = partition(Object.entries(this._pkgs.requires), ([pkg]) => path.isAbsolute(pkg));
|
|
1098
1123
|
return format(jen
|
|
1099
1124
|
.statements(renderImports(path.dirname(base), externalImports, this._pkgs.aliases, this._extMode), renderImports(path.dirname(base), localImports, this._pkgs.aliases, this._extMode), ...statements)
|
|
1100
1125
|
.toString());
|
|
@@ -1275,23 +1300,25 @@ async function parseResolverFile(path) {
|
|
|
1275
1300
|
async function parseTypeResolvers(typeName, glob$1, ignore) {
|
|
1276
1301
|
const shouldIgnore = createMatcher(ignore);
|
|
1277
1302
|
const result = {};
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
}
|
|
1293
|
-
result[realName] = reference;
|
|
1303
|
+
// NOTE: sort the files so that the result (and the warnings) do not change
|
|
1304
|
+
// with the order in which the file system returns entries.
|
|
1305
|
+
const fullpaths = (await glob.glob(glob$1, { ...globOptions, withFileTypes: true }))
|
|
1306
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".ts"))
|
|
1307
|
+
.map((entry) => toPosixPath(entry.fullpath()))
|
|
1308
|
+
.filter((fullpath) => !shouldIgnore(fullpath))
|
|
1309
|
+
.sort(comparePaths);
|
|
1310
|
+
for (const fullpath of fullpaths) {
|
|
1311
|
+
for (const [name, reference] of Object.entries(await parseResolverFile(fullpath))) {
|
|
1312
|
+
let realName = name;
|
|
1313
|
+
if (realName === "default" &&
|
|
1314
|
+
typeof glob$1 === "string" &&
|
|
1315
|
+
toPosixPath(glob$1).endsWith("/*.ts")) {
|
|
1316
|
+
realName = path.basename(fullpath, path.extname(fullpath));
|
|
1294
1317
|
}
|
|
1318
|
+
if (realName in result) {
|
|
1319
|
+
console.warn(`WARNING: Duplicate resolver name: ${typeName ? `${typeName}.` : ""}${realName} in ${fullpath} and ${result[realName].module}`);
|
|
1320
|
+
}
|
|
1321
|
+
result[realName] = reference;
|
|
1295
1322
|
}
|
|
1296
1323
|
}
|
|
1297
1324
|
return result;
|
|
@@ -1303,8 +1330,9 @@ async function parse$2(dirpath, ignore) {
|
|
|
1303
1330
|
}
|
|
1304
1331
|
const out = {};
|
|
1305
1332
|
const shouldIgnore = createMatcher(ignore);
|
|
1306
|
-
|
|
1307
|
-
|
|
1333
|
+
const names = (await fs.readdir(dirpath)).sort(comparePaths);
|
|
1334
|
+
for (const name of names) {
|
|
1335
|
+
const file = path.posix.join(toPosixPath(dirpath), name);
|
|
1308
1336
|
const entry = await fs.stat(file);
|
|
1309
1337
|
if (entry.isDirectory()) {
|
|
1310
1338
|
out[name] = await parseTypeResolvers(name, `${file}/*.ts`, shouldIgnore);
|
|
@@ -1614,7 +1642,7 @@ function namedNodesDict(nodes = []) {
|
|
|
1614
1642
|
return Object.fromEntries(nodes.map((node) => [node.name.value, node]));
|
|
1615
1643
|
}
|
|
1616
1644
|
function sortNamedNodes(nodes) {
|
|
1617
|
-
return Array.from(nodes).sort(({ name: { value: a } }, { name: { value: b } }) => a.localeCompare(b));
|
|
1645
|
+
return Array.from(nodes).sort(({ name: { value: a } }, { name: { value: b } }) => a.localeCompare(b, "en"));
|
|
1618
1646
|
}
|
|
1619
1647
|
function isIntValueNodeEqual(a, b) {
|
|
1620
1648
|
return a.value === b.value;
|
|
@@ -1948,21 +1976,31 @@ function mergeDocumentNodes(documentNodes) {
|
|
|
1948
1976
|
};
|
|
1949
1977
|
}
|
|
1950
1978
|
|
|
1951
|
-
async function
|
|
1952
|
-
for
|
|
1979
|
+
async function collectSchemaFiles(glob$1, files) {
|
|
1980
|
+
for (const path$1 of await glob.glob(glob$1, globOptions)) {
|
|
1953
1981
|
const entry = await fs.stat(path$1);
|
|
1954
1982
|
if (entry.isFile()) {
|
|
1955
|
-
|
|
1983
|
+
files.add(toPosixPath(path$1));
|
|
1956
1984
|
}
|
|
1957
1985
|
else if (entry.isDirectory()) {
|
|
1958
|
-
|
|
1986
|
+
await collectSchemaFiles(path.posix.join(toPosixPath(path$1), "**/*.graphql"), files);
|
|
1959
1987
|
}
|
|
1960
1988
|
}
|
|
1961
1989
|
}
|
|
1990
|
+
/**
|
|
1991
|
+
* Finds the schema files and sorts them by path. The order of the files sets
|
|
1992
|
+
* the order of the merged definitions and fields, so it must not change with
|
|
1993
|
+
* the file system or the platform.
|
|
1994
|
+
*/
|
|
1995
|
+
async function findSchemaFiles(glob) {
|
|
1996
|
+
const files = new Set();
|
|
1997
|
+
await collectSchemaFiles(glob, files);
|
|
1998
|
+
return Array.from(files).sort(comparePaths);
|
|
1999
|
+
}
|
|
1962
2000
|
async function parse(glob, ignore) {
|
|
1963
2001
|
const shouldIgnore = createMatcher(ignore);
|
|
1964
2002
|
const documentNodes = [];
|
|
1965
|
-
for
|
|
2003
|
+
for (const entry of await findSchemaFiles(glob)) {
|
|
1966
2004
|
if (shouldIgnore(entry)) {
|
|
1967
2005
|
continue;
|
|
1968
2006
|
}
|
package/build/lib.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import path, { resolve, basename, extname,
|
|
1
|
+
import path, { resolve, basename, extname, posix } from 'node:path';
|
|
2
2
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
3
3
|
import { GraphQLNonNull, GraphQLList, GraphQLScalarType, GraphQLEnumType, GraphQLDirective, Kind, GraphQLObjectType, getNamedType, getNullableType, GraphQLInterfaceType, GraphQLUnionType, GraphQLInputObjectType, DirectiveLocation, specifiedDirectives, isTypeExtensionNode, GraphQLError, isTypeDefinitionNode, parse as parse$3, Source, buildASTSchema, validateSchema } from 'graphql';
|
|
4
4
|
import jen$1, { jen } from 'jennifer-js';
|
|
@@ -7,7 +7,7 @@ import partition from 'just-partition';
|
|
|
7
7
|
import pascalCase from 'just-pascal-case';
|
|
8
8
|
import fs from 'node:fs/promises';
|
|
9
9
|
import ts, { getLineAndCharacterOfPosition } from 'typescript';
|
|
10
|
-
import {
|
|
10
|
+
import { glob } from 'glob';
|
|
11
11
|
import pm from 'picomatch';
|
|
12
12
|
import zip from 'just-zip-it';
|
|
13
13
|
|
|
@@ -275,6 +275,30 @@ class RequiredPackages {
|
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Glob options that make Windows paths work as patterns. On Windows, a
|
|
280
|
+
* backslash is a path separator and not an escape character.
|
|
281
|
+
*/
|
|
282
|
+
const globOptions = {
|
|
283
|
+
windowsPathsNoEscape: path.sep === "\\",
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* Converts native path separators to forward slashes.
|
|
287
|
+
*
|
|
288
|
+
* Glob patterns and module specifiers must use forward slashes, even on
|
|
289
|
+
* Windows.
|
|
290
|
+
*/
|
|
291
|
+
function toPosixPath(p) {
|
|
292
|
+
return path.sep === "\\" ? p.replaceAll("\\", "/") : p;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Compares paths by code unit. The result does not change with the locale
|
|
296
|
+
* or with the order in which the file system returns entries.
|
|
297
|
+
*/
|
|
298
|
+
function comparePaths(a, b) {
|
|
299
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
300
|
+
}
|
|
301
|
+
|
|
278
302
|
function renderSymbolReference(pkgs, ref, alias) {
|
|
279
303
|
const ns = ref.module
|
|
280
304
|
? jen.id(pkgs.addRequires(ref.module, ref.symbol, alias ?? ref.alias))
|
|
@@ -283,10 +307,10 @@ function renderSymbolReference(pkgs, ref, alias) {
|
|
|
283
307
|
}
|
|
284
308
|
|
|
285
309
|
function compareEntryKey([a], [b]) {
|
|
286
|
-
return a.localeCompare(b);
|
|
310
|
+
return a.localeCompare(b, "en");
|
|
287
311
|
}
|
|
288
312
|
function compareName({ name: a }, { name: b }) {
|
|
289
|
-
return a.localeCompare(b);
|
|
313
|
+
return a.localeCompare(b, "en");
|
|
290
314
|
}
|
|
291
315
|
const PRIMITIVE_TYPES = new Set(["ID", "Int", "Float", "String", "Boolean"]);
|
|
292
316
|
function isPrimitiveType(type) {
|
|
@@ -305,8 +329,9 @@ function renderImports(base, imports, aliases, extMode = "omit") {
|
|
|
305
329
|
if (mod.startsWith("file:///")) {
|
|
306
330
|
mod = fileURLToPath(mod);
|
|
307
331
|
}
|
|
308
|
-
if (
|
|
309
|
-
|
|
332
|
+
if (path.isAbsolute(mod)) {
|
|
333
|
+
// NOTE: module specifiers always use forward slashes, even on Windows.
|
|
334
|
+
mod = toPosixPath(path.relative(base, mod));
|
|
310
335
|
if (!mod.startsWith(".")) {
|
|
311
336
|
mod = `./${mod}`;
|
|
312
337
|
}
|
|
@@ -322,8 +347,8 @@ function renderImports(base, imports, aliases, extMode = "omit") {
|
|
|
322
347
|
}
|
|
323
348
|
return jen$1.import
|
|
324
349
|
.obj(...Array.from(symbols)
|
|
325
|
-
.sort((a, b) => a.localeCompare(b) ||
|
|
326
|
-
importAlias(a).localeCompare(importAlias(b)))
|
|
350
|
+
.sort((a, b) => a.localeCompare(b, "en") ||
|
|
351
|
+
importAlias(a).localeCompare(importAlias(b), "en"))
|
|
327
352
|
.map((symbol) => symbol in aliases
|
|
328
353
|
? jen$1.id(aliases[symbol]).as.id(symbol)
|
|
329
354
|
: jen$1.id(symbol)))
|
|
@@ -1090,9 +1115,9 @@ class GeneratorContext {
|
|
|
1090
1115
|
];
|
|
1091
1116
|
}
|
|
1092
1117
|
renderFile(outfile, renderStatements) {
|
|
1093
|
-
const base =
|
|
1118
|
+
const base = path.resolve(outfile);
|
|
1094
1119
|
const statements = renderStatements.call(this);
|
|
1095
|
-
const [localImports, externalImports] = partition(Object.entries(this._pkgs.requires), ([pkg]) =>
|
|
1120
|
+
const [localImports, externalImports] = partition(Object.entries(this._pkgs.requires), ([pkg]) => path.isAbsolute(pkg));
|
|
1096
1121
|
return format(jen$1
|
|
1097
1122
|
.statements(renderImports(path.dirname(base), externalImports, this._pkgs.aliases, this._extMode), renderImports(path.dirname(base), localImports, this._pkgs.aliases, this._extMode), ...statements)
|
|
1098
1123
|
.toString());
|
|
@@ -1270,26 +1295,28 @@ async function parseResolverFile(path) {
|
|
|
1270
1295
|
return [];
|
|
1271
1296
|
})));
|
|
1272
1297
|
}
|
|
1273
|
-
async function parseTypeResolvers(typeName, glob, ignore) {
|
|
1298
|
+
async function parseTypeResolvers(typeName, glob$1, ignore) {
|
|
1274
1299
|
const shouldIgnore = createMatcher(ignore);
|
|
1275
1300
|
const result = {};
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
}
|
|
1291
|
-
result[realName] = reference;
|
|
1301
|
+
// NOTE: sort the files so that the result (and the warnings) do not change
|
|
1302
|
+
// with the order in which the file system returns entries.
|
|
1303
|
+
const fullpaths = (await glob(glob$1, { ...globOptions, withFileTypes: true }))
|
|
1304
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".ts"))
|
|
1305
|
+
.map((entry) => toPosixPath(entry.fullpath()))
|
|
1306
|
+
.filter((fullpath) => !shouldIgnore(fullpath))
|
|
1307
|
+
.sort(comparePaths);
|
|
1308
|
+
for (const fullpath of fullpaths) {
|
|
1309
|
+
for (const [name, reference] of Object.entries(await parseResolverFile(fullpath))) {
|
|
1310
|
+
let realName = name;
|
|
1311
|
+
if (realName === "default" &&
|
|
1312
|
+
typeof glob$1 === "string" &&
|
|
1313
|
+
toPosixPath(glob$1).endsWith("/*.ts")) {
|
|
1314
|
+
realName = basename(fullpath, extname(fullpath));
|
|
1292
1315
|
}
|
|
1316
|
+
if (realName in result) {
|
|
1317
|
+
console.warn(`WARNING: Duplicate resolver name: ${typeName ? `${typeName}.` : ""}${realName} in ${fullpath} and ${result[realName].module}`);
|
|
1318
|
+
}
|
|
1319
|
+
result[realName] = reference;
|
|
1293
1320
|
}
|
|
1294
1321
|
}
|
|
1295
1322
|
return result;
|
|
@@ -1301,8 +1328,9 @@ async function parse$2(dirpath, ignore) {
|
|
|
1301
1328
|
}
|
|
1302
1329
|
const out = {};
|
|
1303
1330
|
const shouldIgnore = createMatcher(ignore);
|
|
1304
|
-
|
|
1305
|
-
|
|
1331
|
+
const names = (await fs.readdir(dirpath)).sort(comparePaths);
|
|
1332
|
+
for (const name of names) {
|
|
1333
|
+
const file = posix.join(toPosixPath(dirpath), name);
|
|
1306
1334
|
const entry = await fs.stat(file);
|
|
1307
1335
|
if (entry.isDirectory()) {
|
|
1308
1336
|
out[name] = await parseTypeResolvers(name, `${file}/*.ts`, shouldIgnore);
|
|
@@ -1612,7 +1640,7 @@ function namedNodesDict(nodes = []) {
|
|
|
1612
1640
|
return Object.fromEntries(nodes.map((node) => [node.name.value, node]));
|
|
1613
1641
|
}
|
|
1614
1642
|
function sortNamedNodes(nodes) {
|
|
1615
|
-
return Array.from(nodes).sort(({ name: { value: a } }, { name: { value: b } }) => a.localeCompare(b));
|
|
1643
|
+
return Array.from(nodes).sort(({ name: { value: a } }, { name: { value: b } }) => a.localeCompare(b, "en"));
|
|
1616
1644
|
}
|
|
1617
1645
|
function isIntValueNodeEqual(a, b) {
|
|
1618
1646
|
return a.value === b.value;
|
|
@@ -1946,21 +1974,31 @@ function mergeDocumentNodes(documentNodes) {
|
|
|
1946
1974
|
};
|
|
1947
1975
|
}
|
|
1948
1976
|
|
|
1949
|
-
async function
|
|
1950
|
-
for
|
|
1977
|
+
async function collectSchemaFiles(glob$1, files) {
|
|
1978
|
+
for (const path of await glob(glob$1, globOptions)) {
|
|
1951
1979
|
const entry = await fs.stat(path);
|
|
1952
1980
|
if (entry.isFile()) {
|
|
1953
|
-
|
|
1981
|
+
files.add(toPosixPath(path));
|
|
1954
1982
|
}
|
|
1955
1983
|
else if (entry.isDirectory()) {
|
|
1956
|
-
|
|
1984
|
+
await collectSchemaFiles(posix.join(toPosixPath(path), "**/*.graphql"), files);
|
|
1957
1985
|
}
|
|
1958
1986
|
}
|
|
1959
1987
|
}
|
|
1988
|
+
/**
|
|
1989
|
+
* Finds the schema files and sorts them by path. The order of the files sets
|
|
1990
|
+
* the order of the merged definitions and fields, so it must not change with
|
|
1991
|
+
* the file system or the platform.
|
|
1992
|
+
*/
|
|
1993
|
+
async function findSchemaFiles(glob) {
|
|
1994
|
+
const files = new Set();
|
|
1995
|
+
await collectSchemaFiles(glob, files);
|
|
1996
|
+
return Array.from(files).sort(comparePaths);
|
|
1997
|
+
}
|
|
1960
1998
|
async function parse(glob, ignore) {
|
|
1961
1999
|
const shouldIgnore = createMatcher(ignore);
|
|
1962
2000
|
const documentNodes = [];
|
|
1963
|
-
for
|
|
2001
|
+
for (const entry of await findSchemaFiles(glob)) {
|
|
1964
2002
|
if (shouldIgnore(entry)) {
|
|
1965
2003
|
continue;
|
|
1966
2004
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphql-jerky",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Jerky is a schema-first static graphql schema lightweight code generator.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"bin":
|
|
6
|
+
"bin": {
|
|
7
|
+
"graphql-jerky": "build/bin/jerky.cjs"
|
|
8
|
+
},
|
|
7
9
|
"types": "./build/lib.d.ts",
|
|
8
10
|
"module": "./build/lib.mjs",
|
|
9
11
|
"main": "./build/lib.cjs",
|