@sketch-hq/sketch-assistant-utils
Advanced tools
Comparing version 2.0.3 to 3.0.0
# @sketch-hq/sketch-assistant-utils | ||
## 3.0.0 | ||
### Major Changes | ||
- 0833437: Do not repeat rule and Assistant metadata per violation, instead move the metadata up a level to the result object where it only needs including once | ||
### Minor Changes | ||
- 0833437: Rules can now optionally declare their platform compatibility, and this is respected by the Assistant runner function | ||
### Patch Changes | ||
- 0833437: Fix `testRule` so that the test config overwrites fully the Assistant's config | ||
- 0833437: Do not strip comments during package compilation, it's useful to retain these so the type comments pop up in intellisense when using the utils in other projects | ||
## 2.0.3 | ||
@@ -4,0 +19,0 @@ |
import Ajv from 'ajv'; | ||
import { AssistantConfig, Maybe, RuleConfig, ViolationSeverity, RuleDefinition } from '../types'; | ||
/** | ||
* Get rule configuration from an assistant config. | ||
*/ | ||
declare const getRuleConfig: (config: AssistantConfig, ruleName: string) => Maybe<RuleConfig>; | ||
/** | ||
* Determine if the rule has been mentioned in a given config. | ||
*/ | ||
declare const isRuleConfigured: (config: AssistantConfig, ruleName: string) => boolean; | ||
/** | ||
* Get the value of a specific rule option. | ||
*/ | ||
declare const getRuleOption: (config: AssistantConfig, ruleName: string, optionKey: string) => Maybe<import("../types").RuleOption>; | ||
/** | ||
* Validate a rule's options in a config object according to the schema defined | ||
* on the rule module. | ||
*/ | ||
declare const isRuleConfigValid: (config: AssistantConfig, rule: RuleDefinition) => true | Ajv.ErrorObject[]; | ||
/** | ||
* Determine if a rule is active. An active rule must both be mentioned in the | ||
* config and have its `active` option set to `true`. | ||
*/ | ||
declare const isRuleActive: (config: AssistantConfig, ruleName: string) => boolean; | ||
/** | ||
* Determine a rule's severity, falling back to default values if not specified. | ||
*/ | ||
declare const getRuleSeverity: (config: AssistantConfig, ruleName: string) => ViolationSeverity; | ||
/** | ||
* Determine a rule's ignore classes. | ||
*/ | ||
declare const getRuleIgnoreClasses: (config: AssistantConfig, ruleName: string) => string[]; | ||
/** | ||
* Determine a rule's ignore name patterns. | ||
*/ | ||
declare const getRuleIgnoreNamePathPatterns: (config: AssistantConfig, ruleName: string) => RegExp[]; | ||
export { getRuleConfig, getRuleOption, isRuleConfigured, isRuleActive, getRuleSeverity, isRuleConfigValid, getRuleIgnoreClasses, getRuleIgnoreNamePathPatterns, }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -9,6 +9,15 @@ "use strict"; | ||
const rule_option_schemas_1 = require("../rule-option-schemas"); | ||
/** | ||
* Get rule configuration from an assistant config. | ||
*/ | ||
const getRuleConfig = (config, ruleName) => config.rules[ruleName]; | ||
exports.getRuleConfig = getRuleConfig; | ||
/** | ||
* Determine if the rule has been mentioned in a given config. | ||
*/ | ||
const isRuleConfigured = (config, ruleName) => !!getRuleConfig(config, ruleName); | ||
exports.isRuleConfigured = isRuleConfigured; | ||
/** | ||
* Get the value of a specific rule option. | ||
*/ | ||
const getRuleOption = (config, ruleName, optionKey) => { | ||
@@ -19,4 +28,9 @@ const ruleConfig = getRuleConfig(config, ruleName); | ||
exports.getRuleOption = getRuleOption; | ||
/** | ||
* Validate a rule's options in a config object according to the schema defined | ||
* on the rule module. | ||
*/ | ||
const isRuleConfigValid = (config, rule) => { | ||
if (typeof rule.getOptions === 'undefined') { | ||
// If the rule hasn't defined an options schema we can't validate it | ||
return true; | ||
@@ -31,2 +45,6 @@ } | ||
exports.isRuleConfigValid = isRuleConfigValid; | ||
/** | ||
* Determine if a rule is active. An active rule must both be mentioned in the | ||
* config and have its `active` option set to `true`. | ||
*/ | ||
const isRuleActive = (config, ruleName) => { | ||
@@ -37,2 +55,5 @@ const active = getRuleOption(config, ruleName, 'active'); | ||
exports.isRuleActive = isRuleActive; | ||
/** | ||
* Determine a rule's severity, falling back to default values if not specified. | ||
*/ | ||
const getRuleSeverity = (config, ruleName) => { | ||
@@ -50,2 +71,5 @@ const severity = getRuleOption(config, ruleName, 'severity'); | ||
exports.getRuleSeverity = getRuleSeverity; | ||
/** | ||
* Determine a rule's ignore classes. | ||
*/ | ||
const getRuleIgnoreClasses = (config, ruleName) => { | ||
@@ -64,2 +88,5 @@ const rawValues = getRuleOption(config, ruleName, 'ignoreClasses'); | ||
exports.getRuleIgnoreClasses = getRuleIgnoreClasses; | ||
/** | ||
* Determine a rule's ignore name patterns. | ||
*/ | ||
const getRuleIgnoreNamePathPatterns = (config, ruleName) => { | ||
@@ -66,0 +93,0 @@ const rawValues = getRuleOption(config, ruleName, 'ignoreNames'); |
import { AssistantDefinition, Assistant, AssistantEnv, Maybe, RuleDefinition, ESModuleInterop } from '../types'; | ||
/** | ||
* Merge assistant definitions together to form a single assistant definition, with a syntax similar | ||
* to Object.assign(). Assistants are merged from the right-most argument to the left into | ||
* preceeding arguments, according to the following algorithm: | ||
* | ||
* 1. Primitive metadata values like `title` and `description` from the right-most assistant | ||
* override the values from the next assistant to the left | ||
* 2. Rule configuration objects are merged together, with values from right-most assistants | ||
* overriding those from the next assistant to the left | ||
* 3. Assistant rule function arrays are concatenated | ||
* | ||
* @param sources Assistant definitions to merge | ||
*/ | ||
declare const assign: (...sources: AssistantDefinition[]) => AssistantDefinition; | ||
/** | ||
* Prepare an assistant. That is, un-roll its exported value into a flat list of assistant functions, | ||
* invoke and await them to obtain a flat list of concrete assistant definitions which is then merged | ||
* to form a final/single assistant definition. | ||
* | ||
* Assistant preparation is performed at runtime by an assistant runner. | ||
* | ||
* @param source The assistant package to prepare | ||
* @param context The env within which the assistant package is being prepared | ||
*/ | ||
declare const prepare: (source: import("../types").ValueOrArray<Assistant | ESModuleInterop<Assistant>>, env: AssistantEnv) => Promise<AssistantDefinition>; | ||
/** | ||
* Lookup a rule definition by rule name. | ||
*/ | ||
declare const getRuleDefinition: (assistant: AssistantDefinition, ruleName: string) => Maybe<RuleDefinition>; | ||
export { prepare, assign, getRuleDefinition }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -12,2 +12,15 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
* Merge assistant definitions together to form a single assistant definition, with a syntax similar | ||
* to Object.assign(). Assistants are merged from the right-most argument to the left into | ||
* preceeding arguments, according to the following algorithm: | ||
* | ||
* 1. Primitive metadata values like `title` and `description` from the right-most assistant | ||
* override the values from the next assistant to the left | ||
* 2. Rule configuration objects are merged together, with values from right-most assistants | ||
* overriding those from the next assistant to the left | ||
* 3. Assistant rule function arrays are concatenated | ||
* | ||
* @param sources Assistant definitions to merge | ||
*/ | ||
const assign = (...sources) => { | ||
@@ -27,2 +40,12 @@ return sources.reduceRight((acc, curr) => { | ||
exports.assign = assign; | ||
/** | ||
* Prepare an assistant. That is, un-roll its exported value into a flat list of assistant functions, | ||
* invoke and await them to obtain a flat list of concrete assistant definitions which is then merged | ||
* to form a final/single assistant definition. | ||
* | ||
* Assistant preparation is performed at runtime by an assistant runner. | ||
* | ||
* @param source The assistant package to prepare | ||
* @param context The env within which the assistant package is being prepared | ||
*/ | ||
const prepare = (source, env) => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -43,4 +66,7 @@ const definitions = yield Promise.all((Array.isArray(source) ? source : [source]) | ||
exports.prepare = prepare; | ||
/** | ||
* Lookup a rule definition by rule name. | ||
*/ | ||
const getRuleDefinition = (assistant, ruleName) => assistant.rules.find(rule => rule.name === ruleName); | ||
exports.getRuleDefinition = getRuleDefinition; | ||
//# sourceMappingURL=index.js.map |
import { NodeCache, NodeCacheIterator, RunOperation } from '../types'; | ||
/** | ||
* Create a Sketch file cache iterator, a function that iterators across objects | ||
* in the cache, and calls visitor callback functions for them if defined. | ||
*/ | ||
declare const createCacheIterator: (cache: NodeCache, operation: RunOperation) => NodeCacheIterator; | ||
/** | ||
* Return the minimal/empty cache object. | ||
*/ | ||
declare const createCache: () => NodeCache; | ||
export { createCacheIterator, createCache }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -12,2 +12,6 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
* Create a Sketch file cache iterator, a function that iterators across objects | ||
* in the cache, and calls visitor callback functions for them if defined. | ||
*/ | ||
const createCacheIterator = (cache, operation) => (config) => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -29,2 +33,5 @@ for (const key of Object.keys(config)) { | ||
exports.createCacheIterator = createCacheIterator; | ||
/** | ||
* Return the minimal/empty cache object. | ||
*/ | ||
const createCache = () => ({ | ||
@@ -31,0 +38,0 @@ $layers: [], |
import { SketchFile } from '../types'; | ||
/** | ||
* Given a path to a Sketch file on the file system, this function unzips the | ||
* JSON entries and parses them out into a SketchFile object. | ||
*/ | ||
declare const fromFile: (filepath: string) => Promise<SketchFile>; | ||
export { fromFile }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -16,2 +16,6 @@ "use strict"; | ||
const node_stream_zip_1 = __importDefault(require("node-stream-zip")); | ||
/** | ||
* Given a path to a Sketch file on the file system, this function unzips the | ||
* JSON entries and parses them out into a SketchFile object. | ||
*/ | ||
const fromFile = (filepath) => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -18,0 +22,0 @@ const archive = new node_stream_zip_1.default({ |
import { GetImageMetadata } from '../types'; | ||
/** | ||
* Efficiently access image metadata from a zipped Sketch document. Streams | ||
* the image from the zip, and returns as soon as the image dimensions are | ||
* parsed from the header chunks. | ||
*/ | ||
declare const getImageMetadata: GetImageMetadata; | ||
export { getImageMetadata }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -8,2 +8,7 @@ "use strict"; | ||
const probe_image_size_1 = __importDefault(require("probe-image-size")); | ||
/** | ||
* Efficiently access image metadata from a zipped Sketch document. Streams | ||
* the image from the zip, and returns as soon as the image dimensions are | ||
* parsed from the header chunks. | ||
*/ | ||
const getImageMetadata = (ref, filepath) => new Promise((resolve, reject) => { | ||
@@ -10,0 +15,0 @@ const zip = new node_stream_zip_1.default({ file: filepath, storeEntries: true }); |
import { Node, FileFormat } from '../types'; | ||
/** | ||
* Convert a Sketch file-walking Node to a specific file format object. Use this | ||
* to hint the TypeScript compiler which object type you're currently working | ||
* with. Usage, | ||
* | ||
* const artboard = nodeToObj<FileFormat.Artboard>(node) | ||
*/ | ||
declare const nodeToObject: <T extends FileFormat.AnyObject>(node: Node<FileFormat.AnyObject>) => T; | ||
/** | ||
* Return the md5 hash of an object. Keys are deeply sorted for a stable hash. | ||
* Useful for comparing deep similarity of Sketch document objects. | ||
*/ | ||
declare const objectHash: (obj: {}, excludeKeys?: string[]) => string; | ||
/** | ||
* Compares two objects for deep equality. | ||
*/ | ||
declare const objectsEqual: (o1: {}, o2: {}, excludeKeys?: string[]) => boolean; | ||
export { nodeToObject, objectHash, objectsEqual }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -18,2 +18,9 @@ "use strict"; | ||
const object_hash_1 = __importDefault(require("object-hash")); | ||
/** | ||
* Convert a Sketch file-walking Node to a specific file format object. Use this | ||
* to hint the TypeScript compiler which object type you're currently working | ||
* with. Usage, | ||
* | ||
* const artboard = nodeToObj<FileFormat.Artboard>(node) | ||
*/ | ||
const nodeToObject = (node) => { | ||
@@ -24,2 +31,6 @@ const { $pointer: _$pointer } = node, obj = __rest(node, ["$pointer"]); | ||
exports.nodeToObject = nodeToObject; | ||
/** | ||
* Return the md5 hash of an object. Keys are deeply sorted for a stable hash. | ||
* Useful for comparing deep similarity of Sketch document objects. | ||
*/ | ||
const objectHash = (obj, excludeKeys = []) => object_hash_1.default(obj, { | ||
@@ -31,4 +42,7 @@ unorderedObjects: true, | ||
exports.objectHash = objectHash; | ||
/** | ||
* Compares two objects for deep equality. | ||
*/ | ||
const objectsEqual = (o1, o2, excludeKeys = []) => objectHash(o1, excludeKeys) === objectHash(o2, excludeKeys); | ||
exports.objectsEqual = objectsEqual; | ||
//# sourceMappingURL=index.js.map |
import { Maybe, PointerValue, FileFormat } from '../types'; | ||
/** | ||
* Resolve a JSON Pointer to a value within a SketchFile. | ||
*/ | ||
declare const get: (pointer: string, instance: FileFormat.Contents) => Maybe<PointerValue>; | ||
/** | ||
* Resolve the parent of a JSON Pointer to a value within a SketchFile. | ||
*/ | ||
declare const parent: (pointer: string, instance: FileFormat.Contents) => Maybe<PointerValue>; | ||
export { get, parent }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -7,2 +7,5 @@ "use strict"; | ||
const json_pointer_1 = __importDefault(require("@json-schema-spec/json-pointer")); | ||
/** | ||
* Resolve a JSON Pointer to a value within a SketchFile. | ||
*/ | ||
const get = (pointer, instance) => { | ||
@@ -18,2 +21,5 @@ try { | ||
exports.get = get; | ||
/** | ||
* Resolve the parent of a JSON Pointer to a value within a SketchFile. | ||
*/ | ||
const parent = (pointer, instance) => { | ||
@@ -20,0 +26,0 @@ try { |
import { RunOperation, ProcessedSketchFile, SketchFile } from '../types'; | ||
/** | ||
* Recursively prepare Sketch document data in preparation for performing a lint | ||
* run. In practice this means performing two things: | ||
* | ||
* 1. Augmenting each object in the document data with an RFC 6901 compliant | ||
* JSON Pointer string on the `$pointer` key, unlikely to clash with other | ||
* object keys. The pointer values enable objects to indicate their location | ||
* in the document structure, even when observed in isolation, for example | ||
* in a lint rule. | ||
* 2. Populating a minimal cache of Sketch document objects keyed by their | ||
* `_class` prop values, for efficient access and iteration in rule logic. | ||
*/ | ||
declare const process: (file: SketchFile, op: RunOperation) => Promise<ProcessedSketchFile>; | ||
export { process }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -6,7 +6,12 @@ "use strict"; | ||
const processNode = (input, cache, op, pointer) => { | ||
// Bail early if we've been passed a falsey value or the operation is cancelled | ||
if (!input || op.cancelled) | ||
return; | ||
// Bail early if input is not an object | ||
if (typeof input !== 'object') | ||
return; | ||
// Inject the current pointer value | ||
input.$pointer = pointer; | ||
// Test to see if we've been passed an array and if so process each element | ||
// recursively and return | ||
if (input.constructor === Array) { | ||
@@ -21,8 +26,15 @@ const array = input; | ||
for (const key in input) { | ||
// Bail out of this loop iteration early if the key has been excluded | ||
// from processing | ||
if (DO_NOT_PROCESS_KEYS.includes(key)) | ||
continue; | ||
// If the current object has a `_class` prop it means the object should | ||
// be cached in the NodeCache | ||
if (key === '_class') { | ||
if (!cache[obj._class]) | ||
cache[obj._class] = []; | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
cache[obj._class].push(obj); | ||
// Use presence of `layers` and `frame` props as heuristics to identify | ||
// objects with group and layer traits respectively | ||
if ('layers' in obj) | ||
@@ -33,5 +45,18 @@ cache.$groups.push(obj); | ||
} | ||
// Recurse into the input's sub values | ||
processNode(obj[key], cache, op, `${pointer}/${key}`); | ||
} | ||
}; | ||
/** | ||
* Recursively prepare Sketch document data in preparation for performing a lint | ||
* run. In practice this means performing two things: | ||
* | ||
* 1. Augmenting each object in the document data with an RFC 6901 compliant | ||
* JSON Pointer string on the `$pointer` key, unlikely to clash with other | ||
* object keys. The pointer values enable objects to indicate their location | ||
* in the document structure, even when observed in isolation, for example | ||
* in a lint rule. | ||
* 2. Populating a minimal cache of Sketch document objects keyed by their | ||
* `_class` prop values, for efficient access and iteration in rule logic. | ||
*/ | ||
const process = (file, op) => { | ||
@@ -38,0 +63,0 @@ const cache = file_cache_1.createCache(); |
import { RuleOptionSchemaCreator, RuleOptionHelpers } from '../types'; | ||
/** | ||
* Combine multiple rule option schemas into one. We treat _all_ custom options | ||
* as required. | ||
*/ | ||
declare const buildRuleOptionSchema: RuleOptionSchemaCreator; | ||
@@ -3,0 +7,0 @@ declare const helpers: RuleOptionHelpers; |
@@ -17,2 +17,6 @@ "use strict"; | ||
} | ||
/** | ||
* Combine multiple rule option schemas into one. We treat _all_ custom options | ||
* as required. | ||
*/ | ||
const buildRuleOptionSchema = ops => ({ | ||
@@ -24,2 +28,5 @@ type: 'object', | ||
exports.buildRuleOptionSchema = buildRuleOptionSchema; | ||
/** | ||
* Create a floating point number option. | ||
*/ | ||
const numberOption = ops => { | ||
@@ -31,2 +38,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create an integer option. | ||
*/ | ||
const integerOption = ops => { | ||
@@ -38,2 +48,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create a string option. | ||
*/ | ||
const stringOption = ops => { | ||
@@ -45,2 +58,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create a boolean option. | ||
*/ | ||
const booleanOption = ops => { | ||
@@ -57,2 +73,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create a string option limited to a set of values. | ||
*/ | ||
const stringEnumOption = ops => { | ||
@@ -71,2 +90,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create a string list option. | ||
*/ | ||
const stringArrayOption = ops => { | ||
@@ -84,2 +106,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create an object list option. | ||
*/ | ||
const objectArrayOption = ops => { | ||
@@ -86,0 +111,0 @@ assertOptionNameNotReserved(ops.name); |
import { Violation, RunOperation, RuleUtilsCreator, GetImageMetadata, AssistantDefinition, ProcessedSketchFile } from '../types'; | ||
/** | ||
* Returns a RuleUtilsCreator function, which can be used to build util objects | ||
* scoped to a specific rule. | ||
*/ | ||
declare const createRuleUtilsCreator: (processedFile: ProcessedSketchFile, violations: Violation[], assistant: AssistantDefinition, operation: RunOperation, getImageMetadata: GetImageMetadata) => RuleUtilsCreator; | ||
export { createRuleUtilsCreator }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -38,2 +38,7 @@ "use strict"; | ||
} | ||
/** | ||
* Add one or more report items into a violations array. Reports from rules just contain a message | ||
* and optionally a Node, whereas violations container richer contextual information therefore this | ||
* function maps the former to the latter. | ||
*/ | ||
const addReportsToViolations = (report, violations, assistant, rule, iterateParents) => { | ||
@@ -48,5 +53,7 @@ if (Array.isArray(report) && report.length === 0) | ||
violations.push(...(Array.isArray(report) ? report : [report]) | ||
// Filter out reports involving nodes with ignored `_class` props | ||
.filter(item => { | ||
return item.node ? !classesToIgnore.includes(item.node._class) : true; | ||
}) | ||
// Filter out nodes with ignored name paths | ||
.filter(item => { | ||
@@ -67,13 +74,4 @@ if (!item.node || namesToIgnore.length === 0) | ||
return { | ||
assistant: { | ||
title: assistant.title, | ||
name: assistant.name, | ||
description: assistant.description, | ||
}, | ||
rule: { | ||
title: rule.title, | ||
name: rule.name, | ||
description: rule.description, | ||
debug: rule.debug, | ||
}, | ||
assistantName: assistant.name, | ||
ruleName: rule.name, | ||
message: item.message, | ||
@@ -90,2 +88,8 @@ severity, | ||
}; | ||
/** | ||
* Creates a function that rules can use to get an option value by `name`. All rules need to do is | ||
* pass the option `name`, all other values are already in scope. A InvalidRuleConfigError is thrown | ||
* if rules attempt to access missing options, or options that are invalid according to the rule's | ||
* self-declared option schema. | ||
*/ | ||
const createOptionGetter = (assistant, rule) => (optionKey) => { | ||
@@ -112,2 +116,5 @@ const result = assistant_config_1.isRuleConfigValid(assistant.config, rule); | ||
}; | ||
/** | ||
* Create a parent iterator function scoped to a Sketch file. | ||
*/ | ||
const createParentIterator = (file) => (node, callback) => { | ||
@@ -129,2 +136,6 @@ if (!node) | ||
}; | ||
/** | ||
* Returns a RuleUtilsCreator function, which can be used to build util objects | ||
* scoped to a specific rule. | ||
*/ | ||
const createRuleUtilsCreator = (processedFile, violations, assistant, operation, getImageMetadata) => { | ||
@@ -131,0 +142,0 @@ const { file, cache } = processedFile; |
@@ -8,4 +8,7 @@ import { AssistantDefinition, ProcessedSketchFile, AssistantEnv, RunOperation, GetImageMetadata, RunResult } from '../types'; | ||
} | ||
/** | ||
* Run an assistant, catching and returning any errors encountered during rule invocation. | ||
*/ | ||
declare const runAssistant: (file: ProcessedSketchFile, assistant: AssistantDefinition, env: AssistantEnv, operation: RunOperation, getImageMetadata: GetImageMetadata) => Promise<RunResult>; | ||
export { runAssistant, RuleInvocationError }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -29,2 +29,5 @@ "use strict"; | ||
exports.RuleInvocationError = RuleInvocationError; | ||
/** | ||
* Run an assistant, catching and returning any errors encountered during rule invocation. | ||
*/ | ||
const runAssistant = (file, assistant, env, operation, getImageMetadata) => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -40,4 +43,23 @@ const violations = []; | ||
}; | ||
const activeRules = assistant.rules | ||
.filter(rule => assistant_config_1.isRuleActive(assistant.config, rule.name)) // Rule turned on in config | ||
.filter(rule => (rule.platform ? rule.platform === env.platform : true)); // Rule platform is supported | ||
const metadata = { | ||
assistant: { | ||
title: assistant.title, | ||
description: assistant.description, | ||
name: assistant.name, | ||
config: assistant.config, | ||
}, | ||
rules: activeRules.reduce((acc, curr) => { | ||
return Object.assign(Object.assign({}, acc), { [curr.name]: { | ||
title: curr.title, | ||
description: curr.description, | ||
debug: curr.debug, | ||
platform: curr.platform, | ||
} }); | ||
}, {}), | ||
}; | ||
try { | ||
yield p_map_1.default(assistant.rules.filter(rule => assistant_config_1.isRuleActive(assistant.config, rule.name)), (rule) => __awaiter(void 0, void 0, void 0, function* () { | ||
yield p_map_1.default(activeRules, (rule) => __awaiter(void 0, void 0, void 0, function* () { | ||
if (operation.cancelled) | ||
@@ -59,2 +81,3 @@ return; | ||
errors: Array.from(error), | ||
metadata, | ||
}; | ||
@@ -65,2 +88,3 @@ } | ||
errors: [], | ||
metadata, | ||
}; | ||
@@ -67,0 +91,0 @@ }); |
import { FileFormat, Assistant, RuleOptionsCreator, RuleFunction, RuleDefinition, AssistantDefinition, AssistantConfig, ViolationSeverity, RuleConfigGroup, AssistantEnv, RunResult } from '../types'; | ||
declare const createRule: ({ title, description, rule, getOptions, name, debug, }?: { | ||
/** | ||
* Create a dummy rule definition. | ||
*/ | ||
declare const createRule: ({ title, description, rule, getOptions, name, debug, platform, }?: { | ||
title?: string | undefined; | ||
@@ -9,3 +12,7 @@ description?: string | undefined; | ||
debug?: boolean | undefined; | ||
platform?: "sketch" | "node" | undefined; | ||
}) => RuleDefinition; | ||
/** | ||
* Create a dummy assistant configuration. | ||
*/ | ||
declare const createAssistantConfig: ({ rules, defaultSeverity, }?: { | ||
@@ -15,2 +22,5 @@ rules?: RuleConfigGroup | undefined; | ||
}) => AssistantConfig; | ||
/** | ||
* Create a dummy assistant definition. | ||
*/ | ||
declare const createAssistantDefinition: ({ title, description, name, config, rules, }?: { | ||
@@ -23,2 +33,5 @@ title?: string | undefined; | ||
}) => AssistantDefinition; | ||
/** | ||
* Create a dummy assistant function. | ||
*/ | ||
declare const createAssistant: ({ title, description, name, config, rules, }?: { | ||
@@ -34,4 +47,8 @@ title?: string | undefined; | ||
}; | ||
export declare const testRule: (filepath: string, configGroup: RuleConfigGroup, assistant: Assistant, env?: AssistantEnv) => Promise<RunResult>; | ||
/** | ||
* Test an individual rule within the context of a specific assistant. The assistant has its config | ||
* overwritten by the passed in value to enable testing rules in isolation. | ||
*/ | ||
export declare const testRule: (filepath: string, ruleConfig: RuleConfigGroup, assistant: Assistant, env?: AssistantEnv) => Promise<RunResult>; | ||
export { createRule, createDummyRectNode, createAssistantConfig, createAssistant, createAssistantDefinition, }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -17,3 +17,6 @@ "use strict"; | ||
const get_image_metadata_1 = require("../get-image-metadata"); | ||
const createRule = ({ title, description, rule, getOptions, name, debug, } = {}) => ({ | ||
/** | ||
* Create a dummy rule definition. | ||
*/ | ||
const createRule = ({ title, description, rule, getOptions, name, debug, platform, } = {}) => ({ | ||
name: name !== null && name !== void 0 ? name : 'dummy-assistant/dummy-rule', | ||
@@ -25,6 +28,13 @@ title: title !== null && title !== void 0 ? title : 'Dummy Rule', | ||
debug, | ||
platform: platform !== null && platform !== void 0 ? platform : 'node', | ||
}); | ||
exports.createRule = createRule; | ||
/** | ||
* Create a dummy assistant configuration. | ||
*/ | ||
const createAssistantConfig = ({ rules, defaultSeverity, } = {}) => (Object.assign(Object.assign({}, (typeof defaultSeverity === 'undefined' ? {} : { defaultSeverity })), { rules: rules || {} })); | ||
exports.createAssistantConfig = createAssistantConfig; | ||
/** | ||
* Create a dummy assistant definition. | ||
*/ | ||
const createAssistantDefinition = ({ title, description, name, config, rules, } = {}) => ({ | ||
@@ -38,2 +48,5 @@ title: title !== null && title !== void 0 ? title : 'Dummy Assistant', | ||
exports.createAssistantDefinition = createAssistantDefinition; | ||
/** | ||
* Create a dummy assistant function. | ||
*/ | ||
const createAssistant = ({ title, description, name, config, rules, } = {}) => () => __awaiter(void 0, void 0, void 0, function* () { return createAssistantDefinition({ title, description, name, config, rules }); }); | ||
@@ -51,21 +64,16 @@ exports.createAssistant = createAssistant; | ||
exports.createDummyRectNode = createDummyRectNode; | ||
exports.testRule = (filepath, configGroup, assistant, env = { locale: 'en', platform: 'node' }) => __awaiter(void 0, void 0, void 0, function* () { | ||
/** | ||
* Test an individual rule within the context of a specific assistant. The assistant has its config | ||
* overwritten by the passed in value to enable testing rules in isolation. | ||
*/ | ||
exports.testRule = (filepath, ruleConfig, assistant, env = { locale: 'en', platform: 'node' }) => __awaiter(void 0, void 0, void 0, function* () { | ||
const file = yield from_file_1.fromFile(filepath); | ||
const op = { cancelled: false }; | ||
const processedFile = yield process_1.process(file, op); | ||
const TestAssistant = [ | ||
assistant, | ||
() => __awaiter(void 0, void 0, void 0, function* () { | ||
return ({ | ||
name: '', | ||
description: '', | ||
title: '', | ||
rules: [], | ||
config: { rules: Object.assign({}, configGroup) }, | ||
}); | ||
}), | ||
]; | ||
const assistantDefinition = yield assistant_1.prepare(TestAssistant, env); | ||
const assistantDefinition = yield assistant_1.prepare(assistant, env); | ||
assistantDefinition.config = { | ||
rules: ruleConfig, | ||
}; | ||
return yield run_assistant_1.runAssistant(processedFile, assistantDefinition, env, op, get_image_metadata_1.getImageMetadata); | ||
}); | ||
//# sourceMappingURL=index.js.map |
import { FileFormat3 } from '@sketch-hq/sketch-file-format-ts'; | ||
import { JSONSchema7 } from 'json-schema'; | ||
/** | ||
* Re-export the specific version of the file format supported by this package. | ||
*/ | ||
export { FileFormat3 as FileFormat }; | ||
/** | ||
* Optional value. | ||
*/ | ||
export declare type Maybe<T> = T | undefined | null; | ||
/** | ||
* All possible string values for the `_class` property in Sketch files. | ||
*/ | ||
export declare type SketchClass = FileFormat3.AnyObject['_class']; | ||
/** | ||
* Utility function for gathering metadata about Sketch file images. Is isomorphic in the sense that | ||
* its signature shound't change across platforms. | ||
*/ | ||
export declare type GetImageMetadata = (ref: string, filepath: string) => Promise<ImageMetadata>; | ||
/** | ||
* When rules request metadata for a Sketch file image it is returned in this format. | ||
*/ | ||
export declare type ImageMetadata = { | ||
@@ -12,2 +28,6 @@ width: number; | ||
}; | ||
/** | ||
* Represents a Sketch file that is on disk. Collates the filepath with an object | ||
* typed as Contents from the file format. | ||
*/ | ||
export declare type SketchFile = { | ||
@@ -17,15 +37,43 @@ filepath: string; | ||
}; | ||
/** | ||
* Value or arbitrarily nested array of values. | ||
*/ | ||
export declare type ValueOrArray<T> = T | Array<ValueOrArray<T>>; | ||
/** | ||
* Union of all possible objects with a `_class` value that can be found in a Sketch | ||
* file, injected with a JSON Pointer during file processing. | ||
*/ | ||
export declare type Node<T = FileFormat3.AnyObject> = T & { | ||
$pointer: string; | ||
}; | ||
/** | ||
* Array of Nodes. An concrete example of this in a Sketch file is a group's `layers` array. | ||
*/ | ||
export interface NodeArray extends Array<Node> { | ||
$pointer: string; | ||
} | ||
/** | ||
* All possible Node and primitive values that a JSON Pointer can resolve to in a Sketch file. | ||
*/ | ||
export declare type PointerValue = Node | NodeArray | Node<FileFormat3.Contents> | Node<FileFormat3.Contents['document']> | Node<FileFormat3.Contents['meta']> | Node<FileFormat3.Contents['user']> | string | number | boolean; | ||
/** | ||
* Rule-supplied function called during cache iteration. Rules will typically use these while | ||
* scanning a Sketch file for relevant objects and checking the values against their logic. | ||
*/ | ||
export declare type NodeCacheVisitor = (data: Node) => Promise<void>; | ||
/** | ||
* Rules supply a cache iterator config to register vistor functions against the specific object | ||
* types available in the cache. | ||
*/ | ||
export declare type NodeCacheIteratorConfig = { | ||
[key in keyof NodeCache]?: NodeCacheVisitor; | ||
}; | ||
/** | ||
* A function that iterates a cache using a cache iteration config. | ||
*/ | ||
export declare type NodeCacheIterator = (config: NodeCacheIteratorConfig) => Promise<void>; | ||
/** | ||
* A cache of Sketch file Nodes keyed by `_class` values. The special `$layers` key collates all | ||
* layer Nodes, and the `$groups` key collates all layer Nodes that are also groups. | ||
*/ | ||
export declare type NodeCache = { | ||
@@ -37,2 +85,6 @@ $layers: Node[]; | ||
}; | ||
/** | ||
* A processed Sketch file is one that has has had its objects cached into a NodeCache, and JSON | ||
* Pointers injected. | ||
*/ | ||
export declare type ProcessedSketchFile = { | ||
@@ -42,2 +94,8 @@ cache: NodeCache; | ||
}; | ||
/** | ||
* Contains a flag indicating whether the run operation has been cancelled by | ||
* the outer environment. All long running processes happening during a run | ||
* (like cache creation, rule invocation etc.) should exit early as soon as a | ||
* cancellation is detected. | ||
*/ | ||
export declare type RunOperation = { | ||
@@ -48,6 +106,22 @@ cancelled: boolean; | ||
}; | ||
/** | ||
* The result of running an assistant. One or more `violations` implies the assistant's rules found | ||
* issues with the Sketch document. One or more `errors` implies that some rules didn't run because | ||
* they encountered errors. Metadata (`title`, `description` etc) relating to the Assistant that | ||
* produced the result, and the rules that were invoked is also provided | ||
*/ | ||
export declare type RunResult = { | ||
violations: Violation[]; | ||
errors: Error[]; | ||
metadata: { | ||
assistant: Omit<AssistantDefinition, 'rules'>; | ||
rules: { | ||
[ruleName: string]: Omit<RuleDefinition, 'rule' | 'getOptions' | 'name'>; | ||
}; | ||
}; | ||
}; | ||
/** | ||
* Contains all the values and utils exposed to individual rule functions. The | ||
* values are scoped to the rule itself, to simplify the API surface. | ||
*/ | ||
export declare type RuleContext = { | ||
@@ -61,16 +135,63 @@ utils: RuleUtils; | ||
}; | ||
/** | ||
* Function for creating a rule utilties object scoped to a specific assistant rule. | ||
*/ | ||
export declare type RuleUtilsCreator = (ruleName: string) => RuleUtils; | ||
/** | ||
* A function that when invoked repeatedly calls its callback for each of a Node's parents | ||
* until it reaches the document root, at wich point it stops. | ||
*/ | ||
export declare type ParentIterator = (node: Maybe<PointerValue>, callback: (target: Node | NodeArray | Node<FileFormat3.Contents['document']>) => void) => void; | ||
/** | ||
* Object contain utilties to be used within rule functions. | ||
*/ | ||
export declare type RuleUtils = { | ||
/** | ||
* Report one or more violations. | ||
*/ | ||
report: (report: ReportItem | ReportItem[]) => void; | ||
/** | ||
* Iterate the Sketch file object cache. | ||
*/ | ||
iterateCache: (config: NodeCacheIteratorConfig) => Promise<void>; | ||
/** | ||
* Iterate back through the Node's parents to the Sketch file root. | ||
*/ | ||
iterateParents: ParentIterator; | ||
/** | ||
* Get a rule option value by name. Throws if the rule hasn't been configured in the assistant. | ||
* It's essential that every rule activated in an assistant is properly configured. | ||
*/ | ||
getOption: (option: string) => Maybe<RuleOption>; | ||
/** | ||
* Returns metadata for a given Sketch file image. | ||
*/ | ||
getImageMetadata: (ref: string) => Promise<ImageMetadata>; | ||
/** | ||
* Converts a Node to the original file format type. | ||
*/ | ||
nodeToObject: <T extends FileFormat3.AnyObject>(node: Node) => T; | ||
/** | ||
* Return the md5 hash of an object. Keys are deeply sorted for a stable hash. | ||
* Useful for comparing deep similarity of Sketch document objects. By default | ||
* the keys `do_objectID` and `$pointer` are excluded since they will always | ||
* be different. | ||
*/ | ||
objectHash: (o: {}, excludeKeys?: string[]) => string; | ||
/** | ||
* Compare two document objects for deep equality. | ||
*/ | ||
objectsEqual: (o1: {}, o2: {}, excludeKeys?: string[]) => boolean; | ||
/** | ||
* Resolve a JSON Pointer to a document object. | ||
*/ | ||
get: (pointer: string) => Maybe<PointerValue>; | ||
/** | ||
* Resolve a JSON Pointer to a document object's parent. | ||
*/ | ||
parent: (pointer: string) => Maybe<PointerValue>; | ||
}; | ||
/** | ||
* Information a rule needs to supply when reporting a violation. | ||
*/ | ||
export declare type ReportItem = { | ||
@@ -80,6 +201,10 @@ message: string; | ||
}; | ||
/** | ||
* A violation collates all the information about a problem, and is the fundamental way an assistant | ||
* communicates results to the outer environment. | ||
*/ | ||
export declare type Violation = { | ||
message: string; | ||
assistant: Omit<AssistantDefinition, 'rules' | 'config'>; | ||
rule: Omit<RuleDefinition, 'rule' | 'getOptions'>; | ||
assistantName: string; | ||
ruleName: string; | ||
severity: ViolationSeverity; | ||
@@ -89,2 +214,5 @@ pointer: string | null; | ||
}; | ||
/** | ||
* Define the possible violation severity levels. | ||
*/ | ||
export declare enum ViolationSeverity { | ||
@@ -95,7 +223,33 @@ info = 1, | ||
} | ||
/** | ||
* Platforms that can run Assistants. | ||
*/ | ||
export declare type Platform = 'sketch' | 'node'; | ||
/** | ||
* Ambient environmental information for assistants, typically provided by an outer assistant runner. | ||
*/ | ||
export declare type AssistantEnv = { | ||
/** | ||
* Language tag indicating the current user's locale. Use this to optionally internationalize your | ||
* assistant's content. Its exact value is not guaranteed, so an appropriate fallback locale should | ||
* always be used for unrecognised values. For assistants running in Sketch it's value is likely | ||
* to be either `en` or `zh-Hans`. | ||
*/ | ||
locale: string | undefined; | ||
platform: 'sketch' | 'node'; | ||
/** | ||
* Indicates whether the assistant is running in either a Node or Sketch (JavaScriptCore) environment | ||
*/ | ||
platform: Platform; | ||
}; | ||
/** | ||
* Canonical definition of an assistant, that is, an async function that given an AssistantEnv | ||
* will resolve with a concrete AssistantDefinition. Assistants therefore are able to defer final | ||
* creation until invoked by a runner, and which point critical contextual information such as the | ||
* locale are available. | ||
*/ | ||
export declare type Assistant = (env: AssistantEnv) => Promise<AssistantDefinition>; | ||
/** | ||
* The shape of an ES Module with a default export built with TypeScript or Babel with ES Module | ||
* interoperability. | ||
*/ | ||
export declare type ESModuleInterop<DefaultExport> = { | ||
@@ -105,25 +259,94 @@ __esModule: true; | ||
}; | ||
/** | ||
* Defines the expected type definition for the export from a 1st or 3rd party assistant package. It | ||
* allows an assistant to be expressed as either a single assistant or an array of assistants that | ||
* should be merged before a run operation. Via type recursion arbitrarily nested arrays of | ||
* assistant functions are supported to allow for incorporation of other assistant packages into | ||
* the final export. | ||
*/ | ||
export declare type AssistantPackageExport = ValueOrArray<Assistant | ESModuleInterop<Assistant>>; | ||
/** | ||
* Concrete assistant definition that can be invoked against a Sketch file during a lint run. | ||
* Fundamentally assistants collate a list of rules with configuration for those rules, alongside | ||
* metadata about the assistant. | ||
*/ | ||
export declare type AssistantDefinition = { | ||
/** | ||
* List of rules owned by the assistant. | ||
*/ | ||
rules: RuleDefinition[]; | ||
/** | ||
* Assistant configuration activates and configures one or more rules present in its rule list. | ||
*/ | ||
config: AssistantConfig; | ||
/** | ||
* Human readable assistant name, e.g. "Grid of 8" | ||
*/ | ||
title: string; | ||
/** | ||
* Longer human readable description for the assistant. | ||
*/ | ||
description: string; | ||
/** | ||
* Assistant name is the same as its package name, i.e. the `name` property in its `package.json`. | ||
*/ | ||
name: string; | ||
}; | ||
/** | ||
* Canonical rule defintion combining the rule function, its option schema creator with other | ||
* basic metadata. | ||
*/ | ||
export declare type RuleDefinition = { | ||
rule: RuleFunction; | ||
/** | ||
* The rule name acts as its id and should combine an identifier for the rule with the parent | ||
* assistant's name separated by a slash, e.g. | ||
* "@sketch-hq/sketch-assistant-recommended/groups-max-layers" | ||
*/ | ||
name: string; | ||
/** | ||
* Human readable title for the rule, e.g. "Groups Max Layers". | ||
*/ | ||
title: string; | ||
/** | ||
* Longer human readable description for the rule. | ||
*/ | ||
description: string; | ||
/** | ||
* Rules that require options (i.e. are not just simply "on" or "off") need to describe the schema | ||
* for those options by implementing this function | ||
*/ | ||
getOptions?: RuleOptionsCreator; | ||
/** | ||
* Flags a rule as for internal/development purposes only | ||
*/ | ||
debug?: boolean; | ||
/** | ||
* Indicates rule platform compatibility. For cross-platform rules this property can be omitted. | ||
*/ | ||
platform?: Platform; | ||
}; | ||
/** | ||
* A map of rule configs, keyed by the rule's name. | ||
*/ | ||
export declare type RuleConfigGroup = { | ||
[ruleName: string]: Maybe<RuleConfig>; | ||
}; | ||
/** | ||
* Contains the assistant configuration. | ||
*/ | ||
export declare type AssistantConfig = { | ||
/** | ||
* Default severity to be used for violations raised by rules that haven't been configured with | ||
* their own explicit severity level. | ||
*/ | ||
defaultSeverity?: Maybe<ViolationSeverity>; | ||
/** | ||
* Configuration to be applied to the rules available to the assistant. | ||
*/ | ||
rules: RuleConfigGroup; | ||
}; | ||
/** | ||
* Custom rule options with these names are forbidden. | ||
*/ | ||
export declare enum ReservedRuleOptionNames { | ||
@@ -135,16 +358,50 @@ active = "active", | ||
} | ||
/** | ||
* Contains the configuration for an individual rule. | ||
*/ | ||
export declare type RuleConfig = { | ||
/** | ||
* Whether the rule is active or not. Alternatively omitting the rule from the assistant config is | ||
* the same as setting this flag to `false`. | ||
*/ | ||
[ReservedRuleOptionNames.active]: boolean; | ||
/** | ||
* The severity of any violations reported by the rule. | ||
*/ | ||
[ReservedRuleOptionNames.severity]?: ViolationSeverity; | ||
/** | ||
* Violations associated with Nodes with `_class` values listed here will be filtered out of the | ||
* final result set. | ||
*/ | ||
[ReservedRuleOptionNames.ignoreClasses]?: SketchClass[]; | ||
/** | ||
* Violations associated with Nodes with name paths that match the regexes listed here will be | ||
* filtered out of the final result set. | ||
*/ | ||
[ReservedRuleOptionNames.ignoreNames]?: string[]; | ||
/** | ||
* Rule custom options will also appear mixed into this object. | ||
*/ | ||
[key: string]: Maybe<RuleOption>; | ||
}; | ||
/** | ||
* The valid set of types available for individual rule options. | ||
*/ | ||
export declare type RuleOption = string | number | boolean | string[] | { | ||
[key: string]: Maybe<string | number | boolean | string[]>; | ||
}[]; | ||
/** | ||
* Async function that is expected to perform the core rule logic using the values and helper | ||
* functions provided by the passed in RuleInvocationContext object. | ||
*/ | ||
export declare type RuleFunction = (context: RuleContext) => Promise<void>; | ||
/** | ||
* JSONSchema `properties` value. | ||
*/ | ||
export declare type JSONSchemaProps = { | ||
[key: string]: JSONSchema7; | ||
}; | ||
/** | ||
* Creates rule option schema properties for a number option. | ||
*/ | ||
export declare type NumberOptionCreator = (ops: { | ||
@@ -158,2 +415,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for an integer option. | ||
*/ | ||
export declare type IntegerOptionCreator = (ops: { | ||
@@ -167,2 +427,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for a string option. | ||
*/ | ||
export declare type StringOptionCreator = (ops: { | ||
@@ -177,2 +440,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for a boolean option. | ||
*/ | ||
export declare type BoolOptionCreator = (ops: { | ||
@@ -184,2 +450,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for a string enum option. | ||
*/ | ||
export declare type StringEnumOptionCreator = (ops: { | ||
@@ -193,2 +462,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for a string array option. | ||
*/ | ||
export declare type StringArrayOptionCreator = (ops: { | ||
@@ -203,2 +475,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for an object array option. | ||
*/ | ||
export declare type ObjectArrayOptionCreator = (ops: { | ||
@@ -212,3 +487,9 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* A function that should be implemented on rule definitions if they need to define custom options. | ||
*/ | ||
export declare type RuleOptionsCreator = (helpers: RuleOptionHelpers) => JSONSchemaProps[]; | ||
/** | ||
* An object of helper functions for creating the different types of option schemas. | ||
*/ | ||
export declare type RuleOptionHelpers = { | ||
@@ -223,3 +504,6 @@ numberOption: NumberOptionCreator; | ||
}; | ||
/** | ||
* Combines a set of JSON Schema `properties` objects into a single valid JSON Schema. | ||
*/ | ||
export declare type RuleOptionSchemaCreator = (ops: JSONSchemaProps[]) => JSONSchema7; | ||
//# sourceMappingURL=types.d.ts.map |
@@ -5,2 +5,5 @@ "use strict"; | ||
exports.FileFormat = sketch_file_format_ts_1.FileFormat3; | ||
/** | ||
* Define the possible violation severity levels. | ||
*/ | ||
var ViolationSeverity; | ||
@@ -12,2 +15,5 @@ (function (ViolationSeverity) { | ||
})(ViolationSeverity = exports.ViolationSeverity || (exports.ViolationSeverity = {})); | ||
/** | ||
* Custom rule options with these names are forbidden. | ||
*/ | ||
var ReservedRuleOptionNames; | ||
@@ -14,0 +20,0 @@ (function (ReservedRuleOptionNames) { |
import Ajv from 'ajv'; | ||
import { AssistantConfig, Maybe, RuleConfig, ViolationSeverity, RuleDefinition } from '../types'; | ||
/** | ||
* Get rule configuration from an assistant config. | ||
*/ | ||
declare const getRuleConfig: (config: AssistantConfig, ruleName: string) => Maybe<RuleConfig>; | ||
/** | ||
* Determine if the rule has been mentioned in a given config. | ||
*/ | ||
declare const isRuleConfigured: (config: AssistantConfig, ruleName: string) => boolean; | ||
/** | ||
* Get the value of a specific rule option. | ||
*/ | ||
declare const getRuleOption: (config: AssistantConfig, ruleName: string, optionKey: string) => Maybe<import("../types").RuleOption>; | ||
/** | ||
* Validate a rule's options in a config object according to the schema defined | ||
* on the rule module. | ||
*/ | ||
declare const isRuleConfigValid: (config: AssistantConfig, rule: RuleDefinition) => true | Ajv.ErrorObject[]; | ||
/** | ||
* Determine if a rule is active. An active rule must both be mentioned in the | ||
* config and have its `active` option set to `true`. | ||
*/ | ||
declare const isRuleActive: (config: AssistantConfig, ruleName: string) => boolean; | ||
/** | ||
* Determine a rule's severity, falling back to default values if not specified. | ||
*/ | ||
declare const getRuleSeverity: (config: AssistantConfig, ruleName: string) => ViolationSeverity; | ||
/** | ||
* Determine a rule's ignore classes. | ||
*/ | ||
declare const getRuleIgnoreClasses: (config: AssistantConfig, ruleName: string) => string[]; | ||
/** | ||
* Determine a rule's ignore name patterns. | ||
*/ | ||
declare const getRuleIgnoreNamePathPatterns: (config: AssistantConfig, ruleName: string) => RegExp[]; | ||
export { getRuleConfig, getRuleOption, isRuleConfigured, isRuleActive, getRuleSeverity, isRuleConfigValid, getRuleIgnoreClasses, getRuleIgnoreNamePathPatterns, }; | ||
//# sourceMappingURL=index.d.ts.map |
import Ajv from 'ajv'; | ||
import { ViolationSeverity } from '../types'; | ||
import { helpers, buildRuleOptionSchema } from '../rule-option-schemas'; | ||
/** | ||
* Get rule configuration from an assistant config. | ||
*/ | ||
const getRuleConfig = (config, ruleName) => config.rules[ruleName]; | ||
/** | ||
* Determine if the rule has been mentioned in a given config. | ||
*/ | ||
const isRuleConfigured = (config, ruleName) => !!getRuleConfig(config, ruleName); | ||
/** | ||
* Get the value of a specific rule option. | ||
*/ | ||
const getRuleOption = (config, ruleName, optionKey) => { | ||
@@ -10,4 +19,9 @@ const ruleConfig = getRuleConfig(config, ruleName); | ||
}; | ||
/** | ||
* Validate a rule's options in a config object according to the schema defined | ||
* on the rule module. | ||
*/ | ||
const isRuleConfigValid = (config, rule) => { | ||
if (typeof rule.getOptions === 'undefined') { | ||
// If the rule hasn't defined an options schema we can't validate it | ||
return true; | ||
@@ -21,2 +35,6 @@ } | ||
}; | ||
/** | ||
* Determine if a rule is active. An active rule must both be mentioned in the | ||
* config and have its `active` option set to `true`. | ||
*/ | ||
const isRuleActive = (config, ruleName) => { | ||
@@ -26,2 +44,5 @@ const active = getRuleOption(config, ruleName, 'active'); | ||
}; | ||
/** | ||
* Determine a rule's severity, falling back to default values if not specified. | ||
*/ | ||
const getRuleSeverity = (config, ruleName) => { | ||
@@ -38,2 +59,5 @@ const severity = getRuleOption(config, ruleName, 'severity'); | ||
}; | ||
/** | ||
* Determine a rule's ignore classes. | ||
*/ | ||
const getRuleIgnoreClasses = (config, ruleName) => { | ||
@@ -51,2 +75,5 @@ const rawValues = getRuleOption(config, ruleName, 'ignoreClasses'); | ||
}; | ||
/** | ||
* Determine a rule's ignore name patterns. | ||
*/ | ||
const getRuleIgnoreNamePathPatterns = (config, ruleName) => { | ||
@@ -53,0 +80,0 @@ const rawValues = getRuleOption(config, ruleName, 'ignoreNames'); |
import { AssistantDefinition, Assistant, AssistantEnv, Maybe, RuleDefinition, ESModuleInterop } from '../types'; | ||
/** | ||
* Merge assistant definitions together to form a single assistant definition, with a syntax similar | ||
* to Object.assign(). Assistants are merged from the right-most argument to the left into | ||
* preceeding arguments, according to the following algorithm: | ||
* | ||
* 1. Primitive metadata values like `title` and `description` from the right-most assistant | ||
* override the values from the next assistant to the left | ||
* 2. Rule configuration objects are merged together, with values from right-most assistants | ||
* overriding those from the next assistant to the left | ||
* 3. Assistant rule function arrays are concatenated | ||
* | ||
* @param sources Assistant definitions to merge | ||
*/ | ||
declare const assign: (...sources: AssistantDefinition[]) => AssistantDefinition; | ||
/** | ||
* Prepare an assistant. That is, un-roll its exported value into a flat list of assistant functions, | ||
* invoke and await them to obtain a flat list of concrete assistant definitions which is then merged | ||
* to form a final/single assistant definition. | ||
* | ||
* Assistant preparation is performed at runtime by an assistant runner. | ||
* | ||
* @param source The assistant package to prepare | ||
* @param context The env within which the assistant package is being prepared | ||
*/ | ||
declare const prepare: (source: import("../types").ValueOrArray<Assistant | ESModuleInterop<Assistant>>, env: AssistantEnv) => Promise<AssistantDefinition>; | ||
/** | ||
* Lookup a rule definition by rule name. | ||
*/ | ||
declare const getRuleDefinition: (assistant: AssistantDefinition, ruleName: string) => Maybe<RuleDefinition>; | ||
export { prepare, assign, getRuleDefinition }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -10,2 +10,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
}; | ||
/** | ||
* Merge assistant definitions together to form a single assistant definition, with a syntax similar | ||
* to Object.assign(). Assistants are merged from the right-most argument to the left into | ||
* preceeding arguments, according to the following algorithm: | ||
* | ||
* 1. Primitive metadata values like `title` and `description` from the right-most assistant | ||
* override the values from the next assistant to the left | ||
* 2. Rule configuration objects are merged together, with values from right-most assistants | ||
* overriding those from the next assistant to the left | ||
* 3. Assistant rule function arrays are concatenated | ||
* | ||
* @param sources Assistant definitions to merge | ||
*/ | ||
const assign = (...sources) => { | ||
@@ -24,2 +37,12 @@ return sources.reduceRight((acc, curr) => { | ||
}; | ||
/** | ||
* Prepare an assistant. That is, un-roll its exported value into a flat list of assistant functions, | ||
* invoke and await them to obtain a flat list of concrete assistant definitions which is then merged | ||
* to form a final/single assistant definition. | ||
* | ||
* Assistant preparation is performed at runtime by an assistant runner. | ||
* | ||
* @param source The assistant package to prepare | ||
* @param context The env within which the assistant package is being prepared | ||
*/ | ||
const prepare = (source, env) => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -39,4 +62,7 @@ const definitions = yield Promise.all((Array.isArray(source) ? source : [source]) | ||
}); | ||
/** | ||
* Lookup a rule definition by rule name. | ||
*/ | ||
const getRuleDefinition = (assistant, ruleName) => assistant.rules.find(rule => rule.name === ruleName); | ||
export { prepare, assign, getRuleDefinition }; | ||
//# sourceMappingURL=index.js.map |
import { NodeCache, NodeCacheIterator, RunOperation } from '../types'; | ||
/** | ||
* Create a Sketch file cache iterator, a function that iterators across objects | ||
* in the cache, and calls visitor callback functions for them if defined. | ||
*/ | ||
declare const createCacheIterator: (cache: NodeCache, operation: RunOperation) => NodeCacheIterator; | ||
/** | ||
* Return the minimal/empty cache object. | ||
*/ | ||
declare const createCache: () => NodeCache; | ||
export { createCacheIterator, createCache }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -10,2 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
}; | ||
/** | ||
* Create a Sketch file cache iterator, a function that iterators across objects | ||
* in the cache, and calls visitor callback functions for them if defined. | ||
*/ | ||
const createCacheIterator = (cache, operation) => (config) => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -26,2 +30,5 @@ for (const key of Object.keys(config)) { | ||
}); | ||
/** | ||
* Return the minimal/empty cache object. | ||
*/ | ||
const createCache = () => ({ | ||
@@ -28,0 +35,0 @@ $layers: [], |
import { SketchFile } from '../types'; | ||
/** | ||
* Given a path to a Sketch file on the file system, this function unzips the | ||
* JSON entries and parses them out into a SketchFile object. | ||
*/ | ||
declare const fromFile: (filepath: string) => Promise<SketchFile>; | ||
export { fromFile }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -11,2 +11,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
import StreamZip from 'node-stream-zip'; | ||
/** | ||
* Given a path to a Sketch file on the file system, this function unzips the | ||
* JSON entries and parses them out into a SketchFile object. | ||
*/ | ||
const fromFile = (filepath) => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -13,0 +17,0 @@ const archive = new StreamZip({ |
import { GetImageMetadata } from '../types'; | ||
/** | ||
* Efficiently access image metadata from a zipped Sketch document. Streams | ||
* the image from the zip, and returns as soon as the image dimensions are | ||
* parsed from the header chunks. | ||
*/ | ||
declare const getImageMetadata: GetImageMetadata; | ||
export { getImageMetadata }; | ||
//# sourceMappingURL=index.d.ts.map |
import NodeStreamZip from 'node-stream-zip'; | ||
import probeImageSize from 'probe-image-size'; | ||
/** | ||
* Efficiently access image metadata from a zipped Sketch document. Streams | ||
* the image from the zip, and returns as soon as the image dimensions are | ||
* parsed from the header chunks. | ||
*/ | ||
const getImageMetadata = (ref, filepath) => new Promise((resolve, reject) => { | ||
@@ -4,0 +9,0 @@ const zip = new NodeStreamZip({ file: filepath, storeEntries: true }); |
import { Node, FileFormat } from '../types'; | ||
/** | ||
* Convert a Sketch file-walking Node to a specific file format object. Use this | ||
* to hint the TypeScript compiler which object type you're currently working | ||
* with. Usage, | ||
* | ||
* const artboard = nodeToObj<FileFormat.Artboard>(node) | ||
*/ | ||
declare const nodeToObject: <T extends FileFormat.AnyObject>(node: Node<FileFormat.AnyObject>) => T; | ||
/** | ||
* Return the md5 hash of an object. Keys are deeply sorted for a stable hash. | ||
* Useful for comparing deep similarity of Sketch document objects. | ||
*/ | ||
declare const objectHash: (obj: {}, excludeKeys?: string[]) => string; | ||
/** | ||
* Compares two objects for deep equality. | ||
*/ | ||
declare const objectsEqual: (o1: {}, o2: {}, excludeKeys?: string[]) => boolean; | ||
export { nodeToObject, objectHash, objectsEqual }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -13,2 +13,9 @@ var __rest = (this && this.__rest) || function (s, e) { | ||
import hash from 'object-hash'; | ||
/** | ||
* Convert a Sketch file-walking Node to a specific file format object. Use this | ||
* to hint the TypeScript compiler which object type you're currently working | ||
* with. Usage, | ||
* | ||
* const artboard = nodeToObj<FileFormat.Artboard>(node) | ||
*/ | ||
const nodeToObject = (node) => { | ||
@@ -18,2 +25,6 @@ const { $pointer: _$pointer } = node, obj = __rest(node, ["$pointer"]); | ||
}; | ||
/** | ||
* Return the md5 hash of an object. Keys are deeply sorted for a stable hash. | ||
* Useful for comparing deep similarity of Sketch document objects. | ||
*/ | ||
const objectHash = (obj, excludeKeys = []) => hash(obj, { | ||
@@ -24,4 +35,7 @@ unorderedObjects: true, | ||
}); | ||
/** | ||
* Compares two objects for deep equality. | ||
*/ | ||
const objectsEqual = (o1, o2, excludeKeys = []) => objectHash(o1, excludeKeys) === objectHash(o2, excludeKeys); | ||
export { nodeToObject, objectHash, objectsEqual }; | ||
//# sourceMappingURL=index.js.map |
import { Maybe, PointerValue, FileFormat } from '../types'; | ||
/** | ||
* Resolve a JSON Pointer to a value within a SketchFile. | ||
*/ | ||
declare const get: (pointer: string, instance: FileFormat.Contents) => Maybe<PointerValue>; | ||
/** | ||
* Resolve the parent of a JSON Pointer to a value within a SketchFile. | ||
*/ | ||
declare const parent: (pointer: string, instance: FileFormat.Contents) => Maybe<PointerValue>; | ||
export { get, parent }; | ||
//# sourceMappingURL=index.d.ts.map |
import Ptr from '@json-schema-spec/json-pointer'; | ||
/** | ||
* Resolve a JSON Pointer to a value within a SketchFile. | ||
*/ | ||
const get = (pointer, instance) => { | ||
@@ -11,2 +14,5 @@ try { | ||
}; | ||
/** | ||
* Resolve the parent of a JSON Pointer to a value within a SketchFile. | ||
*/ | ||
const parent = (pointer, instance) => { | ||
@@ -13,0 +19,0 @@ try { |
import { RunOperation, ProcessedSketchFile, SketchFile } from '../types'; | ||
/** | ||
* Recursively prepare Sketch document data in preparation for performing a lint | ||
* run. In practice this means performing two things: | ||
* | ||
* 1. Augmenting each object in the document data with an RFC 6901 compliant | ||
* JSON Pointer string on the `$pointer` key, unlikely to clash with other | ||
* object keys. The pointer values enable objects to indicate their location | ||
* in the document structure, even when observed in isolation, for example | ||
* in a lint rule. | ||
* 2. Populating a minimal cache of Sketch document objects keyed by their | ||
* `_class` prop values, for efficient access and iteration in rule logic. | ||
*/ | ||
declare const process: (file: SketchFile, op: RunOperation) => Promise<ProcessedSketchFile>; | ||
export { process }; | ||
//# sourceMappingURL=index.d.ts.map |
import { createCache } from '../file-cache'; | ||
const DO_NOT_PROCESS_KEYS = ['foreignLayerStyles', 'foreignSymbols', 'foreignTextStyles']; | ||
const processNode = (input, cache, op, pointer) => { | ||
// Bail early if we've been passed a falsey value or the operation is cancelled | ||
if (!input || op.cancelled) | ||
return; | ||
// Bail early if input is not an object | ||
if (typeof input !== 'object') | ||
return; | ||
// Inject the current pointer value | ||
input.$pointer = pointer; | ||
// Test to see if we've been passed an array and if so process each element | ||
// recursively and return | ||
if (input.constructor === Array) { | ||
@@ -18,8 +23,15 @@ const array = input; | ||
for (const key in input) { | ||
// Bail out of this loop iteration early if the key has been excluded | ||
// from processing | ||
if (DO_NOT_PROCESS_KEYS.includes(key)) | ||
continue; | ||
// If the current object has a `_class` prop it means the object should | ||
// be cached in the NodeCache | ||
if (key === '_class') { | ||
if (!cache[obj._class]) | ||
cache[obj._class] = []; | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
cache[obj._class].push(obj); | ||
// Use presence of `layers` and `frame` props as heuristics to identify | ||
// objects with group and layer traits respectively | ||
if ('layers' in obj) | ||
@@ -30,5 +42,18 @@ cache.$groups.push(obj); | ||
} | ||
// Recurse into the input's sub values | ||
processNode(obj[key], cache, op, `${pointer}/${key}`); | ||
} | ||
}; | ||
/** | ||
* Recursively prepare Sketch document data in preparation for performing a lint | ||
* run. In practice this means performing two things: | ||
* | ||
* 1. Augmenting each object in the document data with an RFC 6901 compliant | ||
* JSON Pointer string on the `$pointer` key, unlikely to clash with other | ||
* object keys. The pointer values enable objects to indicate their location | ||
* in the document structure, even when observed in isolation, for example | ||
* in a lint rule. | ||
* 2. Populating a minimal cache of Sketch document objects keyed by their | ||
* `_class` prop values, for efficient access and iteration in rule logic. | ||
*/ | ||
const process = (file, op) => { | ||
@@ -35,0 +60,0 @@ const cache = createCache(); |
import { RuleOptionSchemaCreator, RuleOptionHelpers } from '../types'; | ||
/** | ||
* Combine multiple rule option schemas into one. We treat _all_ custom options | ||
* as required. | ||
*/ | ||
declare const buildRuleOptionSchema: RuleOptionSchemaCreator; | ||
@@ -3,0 +7,0 @@ declare const helpers: RuleOptionHelpers; |
@@ -15,2 +15,6 @@ import { ReservedRuleOptionNames, } from '../types'; | ||
} | ||
/** | ||
* Combine multiple rule option schemas into one. We treat _all_ custom options | ||
* as required. | ||
*/ | ||
const buildRuleOptionSchema = ops => ({ | ||
@@ -21,2 +25,5 @@ type: 'object', | ||
}); | ||
/** | ||
* Create a floating point number option. | ||
*/ | ||
const numberOption = ops => { | ||
@@ -28,2 +35,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create an integer option. | ||
*/ | ||
const integerOption = ops => { | ||
@@ -35,2 +45,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create a string option. | ||
*/ | ||
const stringOption = ops => { | ||
@@ -42,2 +55,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create a boolean option. | ||
*/ | ||
const booleanOption = ops => { | ||
@@ -54,2 +70,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create a string option limited to a set of values. | ||
*/ | ||
const stringEnumOption = ops => { | ||
@@ -68,2 +87,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create a string list option. | ||
*/ | ||
const stringArrayOption = ops => { | ||
@@ -81,2 +103,5 @@ assertOptionNameNotReserved(ops.name); | ||
}; | ||
/** | ||
* Create an object list option. | ||
*/ | ||
const objectArrayOption = ops => { | ||
@@ -83,0 +108,0 @@ assertOptionNameNotReserved(ops.name); |
import { Violation, RunOperation, RuleUtilsCreator, GetImageMetadata, AssistantDefinition, ProcessedSketchFile } from '../types'; | ||
/** | ||
* Returns a RuleUtilsCreator function, which can be used to build util objects | ||
* scoped to a specific rule. | ||
*/ | ||
declare const createRuleUtilsCreator: (processedFile: ProcessedSketchFile, violations: Violation[], assistant: AssistantDefinition, operation: RunOperation, getImageMetadata: GetImageMetadata) => RuleUtilsCreator; | ||
export { createRuleUtilsCreator }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -26,2 +26,7 @@ import mem from 'mem'; | ||
} | ||
/** | ||
* Add one or more report items into a violations array. Reports from rules just contain a message | ||
* and optionally a Node, whereas violations container richer contextual information therefore this | ||
* function maps the former to the latter. | ||
*/ | ||
const addReportsToViolations = (report, violations, assistant, rule, iterateParents) => { | ||
@@ -36,5 +41,7 @@ if (Array.isArray(report) && report.length === 0) | ||
violations.push(...(Array.isArray(report) ? report : [report]) | ||
// Filter out reports involving nodes with ignored `_class` props | ||
.filter(item => { | ||
return item.node ? !classesToIgnore.includes(item.node._class) : true; | ||
}) | ||
// Filter out nodes with ignored name paths | ||
.filter(item => { | ||
@@ -55,13 +62,4 @@ if (!item.node || namesToIgnore.length === 0) | ||
return { | ||
assistant: { | ||
title: assistant.title, | ||
name: assistant.name, | ||
description: assistant.description, | ||
}, | ||
rule: { | ||
title: rule.title, | ||
name: rule.name, | ||
description: rule.description, | ||
debug: rule.debug, | ||
}, | ||
assistantName: assistant.name, | ||
ruleName: rule.name, | ||
message: item.message, | ||
@@ -78,2 +76,8 @@ severity, | ||
}; | ||
/** | ||
* Creates a function that rules can use to get an option value by `name`. All rules need to do is | ||
* pass the option `name`, all other values are already in scope. A InvalidRuleConfigError is thrown | ||
* if rules attempt to access missing options, or options that are invalid according to the rule's | ||
* self-declared option schema. | ||
*/ | ||
const createOptionGetter = (assistant, rule) => (optionKey) => { | ||
@@ -100,2 +104,5 @@ const result = isRuleConfigValid(assistant.config, rule); | ||
}; | ||
/** | ||
* Create a parent iterator function scoped to a Sketch file. | ||
*/ | ||
const createParentIterator = (file) => (node, callback) => { | ||
@@ -117,2 +124,6 @@ if (!node) | ||
}; | ||
/** | ||
* Returns a RuleUtilsCreator function, which can be used to build util objects | ||
* scoped to a specific rule. | ||
*/ | ||
const createRuleUtilsCreator = (processedFile, violations, assistant, operation, getImageMetadata) => { | ||
@@ -119,0 +130,0 @@ const { file, cache } = processedFile; |
@@ -8,4 +8,7 @@ import { AssistantDefinition, ProcessedSketchFile, AssistantEnv, RunOperation, GetImageMetadata, RunResult } from '../types'; | ||
} | ||
/** | ||
* Run an assistant, catching and returning any errors encountered during rule invocation. | ||
*/ | ||
declare const runAssistant: (file: ProcessedSketchFile, assistant: AssistantDefinition, env: AssistantEnv, operation: RunOperation, getImageMetadata: GetImageMetadata) => Promise<RunResult>; | ||
export { runAssistant, RuleInvocationError }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -23,2 +23,5 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
} | ||
/** | ||
* Run an assistant, catching and returning any errors encountered during rule invocation. | ||
*/ | ||
const runAssistant = (file, assistant, env, operation, getImageMetadata) => __awaiter(void 0, void 0, void 0, function* () { | ||
@@ -34,4 +37,23 @@ const violations = []; | ||
}; | ||
const activeRules = assistant.rules | ||
.filter(rule => isRuleActive(assistant.config, rule.name)) // Rule turned on in config | ||
.filter(rule => (rule.platform ? rule.platform === env.platform : true)); // Rule platform is supported | ||
const metadata = { | ||
assistant: { | ||
title: assistant.title, | ||
description: assistant.description, | ||
name: assistant.name, | ||
config: assistant.config, | ||
}, | ||
rules: activeRules.reduce((acc, curr) => { | ||
return Object.assign(Object.assign({}, acc), { [curr.name]: { | ||
title: curr.title, | ||
description: curr.description, | ||
debug: curr.debug, | ||
platform: curr.platform, | ||
} }); | ||
}, {}), | ||
}; | ||
try { | ||
yield pMap(assistant.rules.filter(rule => isRuleActive(assistant.config, rule.name)), (rule) => __awaiter(void 0, void 0, void 0, function* () { | ||
yield pMap(activeRules, (rule) => __awaiter(void 0, void 0, void 0, function* () { | ||
if (operation.cancelled) | ||
@@ -53,2 +75,3 @@ return; | ||
errors: Array.from(error), | ||
metadata, | ||
}; | ||
@@ -59,2 +82,3 @@ } | ||
errors: [], | ||
metadata, | ||
}; | ||
@@ -61,0 +85,0 @@ }); |
import { FileFormat, Assistant, RuleOptionsCreator, RuleFunction, RuleDefinition, AssistantDefinition, AssistantConfig, ViolationSeverity, RuleConfigGroup, AssistantEnv, RunResult } from '../types'; | ||
declare const createRule: ({ title, description, rule, getOptions, name, debug, }?: { | ||
/** | ||
* Create a dummy rule definition. | ||
*/ | ||
declare const createRule: ({ title, description, rule, getOptions, name, debug, platform, }?: { | ||
title?: string | undefined; | ||
@@ -9,3 +12,7 @@ description?: string | undefined; | ||
debug?: boolean | undefined; | ||
platform?: "sketch" | "node" | undefined; | ||
}) => RuleDefinition; | ||
/** | ||
* Create a dummy assistant configuration. | ||
*/ | ||
declare const createAssistantConfig: ({ rules, defaultSeverity, }?: { | ||
@@ -15,2 +22,5 @@ rules?: RuleConfigGroup | undefined; | ||
}) => AssistantConfig; | ||
/** | ||
* Create a dummy assistant definition. | ||
*/ | ||
declare const createAssistantDefinition: ({ title, description, name, config, rules, }?: { | ||
@@ -23,2 +33,5 @@ title?: string | undefined; | ||
}) => AssistantDefinition; | ||
/** | ||
* Create a dummy assistant function. | ||
*/ | ||
declare const createAssistant: ({ title, description, name, config, rules, }?: { | ||
@@ -34,4 +47,8 @@ title?: string | undefined; | ||
}; | ||
export declare const testRule: (filepath: string, configGroup: RuleConfigGroup, assistant: Assistant, env?: AssistantEnv) => Promise<RunResult>; | ||
/** | ||
* Test an individual rule within the context of a specific assistant. The assistant has its config | ||
* overwritten by the passed in value to enable testing rules in isolation. | ||
*/ | ||
export declare const testRule: (filepath: string, ruleConfig: RuleConfigGroup, assistant: Assistant, env?: AssistantEnv) => Promise<RunResult>; | ||
export { createRule, createDummyRectNode, createAssistantConfig, createAssistant, createAssistantDefinition, }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -15,3 +15,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
import { getImageMetadata } from '../get-image-metadata'; | ||
const createRule = ({ title, description, rule, getOptions, name, debug, } = {}) => ({ | ||
/** | ||
* Create a dummy rule definition. | ||
*/ | ||
const createRule = ({ title, description, rule, getOptions, name, debug, platform, } = {}) => ({ | ||
name: name !== null && name !== void 0 ? name : 'dummy-assistant/dummy-rule', | ||
@@ -23,4 +26,11 @@ title: title !== null && title !== void 0 ? title : 'Dummy Rule', | ||
debug, | ||
platform: platform !== null && platform !== void 0 ? platform : 'node', | ||
}); | ||
/** | ||
* Create a dummy assistant configuration. | ||
*/ | ||
const createAssistantConfig = ({ rules, defaultSeverity, } = {}) => (Object.assign(Object.assign({}, (typeof defaultSeverity === 'undefined' ? {} : { defaultSeverity })), { rules: rules || {} })); | ||
/** | ||
* Create a dummy assistant definition. | ||
*/ | ||
const createAssistantDefinition = ({ title, description, name, config, rules, } = {}) => ({ | ||
@@ -33,2 +43,5 @@ title: title !== null && title !== void 0 ? title : 'Dummy Assistant', | ||
}); | ||
/** | ||
* Create a dummy assistant function. | ||
*/ | ||
const createAssistant = ({ title, description, name, config, rules, } = {}) => () => __awaiter(void 0, void 0, void 0, function* () { return createAssistantDefinition({ title, description, name, config, rules }); }); | ||
@@ -44,19 +57,14 @@ const createDummyRectNode = () => ({ | ||
}); | ||
export const testRule = (filepath, configGroup, assistant, env = { locale: 'en', platform: 'node' }) => __awaiter(void 0, void 0, void 0, function* () { | ||
/** | ||
* Test an individual rule within the context of a specific assistant. The assistant has its config | ||
* overwritten by the passed in value to enable testing rules in isolation. | ||
*/ | ||
export const testRule = (filepath, ruleConfig, assistant, env = { locale: 'en', platform: 'node' }) => __awaiter(void 0, void 0, void 0, function* () { | ||
const file = yield fromFile(filepath); | ||
const op = { cancelled: false }; | ||
const processedFile = yield process(file, op); | ||
const TestAssistant = [ | ||
assistant, | ||
() => __awaiter(void 0, void 0, void 0, function* () { | ||
return ({ | ||
name: '', | ||
description: '', | ||
title: '', | ||
rules: [], | ||
config: { rules: Object.assign({}, configGroup) }, | ||
}); | ||
}), | ||
]; | ||
const assistantDefinition = yield prepare(TestAssistant, env); | ||
const assistantDefinition = yield prepare(assistant, env); | ||
assistantDefinition.config = { | ||
rules: ruleConfig, | ||
}; | ||
return yield runAssistant(processedFile, assistantDefinition, env, op, getImageMetadata); | ||
@@ -63,0 +71,0 @@ }); |
import { FileFormat3 } from '@sketch-hq/sketch-file-format-ts'; | ||
import { JSONSchema7 } from 'json-schema'; | ||
/** | ||
* Re-export the specific version of the file format supported by this package. | ||
*/ | ||
export { FileFormat3 as FileFormat }; | ||
/** | ||
* Optional value. | ||
*/ | ||
export declare type Maybe<T> = T | undefined | null; | ||
/** | ||
* All possible string values for the `_class` property in Sketch files. | ||
*/ | ||
export declare type SketchClass = FileFormat3.AnyObject['_class']; | ||
/** | ||
* Utility function for gathering metadata about Sketch file images. Is isomorphic in the sense that | ||
* its signature shound't change across platforms. | ||
*/ | ||
export declare type GetImageMetadata = (ref: string, filepath: string) => Promise<ImageMetadata>; | ||
/** | ||
* When rules request metadata for a Sketch file image it is returned in this format. | ||
*/ | ||
export declare type ImageMetadata = { | ||
@@ -12,2 +28,6 @@ width: number; | ||
}; | ||
/** | ||
* Represents a Sketch file that is on disk. Collates the filepath with an object | ||
* typed as Contents from the file format. | ||
*/ | ||
export declare type SketchFile = { | ||
@@ -17,15 +37,43 @@ filepath: string; | ||
}; | ||
/** | ||
* Value or arbitrarily nested array of values. | ||
*/ | ||
export declare type ValueOrArray<T> = T | Array<ValueOrArray<T>>; | ||
/** | ||
* Union of all possible objects with a `_class` value that can be found in a Sketch | ||
* file, injected with a JSON Pointer during file processing. | ||
*/ | ||
export declare type Node<T = FileFormat3.AnyObject> = T & { | ||
$pointer: string; | ||
}; | ||
/** | ||
* Array of Nodes. An concrete example of this in a Sketch file is a group's `layers` array. | ||
*/ | ||
export interface NodeArray extends Array<Node> { | ||
$pointer: string; | ||
} | ||
/** | ||
* All possible Node and primitive values that a JSON Pointer can resolve to in a Sketch file. | ||
*/ | ||
export declare type PointerValue = Node | NodeArray | Node<FileFormat3.Contents> | Node<FileFormat3.Contents['document']> | Node<FileFormat3.Contents['meta']> | Node<FileFormat3.Contents['user']> | string | number | boolean; | ||
/** | ||
* Rule-supplied function called during cache iteration. Rules will typically use these while | ||
* scanning a Sketch file for relevant objects and checking the values against their logic. | ||
*/ | ||
export declare type NodeCacheVisitor = (data: Node) => Promise<void>; | ||
/** | ||
* Rules supply a cache iterator config to register vistor functions against the specific object | ||
* types available in the cache. | ||
*/ | ||
export declare type NodeCacheIteratorConfig = { | ||
[key in keyof NodeCache]?: NodeCacheVisitor; | ||
}; | ||
/** | ||
* A function that iterates a cache using a cache iteration config. | ||
*/ | ||
export declare type NodeCacheIterator = (config: NodeCacheIteratorConfig) => Promise<void>; | ||
/** | ||
* A cache of Sketch file Nodes keyed by `_class` values. The special `$layers` key collates all | ||
* layer Nodes, and the `$groups` key collates all layer Nodes that are also groups. | ||
*/ | ||
export declare type NodeCache = { | ||
@@ -37,2 +85,6 @@ $layers: Node[]; | ||
}; | ||
/** | ||
* A processed Sketch file is one that has has had its objects cached into a NodeCache, and JSON | ||
* Pointers injected. | ||
*/ | ||
export declare type ProcessedSketchFile = { | ||
@@ -42,2 +94,8 @@ cache: NodeCache; | ||
}; | ||
/** | ||
* Contains a flag indicating whether the run operation has been cancelled by | ||
* the outer environment. All long running processes happening during a run | ||
* (like cache creation, rule invocation etc.) should exit early as soon as a | ||
* cancellation is detected. | ||
*/ | ||
export declare type RunOperation = { | ||
@@ -48,6 +106,22 @@ cancelled: boolean; | ||
}; | ||
/** | ||
* The result of running an assistant. One or more `violations` implies the assistant's rules found | ||
* issues with the Sketch document. One or more `errors` implies that some rules didn't run because | ||
* they encountered errors. Metadata (`title`, `description` etc) relating to the Assistant that | ||
* produced the result, and the rules that were invoked is also provided | ||
*/ | ||
export declare type RunResult = { | ||
violations: Violation[]; | ||
errors: Error[]; | ||
metadata: { | ||
assistant: Omit<AssistantDefinition, 'rules'>; | ||
rules: { | ||
[ruleName: string]: Omit<RuleDefinition, 'rule' | 'getOptions' | 'name'>; | ||
}; | ||
}; | ||
}; | ||
/** | ||
* Contains all the values and utils exposed to individual rule functions. The | ||
* values are scoped to the rule itself, to simplify the API surface. | ||
*/ | ||
export declare type RuleContext = { | ||
@@ -61,16 +135,63 @@ utils: RuleUtils; | ||
}; | ||
/** | ||
* Function for creating a rule utilties object scoped to a specific assistant rule. | ||
*/ | ||
export declare type RuleUtilsCreator = (ruleName: string) => RuleUtils; | ||
/** | ||
* A function that when invoked repeatedly calls its callback for each of a Node's parents | ||
* until it reaches the document root, at wich point it stops. | ||
*/ | ||
export declare type ParentIterator = (node: Maybe<PointerValue>, callback: (target: Node | NodeArray | Node<FileFormat3.Contents['document']>) => void) => void; | ||
/** | ||
* Object contain utilties to be used within rule functions. | ||
*/ | ||
export declare type RuleUtils = { | ||
/** | ||
* Report one or more violations. | ||
*/ | ||
report: (report: ReportItem | ReportItem[]) => void; | ||
/** | ||
* Iterate the Sketch file object cache. | ||
*/ | ||
iterateCache: (config: NodeCacheIteratorConfig) => Promise<void>; | ||
/** | ||
* Iterate back through the Node's parents to the Sketch file root. | ||
*/ | ||
iterateParents: ParentIterator; | ||
/** | ||
* Get a rule option value by name. Throws if the rule hasn't been configured in the assistant. | ||
* It's essential that every rule activated in an assistant is properly configured. | ||
*/ | ||
getOption: (option: string) => Maybe<RuleOption>; | ||
/** | ||
* Returns metadata for a given Sketch file image. | ||
*/ | ||
getImageMetadata: (ref: string) => Promise<ImageMetadata>; | ||
/** | ||
* Converts a Node to the original file format type. | ||
*/ | ||
nodeToObject: <T extends FileFormat3.AnyObject>(node: Node) => T; | ||
/** | ||
* Return the md5 hash of an object. Keys are deeply sorted for a stable hash. | ||
* Useful for comparing deep similarity of Sketch document objects. By default | ||
* the keys `do_objectID` and `$pointer` are excluded since they will always | ||
* be different. | ||
*/ | ||
objectHash: (o: {}, excludeKeys?: string[]) => string; | ||
/** | ||
* Compare two document objects for deep equality. | ||
*/ | ||
objectsEqual: (o1: {}, o2: {}, excludeKeys?: string[]) => boolean; | ||
/** | ||
* Resolve a JSON Pointer to a document object. | ||
*/ | ||
get: (pointer: string) => Maybe<PointerValue>; | ||
/** | ||
* Resolve a JSON Pointer to a document object's parent. | ||
*/ | ||
parent: (pointer: string) => Maybe<PointerValue>; | ||
}; | ||
/** | ||
* Information a rule needs to supply when reporting a violation. | ||
*/ | ||
export declare type ReportItem = { | ||
@@ -80,6 +201,10 @@ message: string; | ||
}; | ||
/** | ||
* A violation collates all the information about a problem, and is the fundamental way an assistant | ||
* communicates results to the outer environment. | ||
*/ | ||
export declare type Violation = { | ||
message: string; | ||
assistant: Omit<AssistantDefinition, 'rules' | 'config'>; | ||
rule: Omit<RuleDefinition, 'rule' | 'getOptions'>; | ||
assistantName: string; | ||
ruleName: string; | ||
severity: ViolationSeverity; | ||
@@ -89,2 +214,5 @@ pointer: string | null; | ||
}; | ||
/** | ||
* Define the possible violation severity levels. | ||
*/ | ||
export declare enum ViolationSeverity { | ||
@@ -95,7 +223,33 @@ info = 1, | ||
} | ||
/** | ||
* Platforms that can run Assistants. | ||
*/ | ||
export declare type Platform = 'sketch' | 'node'; | ||
/** | ||
* Ambient environmental information for assistants, typically provided by an outer assistant runner. | ||
*/ | ||
export declare type AssistantEnv = { | ||
/** | ||
* Language tag indicating the current user's locale. Use this to optionally internationalize your | ||
* assistant's content. Its exact value is not guaranteed, so an appropriate fallback locale should | ||
* always be used for unrecognised values. For assistants running in Sketch it's value is likely | ||
* to be either `en` or `zh-Hans`. | ||
*/ | ||
locale: string | undefined; | ||
platform: 'sketch' | 'node'; | ||
/** | ||
* Indicates whether the assistant is running in either a Node or Sketch (JavaScriptCore) environment | ||
*/ | ||
platform: Platform; | ||
}; | ||
/** | ||
* Canonical definition of an assistant, that is, an async function that given an AssistantEnv | ||
* will resolve with a concrete AssistantDefinition. Assistants therefore are able to defer final | ||
* creation until invoked by a runner, and which point critical contextual information such as the | ||
* locale are available. | ||
*/ | ||
export declare type Assistant = (env: AssistantEnv) => Promise<AssistantDefinition>; | ||
/** | ||
* The shape of an ES Module with a default export built with TypeScript or Babel with ES Module | ||
* interoperability. | ||
*/ | ||
export declare type ESModuleInterop<DefaultExport> = { | ||
@@ -105,25 +259,94 @@ __esModule: true; | ||
}; | ||
/** | ||
* Defines the expected type definition for the export from a 1st or 3rd party assistant package. It | ||
* allows an assistant to be expressed as either a single assistant or an array of assistants that | ||
* should be merged before a run operation. Via type recursion arbitrarily nested arrays of | ||
* assistant functions are supported to allow for incorporation of other assistant packages into | ||
* the final export. | ||
*/ | ||
export declare type AssistantPackageExport = ValueOrArray<Assistant | ESModuleInterop<Assistant>>; | ||
/** | ||
* Concrete assistant definition that can be invoked against a Sketch file during a lint run. | ||
* Fundamentally assistants collate a list of rules with configuration for those rules, alongside | ||
* metadata about the assistant. | ||
*/ | ||
export declare type AssistantDefinition = { | ||
/** | ||
* List of rules owned by the assistant. | ||
*/ | ||
rules: RuleDefinition[]; | ||
/** | ||
* Assistant configuration activates and configures one or more rules present in its rule list. | ||
*/ | ||
config: AssistantConfig; | ||
/** | ||
* Human readable assistant name, e.g. "Grid of 8" | ||
*/ | ||
title: string; | ||
/** | ||
* Longer human readable description for the assistant. | ||
*/ | ||
description: string; | ||
/** | ||
* Assistant name is the same as its package name, i.e. the `name` property in its `package.json`. | ||
*/ | ||
name: string; | ||
}; | ||
/** | ||
* Canonical rule defintion combining the rule function, its option schema creator with other | ||
* basic metadata. | ||
*/ | ||
export declare type RuleDefinition = { | ||
rule: RuleFunction; | ||
/** | ||
* The rule name acts as its id and should combine an identifier for the rule with the parent | ||
* assistant's name separated by a slash, e.g. | ||
* "@sketch-hq/sketch-assistant-recommended/groups-max-layers" | ||
*/ | ||
name: string; | ||
/** | ||
* Human readable title for the rule, e.g. "Groups Max Layers". | ||
*/ | ||
title: string; | ||
/** | ||
* Longer human readable description for the rule. | ||
*/ | ||
description: string; | ||
/** | ||
* Rules that require options (i.e. are not just simply "on" or "off") need to describe the schema | ||
* for those options by implementing this function | ||
*/ | ||
getOptions?: RuleOptionsCreator; | ||
/** | ||
* Flags a rule as for internal/development purposes only | ||
*/ | ||
debug?: boolean; | ||
/** | ||
* Indicates rule platform compatibility. For cross-platform rules this property can be omitted. | ||
*/ | ||
platform?: Platform; | ||
}; | ||
/** | ||
* A map of rule configs, keyed by the rule's name. | ||
*/ | ||
export declare type RuleConfigGroup = { | ||
[ruleName: string]: Maybe<RuleConfig>; | ||
}; | ||
/** | ||
* Contains the assistant configuration. | ||
*/ | ||
export declare type AssistantConfig = { | ||
/** | ||
* Default severity to be used for violations raised by rules that haven't been configured with | ||
* their own explicit severity level. | ||
*/ | ||
defaultSeverity?: Maybe<ViolationSeverity>; | ||
/** | ||
* Configuration to be applied to the rules available to the assistant. | ||
*/ | ||
rules: RuleConfigGroup; | ||
}; | ||
/** | ||
* Custom rule options with these names are forbidden. | ||
*/ | ||
export declare enum ReservedRuleOptionNames { | ||
@@ -135,16 +358,50 @@ active = "active", | ||
} | ||
/** | ||
* Contains the configuration for an individual rule. | ||
*/ | ||
export declare type RuleConfig = { | ||
/** | ||
* Whether the rule is active or not. Alternatively omitting the rule from the assistant config is | ||
* the same as setting this flag to `false`. | ||
*/ | ||
[ReservedRuleOptionNames.active]: boolean; | ||
/** | ||
* The severity of any violations reported by the rule. | ||
*/ | ||
[ReservedRuleOptionNames.severity]?: ViolationSeverity; | ||
/** | ||
* Violations associated with Nodes with `_class` values listed here will be filtered out of the | ||
* final result set. | ||
*/ | ||
[ReservedRuleOptionNames.ignoreClasses]?: SketchClass[]; | ||
/** | ||
* Violations associated with Nodes with name paths that match the regexes listed here will be | ||
* filtered out of the final result set. | ||
*/ | ||
[ReservedRuleOptionNames.ignoreNames]?: string[]; | ||
/** | ||
* Rule custom options will also appear mixed into this object. | ||
*/ | ||
[key: string]: Maybe<RuleOption>; | ||
}; | ||
/** | ||
* The valid set of types available for individual rule options. | ||
*/ | ||
export declare type RuleOption = string | number | boolean | string[] | { | ||
[key: string]: Maybe<string | number | boolean | string[]>; | ||
}[]; | ||
/** | ||
* Async function that is expected to perform the core rule logic using the values and helper | ||
* functions provided by the passed in RuleInvocationContext object. | ||
*/ | ||
export declare type RuleFunction = (context: RuleContext) => Promise<void>; | ||
/** | ||
* JSONSchema `properties` value. | ||
*/ | ||
export declare type JSONSchemaProps = { | ||
[key: string]: JSONSchema7; | ||
}; | ||
/** | ||
* Creates rule option schema properties for a number option. | ||
*/ | ||
export declare type NumberOptionCreator = (ops: { | ||
@@ -158,2 +415,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for an integer option. | ||
*/ | ||
export declare type IntegerOptionCreator = (ops: { | ||
@@ -167,2 +427,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for a string option. | ||
*/ | ||
export declare type StringOptionCreator = (ops: { | ||
@@ -177,2 +440,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for a boolean option. | ||
*/ | ||
export declare type BoolOptionCreator = (ops: { | ||
@@ -184,2 +450,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for a string enum option. | ||
*/ | ||
export declare type StringEnumOptionCreator = (ops: { | ||
@@ -193,2 +462,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for a string array option. | ||
*/ | ||
export declare type StringArrayOptionCreator = (ops: { | ||
@@ -203,2 +475,5 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* Creates rule option schema properties for an object array option. | ||
*/ | ||
export declare type ObjectArrayOptionCreator = (ops: { | ||
@@ -212,3 +487,9 @@ name: string; | ||
}) => JSONSchemaProps; | ||
/** | ||
* A function that should be implemented on rule definitions if they need to define custom options. | ||
*/ | ||
export declare type RuleOptionsCreator = (helpers: RuleOptionHelpers) => JSONSchemaProps[]; | ||
/** | ||
* An object of helper functions for creating the different types of option schemas. | ||
*/ | ||
export declare type RuleOptionHelpers = { | ||
@@ -223,3 +504,6 @@ numberOption: NumberOptionCreator; | ||
}; | ||
/** | ||
* Combines a set of JSON Schema `properties` objects into a single valid JSON Schema. | ||
*/ | ||
export declare type RuleOptionSchemaCreator = (ops: JSONSchemaProps[]) => JSONSchema7; | ||
//# sourceMappingURL=types.d.ts.map |
import { FileFormat3 } from '@sketch-hq/sketch-file-format-ts'; | ||
// | ||
// Misc | ||
// | ||
/** | ||
* Re-export the specific version of the file format supported by this package. | ||
*/ | ||
export { FileFormat3 as FileFormat }; | ||
/** | ||
* Define the possible violation severity levels. | ||
*/ | ||
export var ViolationSeverity; | ||
@@ -9,2 +18,5 @@ (function (ViolationSeverity) { | ||
})(ViolationSeverity || (ViolationSeverity = {})); | ||
/** | ||
* Custom rule options with these names are forbidden. | ||
*/ | ||
export var ReservedRuleOptionNames; | ||
@@ -11,0 +23,0 @@ (function (ReservedRuleOptionNames) { |
{ | ||
"name": "@sketch-hq/sketch-assistant-utils", | ||
"version": "2.0.3", | ||
"version": "3.0.0", | ||
"module": "dist/esm/index", | ||
@@ -5,0 +5,0 @@ "main": "dist/cjs/index", |
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
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
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
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
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
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
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
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
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
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
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
219101
3281