@shopify/theme-check-common
Advanced tools
Comparing version 2.4.0 to 2.5.0
# @shopify/theme-check-common | ||
## 2.5.0 | ||
### Minor Changes | ||
- 03b41e1: Breaking: `jsonValidationSet`'s schemas public API change | ||
Now takes a function of the following signature: | ||
```ts | ||
interface JsonValidationSet = { | ||
schemas: (context: 'theme' | 'app') => Promise<SchemaDefinition[]> | ||
} | ||
``` | ||
Reason being we want to support `fileMatch` overloading of `blocks/*.liquid` files and we needed a way to identify which context you're in. | ||
Unfortunately, the JSON schema for `blocks/*.liquid` files in theme app extensions isn't the same one we have in themes. There doesn't seem to be a way to unify them either. | ||
- 03b41e1: Theme Check Config files now accept the `context` property | ||
In your `.theme-check.yml` files, you can set the `context` property to `theme` or `app`. By default, it's `theme`. The `theme-check:theme-app-extension` config sets it to `app`. | ||
You shouldn't need to care about this. It's there so we can do contextual things internally. | ||
- 03b41e1: Add support for the schemas manifest on Shopify/theme-liquid-docs | ||
Shopify/theme-liquid-docs now supports composable JSON schemas (with relative paths). To solve the `blocks/*.liquid` file match JSON schema overload depending on the context (`app` or `theme`), we defined two manifests that describe the schemas required by your solution and define the fileMatch rules: | ||
- [manifest_theme.json](https://github.com/Shopify/theme-liquid-docs/blob/main/schemas/manifest_theme.json) | ||
- [manifest_theme_app_extension.json](https://github.com/Shopify/theme-liquid-docs/blob/main/schemas/manifest_theme.json) | ||
`@shopify/theme-check-docs-updater` now reads those manifests and downloads the tree of dependency that they require. We will no longer need to make new theme-tools releases whenever we add new schemas. We'll be able to dev them and their file associations directly from Shopify/theme-liquid-docs and have downstream consumers updated automatically (the same way docs are automatically updated). | ||
## 2.4.0 | ||
@@ -4,0 +37,0 @@ |
@@ -62,3 +62,3 @@ "use strict"; | ||
if (dependencies.jsonValidationSet) { | ||
const jsonValidator = new JSONValidator_1.JSONValidator(dependencies.jsonValidationSet); | ||
const jsonValidator = new JSONValidator_1.JSONValidator(await dependencies.jsonValidationSet.schemas(config.context)); | ||
validateJSON = jsonValidator.validate.bind(jsonValidator); | ||
@@ -65,0 +65,0 @@ } |
@@ -1,7 +0,6 @@ | ||
import { JsonValidationSet, SourceCodeType, ValidateJSON } from './types'; | ||
import { SchemaDefinition, SourceCodeType, ValidateJSON } from './types'; | ||
export declare class JSONValidator { | ||
private jsonValidationSet; | ||
private service; | ||
private schemas; | ||
constructor(jsonValidationSet: JsonValidationSet); | ||
constructor(schemas: SchemaDefinition[]); | ||
/** | ||
@@ -8,0 +7,0 @@ * Will return an array of diagnostics for the given source code and JSON string. |
@@ -7,4 +7,3 @@ "use strict"; | ||
class JSONValidator { | ||
constructor(jsonValidationSet) { | ||
this.jsonValidationSet = jsonValidationSet; | ||
constructor(schemas) { | ||
/** | ||
@@ -30,9 +29,14 @@ * Will return an array of diagnostics for the given source code and JSON string. | ||
}; | ||
this.jsonValidationSet = jsonValidationSet; | ||
this.schemas = (0, utils_1.indexBy)((x) => x.uri, this.jsonValidationSet.schemas); | ||
this.schemas = (0, utils_1.indexBy)((x) => x.uri, schemas); | ||
this.service = (0, vscode_json_languageservice_1.getLanguageService)({ | ||
schemaRequestService: this.getSchemaForURI.bind(this), | ||
workspaceContext: { | ||
resolveRelativePath: (relativePath, resource) => { | ||
const url = new URL(relativePath, resource); | ||
return url.toString(); | ||
}, | ||
}, | ||
}); | ||
this.service.configure({ | ||
schemas: this.jsonValidationSet.schemas.map((schemaDefinition) => ({ | ||
schemas: schemas.map((schemaDefinition) => ({ | ||
uri: schemaDefinition.uri, | ||
@@ -45,6 +49,6 @@ fileMatch: schemaDefinition.fileMatch, | ||
var _a; | ||
const promise = (_a = this.schemas[uri]) === null || _a === void 0 ? void 0 : _a.schema; | ||
if (!promise) | ||
const schema = (_a = this.schemas[uri]) === null || _a === void 0 ? void 0 : _a.schema; | ||
if (!schema) | ||
return `No schema for '${uri}' found`; | ||
return promise; | ||
return schema; | ||
} | ||
@@ -51,0 +55,0 @@ } |
@@ -11,2 +11,4 @@ import { NodeTypes as LiquidHtmlNodeTypes, LiquidHtmlNode } from '@shopify/liquid-html-parser'; | ||
export declare const isPropertyNode: (node?: ASTNode) => node is PropertyNode; | ||
export declare const Modes: readonly ["theme", "app"]; | ||
export type Mode = (typeof Modes)[number]; | ||
export type Theme = SourceCode<SourceCodeType>[]; | ||
@@ -66,2 +68,3 @@ export type SourceCode<T = SourceCodeType> = T extends SourceCodeType ? { | ||
export interface Config { | ||
context: Mode; | ||
settings: ChecksSettings; | ||
@@ -68,0 +71,0 @@ checks: CheckDefinition<SourceCodeType, Schema>[]; |
@@ -17,3 +17,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ConfigTarget = exports.Severity = exports.LiquidHtmlNodeTypes = exports.SourceCodeType = exports.isPropertyNode = exports.isArrayNode = exports.isObjectNode = void 0; | ||
exports.ConfigTarget = exports.Severity = exports.LiquidHtmlNodeTypes = exports.SourceCodeType = exports.Modes = exports.isPropertyNode = exports.isArrayNode = exports.isObjectNode = void 0; | ||
const liquid_html_parser_1 = require("@shopify/liquid-html-parser"); | ||
@@ -29,2 +29,3 @@ Object.defineProperty(exports, "LiquidHtmlNodeTypes", { enumerable: true, get: function () { return liquid_html_parser_1.NodeTypes; } }); | ||
exports.isPropertyNode = isPropertyNode; | ||
exports.Modes = ['theme', 'app']; | ||
var SourceCodeType; | ||
@@ -31,0 +32,0 @@ (function (SourceCodeType) { |
@@ -1,2 +0,2 @@ | ||
import { Translations } from '..'; | ||
import { Mode, Translations } from '..'; | ||
/** | ||
@@ -22,4 +22,4 @@ * Shopify themes docset. | ||
uri: JSONSchemaURI; | ||
/** A promise that returns a JSON Schema as string */ | ||
schema: Promise<string>; | ||
/** A JSON Schema as string */ | ||
schema: string; | ||
/** | ||
@@ -36,3 +36,3 @@ * When absent, does not match on file. Assumed to be used by other | ||
/** All relevant SchemaDefinitions. */ | ||
schemas: SchemaDefinition[]; | ||
schemas: (mode: Mode) => Promise<SchemaDefinition[]>; | ||
} | ||
@@ -39,0 +39,0 @@ export interface DocsetEntry { |
@@ -29,2 +29,2 @@ import { ArgumentTypes } from './types'; | ||
*/ | ||
export declare function memoize<AT, RT, F extends (arg: AT) => RT>(fn: F, keyFn: (arg: AT) => string): (arg: AT) => RT; | ||
export declare function memoize<AT, F extends (arg: AT) => any, RT extends ReturnType<F>>(fn: F, keyFn: (arg: AT) => string): (arg: AT) => RT; |
{ | ||
"name": "@shopify/theme-check-common", | ||
"version": "2.4.0", | ||
"version": "2.5.0", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -13,3 +13,3 @@ import { expect, describe, it } from 'vitest'; | ||
const offenses = await runJSONCheck(ValidJSON, invalidJson, 'file.json', { | ||
jsonValidationSet: { schemas: [] }, | ||
jsonValidationSet: { schemas: async () => [] }, | ||
}); | ||
@@ -32,3 +32,3 @@ | ||
const offenses = await runJSONCheck(ValidJSON, invalidJson, 'file.json', { | ||
jsonValidationSet: { schemas: [] }, | ||
jsonValidationSet: { schemas: async () => [] }, | ||
}); | ||
@@ -50,3 +50,3 @@ expect(offenses).to.have.length(1); | ||
const offenses = await runJSONCheck(ValidJSON, invalidJson, 'file.json', { | ||
jsonValidationSet: { schemas: [] }, | ||
jsonValidationSet: { schemas: async () => [] }, | ||
}); | ||
@@ -78,6 +78,6 @@ expect(offenses).to.have.length(1); | ||
jsonValidationSet: { | ||
schemas: [ | ||
schemas: async () => [ | ||
{ | ||
uri: 'https://shopify.dev/some-schema.json', | ||
schema: Promise.resolve(basicJsonSchema), | ||
schema: basicJsonSchema, | ||
fileMatch: ['file.json'], | ||
@@ -84,0 +84,0 @@ }, |
@@ -41,6 +41,6 @@ import lodashSet from 'lodash/set'; | ||
jsonValidationSet: { | ||
schemas: [ | ||
schemas: async () => [ | ||
{ | ||
uri: 'https://shopify.dev/some-schema.json', | ||
schema: Promise.resolve(JSON.stringify(MockSectionSchemaJsonSchema)), | ||
schema: JSON.stringify(MockSectionSchemaJsonSchema), | ||
fileMatch: ['**/sections/*.liquid'], | ||
@@ -47,0 +47,0 @@ }, |
@@ -191,2 +191,3 @@ import { expect, describe, it } from 'vitest'; | ||
return { | ||
context: 'theme', | ||
settings: { | ||
@@ -193,0 +194,0 @@ MockCheck: { |
@@ -63,3 +63,5 @@ import { | ||
if (dependencies.jsonValidationSet) { | ||
const jsonValidator = new JSONValidator(dependencies.jsonValidationSet); | ||
const jsonValidator = new JSONValidator( | ||
await dependencies.jsonValidationSet.schemas(config.context), | ||
); | ||
validateJSON = jsonValidator.validate.bind(jsonValidator); | ||
@@ -66,0 +68,0 @@ } |
import { LanguageService, TextDocument, getLanguageService } from 'vscode-json-languageservice'; | ||
import { JsonValidationSet, SchemaDefinition, SourceCodeType, ValidateJSON } from './types'; | ||
import { SchemaDefinition, SourceCodeType, ValidateJSON } from './types'; | ||
import { indexBy } from './utils'; | ||
@@ -9,10 +9,15 @@ | ||
constructor(private jsonValidationSet: JsonValidationSet) { | ||
this.jsonValidationSet = jsonValidationSet; | ||
this.schemas = indexBy((x) => x.uri, this.jsonValidationSet.schemas); | ||
constructor(schemas: SchemaDefinition[]) { | ||
this.schemas = indexBy((x) => x.uri, schemas); | ||
this.service = getLanguageService({ | ||
schemaRequestService: this.getSchemaForURI.bind(this), | ||
workspaceContext: { | ||
resolveRelativePath: (relativePath, resource) => { | ||
const url = new URL(relativePath, resource); | ||
return url.toString(); | ||
}, | ||
}, | ||
}); | ||
this.service.configure({ | ||
schemas: this.jsonValidationSet.schemas.map((schemaDefinition) => ({ | ||
schemas: schemas.map((schemaDefinition) => ({ | ||
uri: schemaDefinition.uri, | ||
@@ -51,6 +56,6 @@ fileMatch: schemaDefinition.fileMatch, | ||
private async getSchemaForURI(uri: string): Promise<string> { | ||
const promise = this.schemas[uri]?.schema; | ||
if (!promise) return `No schema for '${uri}' found`; | ||
return promise; | ||
const schema = this.schemas[uri]?.schema; | ||
if (!schema) return `No schema for '${uri}' found`; | ||
return schema; | ||
} | ||
} |
@@ -56,2 +56,3 @@ import { | ||
const config: Config = { | ||
context: 'theme', | ||
settings: { ...checkSettings }, | ||
@@ -58,0 +59,0 @@ checks: checks, |
@@ -24,2 +24,4 @@ import { NodeTypes as LiquidHtmlNodeTypes, LiquidHtmlNode } from '@shopify/liquid-html-parser'; | ||
export const Modes = ['theme', 'app'] as const; | ||
export type Mode = (typeof Modes)[number]; | ||
export type Theme = SourceCode<SourceCodeType>[]; | ||
@@ -102,2 +104,8 @@ | ||
export interface Config { | ||
// I know, it's `context` in the config and `Mode` in the code... | ||
// We already have something named "Context" internally when you're writing a check. | ||
// I don't like "Mode" as a public API in the configs. Context sounds more Shopify-y. | ||
// So we have `context: theme` and `context: app` as valid .theme-check.yml configs. | ||
// I think it's rather obvious what they mean. | ||
context: Mode; | ||
settings: ChecksSettings; | ||
@@ -104,0 +112,0 @@ checks: CheckDefinition<SourceCodeType, Schema>[]; |
@@ -1,2 +0,2 @@ | ||
import { Translations } from '..'; | ||
import { Mode, Translations } from '..'; | ||
@@ -30,4 +30,4 @@ /** | ||
/** A promise that returns a JSON Schema as string */ | ||
schema: Promise<string>; | ||
/** A JSON Schema as string */ | ||
schema: string; | ||
@@ -46,3 +46,3 @@ /** | ||
/** All relevant SchemaDefinitions. */ | ||
schemas: SchemaDefinition[]; | ||
schemas: (mode: Mode) => Promise<SchemaDefinition[]>; | ||
} | ||
@@ -49,0 +49,0 @@ |
@@ -49,3 +49,6 @@ import { ArgumentTypes } from './types'; | ||
*/ | ||
export function memoize<AT, RT, F extends (arg: AT) => RT>(fn: F, keyFn: (arg: AT) => string) { | ||
export function memoize<AT, F extends (arg: AT) => any, RT extends ReturnType<F>>( | ||
fn: F, | ||
keyFn: (arg: AT) => string, | ||
) { | ||
const cache: Record<string, RT> = {}; | ||
@@ -52,0 +55,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
814874
14757