Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

graphql-mini-transforms

Package Overview
Dependencies
Maintainers
1
Versions
79
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

graphql-mini-transforms - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

jest-simple.js

9

CHANGELOG.md

@@ -8,2 +8,11 @@ # Changelog

## [1.2.0] - 2020-04-27
### Added
- Added a new `{simple: true}` option to the `graphql-mini-transforms/webpack` loader to produce GraphQL exports without any AST [[#114](https://github.com/Shopify/graphql-tools-web/pull/114)]
- Added a new `graphql-mini-transforms/jest-simple` transformer that produces the same shape as the webpack loader’s `simple` option [[#114](https://github.com/Shopify/graphql-tools-web/pull/114)]
## [1.1.0] - 2020-04-14
### Changed

@@ -10,0 +19,0 @@

8

lib/document.d.ts

@@ -1,5 +0,6 @@

import { DocumentNode } from 'graphql';
export declare function cleanDocument(document: DocumentNode, { removeUnused }?: {
import { DocumentNode as UntypedDocumentNode } from 'graphql';
import { DocumentNode, SimpleDocument } from 'graphql-typed';
export declare function cleanDocument(document: UntypedDocumentNode, { removeUnused }?: {
removeUnused?: boolean | undefined;
}): DocumentNode;
}): DocumentNode<any, any, any>;
export declare function extractImports(rawSource: string): {

@@ -9,1 +10,2 @@ imports: string[];

};
export declare function toSimpleDocument<Data, Variables, DeepPartial>(document: DocumentNode<Data, Variables, DeepPartial>): SimpleDocument<Data, Variables, DeepPartial>;

@@ -47,2 +47,15 @@ "use strict";

exports.extractImports = extractImports;
function toSimpleDocument(document) {
var _a, _b;
return {
id: document.id,
name: operationNameForDocument(document),
source: (_b = (_a = document.loc) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.body,
};
}
exports.toSimpleDocument = toSimpleDocument;
function operationNameForDocument(document) {
var _a, _b;
return (_b = (_a = document.definitions.find((definition) => definition.kind === 'OperationDefinition')) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.value;
}
function removeUnusedDefinitions(document) {

@@ -49,0 +62,0 @@ const usedDefinitions = new Set();

@@ -14,2 +14,3 @@ "use strict";

const graphql_1 = require("graphql");
const loader_utils_1 = require("loader-utils");
const document_1 = require("./document");

@@ -20,2 +21,3 @@ function graphQLLoader(source) {

const done = this.async();
const { simple = false } = loader_utils_1.getOptions(this);
if (done == null) {

@@ -25,4 +27,5 @@ throw new Error('@shopify/graphql-loader does not support synchronous processing');

try {
const document = yield loadDocument(source, this.context, this);
done(null, `export default ${JSON.stringify(document_1.cleanDocument(document))};`);
const document = document_1.cleanDocument(yield loadDocument(source, this.context, this));
const exported = simple ? document_1.toSimpleDocument(document) : document;
done(null, `export default JSON.parse(${JSON.stringify(JSON.stringify(exported))});`);
}

@@ -29,0 +32,0 @@ catch (error) {

{
"name": "graphql-mini-transforms",
"description": "Transformers for importing .graphql files in various build tools.",
"version": "1.1.0",
"version": "1.2.0",
"types": "lib",

@@ -34,4 +34,5 @@ "license": "MIT",

"devDependencies": {
"@types/common-tags": "1.8.0",
"common-tags": "1.8.0"
"@types/common-tags": "^1.8.0",
"@types/loader-utils": "^1.1.3",
"common-tags": "^1.8.0"
},

@@ -43,4 +44,6 @@ "dependencies": {

"fs-extra": "^9.0.0",
"graphql": ">=14.5.0 <15.0.0"
"graphql": ">=14.5.0 <15.0.0",
"graphql-typed": "^0.6.0",
"loader-utils": "^2.0.0"
}
}

@@ -62,2 +62,23 @@ # `graphql-mini-transforms`

#### Options
This loader accepts a single option, `simple`. This option changes the shape of the value exported from `.graphql` files. By default, a `graphql-typed` `DocumentNode` is exported, but when `simple` is set to `true`, a `SimpleDocument` is exported instead. This representation of GraphQL documents is smaller than a full `DocumentNode`, but generally won’t work with normalized GraphQL caches.
```js
module.exports = {
module: {
rules: [
{
test: /\.(graphql|gql)$/,
use: 'graphql-mini-transforms/webpack',
exclude: /node_modules/,
options: {simple: true},
},
],
},
};
```
If this option is set to `true`, you should also use the `jest-simple` transformer for Jest, and the `--export-format simple` flag for `graphql-typescript-definitions`.
### Jest

@@ -75,2 +96,12 @@

If you want to get the same output as the `simple` option of the webpack loader, you can instead use the `jest-simple` loader transformer:
```js
module.exports = {
transform: {
'\\.(gql|graphql)$': 'graphql-mini-transforms/jest-simple',
},
};
```
## Prior art

@@ -91,3 +122,1 @@

- [next-plugin-mini-graphql](https://www.npmjs.com/package/next-plugin-mini-graphql) - Provides [Next.js](https://nextjs.org/) support for `.graphql` files using `graphql-mini-transforms`

@@ -1,5 +0,6 @@

import { DocumentNode } from 'graphql';
export declare function cleanDocument(document: DocumentNode, { removeUnused }?: {
import { DocumentNode as UntypedDocumentNode } from 'graphql';
import { DocumentNode, SimpleDocument } from 'graphql-typed';
export declare function cleanDocument(document: UntypedDocumentNode, { removeUnused }?: {
removeUnused?: boolean | undefined;
}): DocumentNode;
}): DocumentNode<any, any, any>;
export declare function extractImports(rawSource: string): {

@@ -9,1 +10,2 @@ imports: string[];

};
export declare function toSimpleDocument<Data, Variables, DeepPartial>(document: DocumentNode<Data, Variables, DeepPartial>): SimpleDocument<Data, Variables, DeepPartial>;

@@ -47,2 +47,15 @@ "use strict";

exports.extractImports = extractImports;
function toSimpleDocument(document) {
var _a, _b;
return {
id: document.id,
name: operationNameForDocument(document),
source: (_b = (_a = document.loc) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.body,
};
}
exports.toSimpleDocument = toSimpleDocument;
function operationNameForDocument(document) {
var _a, _b;
return (_b = (_a = document.definitions.find((definition) => definition.kind === 'OperationDefinition')) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.value;
}
function removeUnusedDefinitions(document) {

@@ -49,0 +62,0 @@ const usedDefinitions = new Set();

@@ -6,9 +6,11 @@ import {createHash} from 'crypto';

parse,
DocumentNode,
DocumentNode as UntypedDocumentNode,
DefinitionNode,
SelectionSetNode,
ExecutableDefinitionNode,
OperationDefinitionNode,
SelectionNode,
Location,
} from 'graphql';
import {DocumentNode, SimpleDocument} from 'graphql-typed';

@@ -19,5 +21,5 @@ const IMPORT_REGEX = /^#import\s+['"]([^'"]*)['"];?[\s\n]*/gm;

export function cleanDocument(
document: DocumentNode,
document: UntypedDocumentNode,
{removeUnused = true} = {},
) {
): DocumentNode<any, any, any> {
if (removeUnused) {

@@ -57,3 +59,3 @@ removeUnusedDefinitions(document);

return normalizedDocument;
return normalizedDocument as any;
}

@@ -72,3 +74,20 @@

function removeUnusedDefinitions(document: DocumentNode) {
export function toSimpleDocument<Data, Variables, DeepPartial>(
document: DocumentNode<Data, Variables, DeepPartial>,
): SimpleDocument<Data, Variables, DeepPartial> {
return {
id: document.id,
name: operationNameForDocument(document),
source: document.loc?.source?.body!,
};
}
function operationNameForDocument(document: DocumentNode) {
return document.definitions.find(
(definition): definition is OperationDefinitionNode =>
definition.kind === 'OperationDefinition',
)?.name?.value;
}
function removeUnusedDefinitions(document: UntypedDocumentNode) {
const usedDefinitions = new Set<DefinitionNode>();

@@ -75,0 +94,0 @@ const dependencies = definitionDependencies(document.definitions);

@@ -14,2 +14,3 @@ "use strict";

const graphql_1 = require("graphql");
const loader_utils_1 = require("loader-utils");
const document_1 = require("./document");

@@ -20,2 +21,3 @@ function graphQLLoader(source) {

const done = this.async();
const { simple = false } = loader_utils_1.getOptions(this);
if (done == null) {

@@ -25,4 +27,5 @@ throw new Error('@shopify/graphql-loader does not support synchronous processing');

try {
const document = yield loadDocument(source, this.context, this);
done(null, `export default ${JSON.stringify(document_1.cleanDocument(document))};`);
const document = document_1.cleanDocument(yield loadDocument(source, this.context, this));
const exported = simple ? document_1.toSimpleDocument(document) : document;
done(null, `export default JSON.parse(${JSON.stringify(JSON.stringify(exported))});`);
}

@@ -29,0 +32,0 @@ catch (error) {

@@ -5,5 +5,10 @@ import {dirname} from 'path';

import {parse, DocumentNode} from 'graphql';
import {getOptions} from 'loader-utils';
import {cleanDocument, extractImports} from './document';
import {cleanDocument, extractImports, toSimpleDocument} from './document';
interface Options {
simple?: boolean;
}
export default async function graphQLLoader(

@@ -16,2 +21,3 @@ this: loader.LoaderContext,

const done = this.async();
const {simple = false} = getOptions(this) as Options;

@@ -25,4 +31,11 @@ if (done == null) {

try {
const document = await loadDocument(source, this.context, this);
done(null, `export default ${JSON.stringify(cleanDocument(document))};`);
const document = cleanDocument(
await loadDocument(source, this.context, this),
);
const exported = simple ? toSimpleDocument(document) : document;
done(
null,
`export default JSON.parse(${JSON.stringify(JSON.stringify(exported))});`,
);
} catch (error) {

@@ -29,0 +42,0 @@ done(error);

@@ -151,8 +151,39 @@ "use strict";

});
describe('simple', () => {
it('has a source property that is the minified source', () => __awaiter(void 0, void 0, void 0, function* () {
const originalSource = common_tags_1.stripIndent `
# Comments should go away
# As should extra space
query Shop ( $id : ID! , $first: Number! ) {
# Most whitespace should go too
shop ( id: $id, first: $first ) {
# Should also minify selection sets
id,
name,
}
}
`;
const expectedSource = `query Shop($id:ID!,$first:Number!){shop(id:$id,first:$first){id name __typename}}`;
expect(yield extractDocumentExport(originalSource, createLoaderContext({ query: { simple: true } }))).toHaveProperty('source', expectedSource);
}));
it('has an id property that is a sha256 hash of the query document', () => __awaiter(void 0, void 0, void 0, function* () {
const result = yield extractDocumentExport(`query Shop { shop { id } }`, createLoaderContext({ query: { simple: true } }));
expect(result).toHaveProperty('id', crypto_1.createHash('sha256').update(result.source).digest('hex'));
}));
it('has a name property that is the name of the first operation', () => __awaiter(void 0, void 0, void 0, function* () {
const result = yield extractDocumentExport(`query Shop { shop { id } }`, createLoaderContext({ query: { simple: true } }));
expect(result).toHaveProperty('name', 'Shop');
}));
it('has an undefined name when there are no named operations', () => __awaiter(void 0, void 0, void 0, function* () {
const result = yield extractDocumentExport(`query { shop { id } }`, createLoaderContext({ query: { simple: true } }));
expect(result).toHaveProperty('name', undefined);
}));
});
});
// This is a limited subset of the loader API that we actually use in our
// loader.
function createLoaderContext({ context = __dirname, readFile = () => '', resolve = (context, imported) => path.resolve(context, imported), } = {}) {
function createLoaderContext({ query = {}, context = __dirname, readFile = () => '', resolve = (context, imported) => path.resolve(context, imported), } = {}) {
return {
context,
query,
fs: {

@@ -188,3 +219,4 @@ readFile(file, withFile) {

const result = yield simulateRun(source, loader);
return JSON.parse(result.replace(/^export default /, '').replace(/;$/, ''));
// eslint-disable-next-line no-eval
return eval(result.replace(/^export default /, '').replace(/;$/, ''));
});

@@ -191,0 +223,0 @@ }

@@ -203,5 +203,62 @@ import * as path from 'path';

});
describe('simple', () => {
it('has a source property that is the minified source', async () => {
const originalSource = stripIndent`
# Comments should go away
# As should extra space
query Shop ( $id : ID! , $first: Number! ) {
# Most whitespace should go too
shop ( id: $id, first: $first ) {
# Should also minify selection sets
id,
name,
}
}
`;
const expectedSource = `query Shop($id:ID!,$first:Number!){shop(id:$id,first:$first){id name __typename}}`;
expect(
await extractDocumentExport(
originalSource,
createLoaderContext({query: {simple: true}}),
),
).toHaveProperty('source', expectedSource);
});
it('has an id property that is a sha256 hash of the query document', async () => {
const result = await extractDocumentExport(
`query Shop { shop { id } }`,
createLoaderContext({query: {simple: true}}),
);
expect(result).toHaveProperty(
'id',
createHash('sha256').update(result.source).digest('hex'),
);
});
it('has a name property that is the name of the first operation', async () => {
const result = await extractDocumentExport(
`query Shop { shop { id } }`,
createLoaderContext({query: {simple: true}}),
);
expect(result).toHaveProperty('name', 'Shop');
});
it('has an undefined name when there are no named operations', async () => {
const result = await extractDocumentExport(
`query { shop { id } }`,
createLoaderContext({query: {simple: true}}),
);
expect(result).toHaveProperty('name', undefined);
});
});
});
interface Options {
query?: any;
context?: string;

@@ -215,2 +272,3 @@ resolve?(context: string, imported: string): string | Error;

function createLoaderContext({
query = {},
context = __dirname,

@@ -222,2 +280,3 @@ readFile = () => '',

context,
query,
fs: {

@@ -263,3 +322,5 @@ readFile(

const result = await simulateRun(source, loader);
return JSON.parse(result.replace(/^export default /, '').replace(/;$/, ''));
// eslint-disable-next-line no-eval
return eval(result.replace(/^export default /, '').replace(/;$/, ''));
}

@@ -266,0 +327,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc