diff --git a/.eslintrc.yml b/.eslintrc.yml index 34000ab..2ebe71d 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,8 +1,9 @@ # https://eslint.org/docs/rules/ root: true +parser: '@typescript-eslint/parser' parserOptions: - sourceType: script + sourceType: module ecmaVersion: 2018 env: es6: true @@ -10,10 +11,14 @@ env: plugins: - prettier - import + - '@typescript-eslint' +ignorePatterns: + - lib + extends: - - eslint:recommended - - plugin:import/recommended - plugin:prettier/recommended + - plugin:@typescript-eslint/eslint-recommended + rules: # Prettier prettier/prettier: @@ -118,7 +123,7 @@ rules: func-names: - 2 - as-needed - func-style: 2 + func-style: 0 linebreak-style: 2 lines-between-class-members: 2 max-len: diff --git a/.gitignore b/.gitignore index 519a35e..7308a23 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ node_modules/ pkg/* test/.sass-cache/ true-*.gem +.idea diff --git a/lib/constants.d.ts b/lib/constants.d.ts new file mode 100644 index 0000000..0cb5e70 --- /dev/null +++ b/lib/constants.d.ts @@ -0,0 +1,22 @@ +export declare const MODULE_TOKEN = "# Module: "; +export declare const MODULE_NESTING_TOKEN = " :: "; +export declare const SUMMARY_TOKEN = "# SUMMARY "; +export declare const END_SUMMARY_TOKEN = "----------"; +export declare const TEST_TOKEN = "Test: "; +export declare const PASS_TOKEN = "\u2714 "; +export declare const FAIL_TOKEN = "\u2716 FAILED: ["; +export declare const END_FAIL_TOKEN = "]"; +export declare const ASSERT_TOKEN = "ASSERT: "; +export declare const FAILURE_DETAIL_TOKEN = "- "; +export declare const FAILURE_TYPE_START_TOKEN = "["; +export declare const FAILURE_TYPE_END_TOKEN = "]"; +export declare const OUTPUT_TOKEN = "Output: "; +export declare const EXPECTED_TOKEN = "Expected: "; +export declare const DETAILS_SEPARATOR_TOKEN = ": "; +export declare const OUTPUT_START_TOKEN = "OUTPUT"; +export declare const OUTPUT_END_TOKEN = "END_OUTPUT"; +export declare const EXPECTED_START_TOKEN = "EXPECTED"; +export declare const EXPECTED_END_TOKEN = "END_EXPECTED"; +export declare const CONTAINED_START_TOKEN = "CONTAINED"; +export declare const CONTAINED_END_TOKEN = "END_CONTAINED"; +export declare const ASSERT_END_TOKEN = "END_ASSERT"; diff --git a/lib/constants.js b/lib/constants.js new file mode 100644 index 0000000..a4093e8 --- /dev/null +++ b/lib/constants.js @@ -0,0 +1,27 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ASSERT_END_TOKEN = exports.CONTAINED_END_TOKEN = exports.CONTAINED_START_TOKEN = exports.EXPECTED_END_TOKEN = exports.EXPECTED_START_TOKEN = exports.OUTPUT_END_TOKEN = exports.OUTPUT_START_TOKEN = exports.DETAILS_SEPARATOR_TOKEN = exports.EXPECTED_TOKEN = exports.OUTPUT_TOKEN = exports.FAILURE_TYPE_END_TOKEN = exports.FAILURE_TYPE_START_TOKEN = exports.FAILURE_DETAIL_TOKEN = exports.ASSERT_TOKEN = exports.END_FAIL_TOKEN = exports.FAIL_TOKEN = exports.PASS_TOKEN = exports.TEST_TOKEN = exports.END_SUMMARY_TOKEN = exports.SUMMARY_TOKEN = exports.MODULE_NESTING_TOKEN = exports.MODULE_TOKEN = void 0; +// Tokens defining the True CSS output language. +exports.MODULE_TOKEN = '# Module: '; +exports.MODULE_NESTING_TOKEN = ' :: '; +exports.SUMMARY_TOKEN = '# SUMMARY '; +exports.END_SUMMARY_TOKEN = '----------'; +exports.TEST_TOKEN = 'Test: '; +exports.PASS_TOKEN = '✔ '; +exports.FAIL_TOKEN = '✖ FAILED: ['; +exports.END_FAIL_TOKEN = ']'; +exports.ASSERT_TOKEN = 'ASSERT: '; +exports.FAILURE_DETAIL_TOKEN = '- '; +exports.FAILURE_TYPE_START_TOKEN = '['; +exports.FAILURE_TYPE_END_TOKEN = ']'; +exports.OUTPUT_TOKEN = 'Output: '; +exports.EXPECTED_TOKEN = 'Expected: '; +exports.DETAILS_SEPARATOR_TOKEN = ': '; +exports.OUTPUT_START_TOKEN = 'OUTPUT'; +exports.OUTPUT_END_TOKEN = 'END_OUTPUT'; +exports.EXPECTED_START_TOKEN = 'EXPECTED'; +exports.EXPECTED_END_TOKEN = 'END_EXPECTED'; +exports.CONTAINED_START_TOKEN = 'CONTAINED'; +exports.CONTAINED_END_TOKEN = 'END_CONTAINED'; +exports.ASSERT_END_TOKEN = 'END_ASSERT'; +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/lib/constants.js.map b/lib/constants.js.map new file mode 100644 index 0000000..224c488 --- /dev/null +++ b/lib/constants.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAA,gDAAgD;AACnC,QAAA,YAAY,GAAG,YAAY,CAAC;AAC5B,QAAA,oBAAoB,GAAG,MAAM,CAAC;AAC9B,QAAA,aAAa,GAAG,YAAY,CAAC;AAC7B,QAAA,iBAAiB,GAAG,YAAY,CAAC;AACjC,QAAA,UAAU,GAAG,QAAQ,CAAC;AACtB,QAAA,UAAU,GAAG,IAAI,CAAC;AAClB,QAAA,UAAU,GAAG,aAAa,CAAC;AAC3B,QAAA,cAAc,GAAG,GAAG,CAAC;AACrB,QAAA,YAAY,GAAG,UAAU,CAAC;AAC1B,QAAA,oBAAoB,GAAG,IAAI,CAAC;AAC5B,QAAA,wBAAwB,GAAG,GAAG,CAAC;AAC/B,QAAA,sBAAsB,GAAG,GAAG,CAAC;AAC7B,QAAA,YAAY,GAAG,UAAU,CAAC;AAC1B,QAAA,cAAc,GAAG,YAAY,CAAC;AAC9B,QAAA,uBAAuB,GAAG,IAAI,CAAC;AAC/B,QAAA,kBAAkB,GAAG,QAAQ,CAAC;AAC9B,QAAA,gBAAgB,GAAG,YAAY,CAAC;AAChC,QAAA,oBAAoB,GAAG,UAAU,CAAC;AAClC,QAAA,kBAAkB,GAAG,cAAc,CAAC;AACpC,QAAA,qBAAqB,GAAG,WAAW,CAAC;AACpC,QAAA,mBAAmB,GAAG,eAAe,CAAC;AACtC,QAAA,gBAAgB,GAAG,YAAY,CAAC"} \ No newline at end of file diff --git a/lib/index.d.ts b/lib/index.d.ts new file mode 100644 index 0000000..6446514 --- /dev/null +++ b/lib/index.d.ts @@ -0,0 +1,36 @@ +import type { Options } from 'sass'; +import { Node } from 'css'; +export interface TrueOptions { + sass?: typeof import('sass'); + describe: (description: string, fn: () => void) => void; + it: (description: string, fn: () => void) => void; + contextLines?: number; +} +export interface Assertion { + description: string; + output?: string; + assertionType?: string; + expected?: string; + details?: string; + passed?: boolean; +} +export interface Test { + test: string; + assertions: Assertion[]; +} +export interface Module { + module: string; + tests: Test[]; + modules?: Module[]; +} +export declare type Context = { + modules: Module[]; + currentModule?: Module; + currentTest?: Test; + currentAssertion?: Assertion; + currentOutputRules?: Node[]; + currentExpectedRules?: Node[]; +}; +export declare function formatFailureMessage(assertion: Assertion): string; +export declare function runSass(sassOptions: Options, trueOptions: TrueOptions): void; +export declare function parse(rawCss: Readonly, ctxLines?: Readonly): Module[]; diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..9f71310 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,405 @@ +"use strict"; +/* eslint-disable no-plusplus, no-unused-vars, no-var, no-use-before-define */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parse = exports.runSass = exports.formatFailureMessage = void 0; +var path = require("path"); +var assert = require("assert"); +var css = require("css"); +var lodash_1 = require("lodash"); +var chalk = require("chalk"); +var constants_1 = require("./constants"); +var utils_1 = require("./utils"); +function formatFailureMessage(assertion) { + var msg = assertion.description; + msg = "".concat(msg, " (\"").concat(assertion.output, "\""); + msg = "".concat(msg, " ").concat(assertion.assertionType, " \"").concat(assertion.expected, "\""); + if (assertion.details) { + msg = "".concat(msg, " -- ").concat(assertion.details); + } + msg = "".concat(msg, ")"); + msg = "".concat(msg, "\n").concat(chalk.green('+ expected ')).concat(chalk.red('- actual')); + msg = "".concat(msg, "\n\n").concat(chalk.red("-".concat(assertion.output))); + msg = "".concat(msg, "\n").concat(chalk.green("+".concat(assertion.expected, "\n"))); + return msg; +} +exports.formatFailureMessage = formatFailureMessage; +function dealWithAnnoyingMediaQueries(rawCSS) { + var matchMediaQuery = /(@[a-zA-Z0-9:()\s-]+)/g; + // eslint-disable-next-line max-len + var matchCSSWithinMediaQueryBlock = /@[a-zA-Z0-9:()\s-]+{([a-zA-Z0-9:()\s-;._\\n{}]+)(?!}\\n})/g; + var mediaqueries = rawCSS.match(matchMediaQuery); + var rawCSSSansMediaQueries = rawCSS + .replace(matchMediaQuery, '') + .replace(matchCSSWithinMediaQueryBlock, '') + .replace(/^{/, ''); + var matches = matchCSSWithinMediaQueryBlock.exec(rawCSS); + var i = 0; + var mediaQueryBasedSelectors = []; + var mediaqueryRule = /* istanbul ignore next */ function (rule) { + return mediaqueries[i] + rule; + }; + /* istanbul ignore next */ + while (matches !== null) { + // This is necessary to avoid infinite loops with zero-width matches + if (matches.index === matchCSSWithinMediaQueryBlock.lastIndex) { + matchCSSWithinMediaQueryBlock.lastIndex++; + } + /* istanbul ignore next */ + var cssWithinMediaQuery = (0, utils_1.removeNewLines)(matches[1]); + var cssRules = (0, utils_1.cssStringToArrayOfRules)(cssWithinMediaQuery); + mediaQueryBasedSelectors = mediaQueryBasedSelectors.concat(cssRules.map(mediaqueryRule)); + i++; + matches = matchCSSWithinMediaQueryBlock.exec(rawCSS); + } + return { + mediaQueryBasedSelectors: mediaQueryBasedSelectors, + rawCSSSansMediaQueries: rawCSSSansMediaQueries, + }; +} +function createSelectorsRulesPairs(cssString) { + var processedMediaQueries = dealWithAnnoyingMediaQueries(cssString); + var mediaQueries = (0, utils_1.splitSelectorAndProperties)(processedMediaQueries.mediaQueryBasedSelectors); + var nonMediaQueries = processedMediaQueries.rawCSSSansMediaQueries; + var blocks = (0, utils_1.cssStringToArrayOfRules)(nonMediaQueries); + var splitBlocks = (0, utils_1.splitSelectorAndProperties)(blocks); + return splitBlocks.concat(mediaQueries).filter(utils_1.falsyValues); +} +function contains(output, expected) { + var outputBlocks = createSelectorsRulesPairs(output); + var expectedBlocks = createSelectorsRulesPairs(expected); + var results = expectedBlocks.map(function (block) { + var outputBlock = outputBlocks.find(function (element) { return element.selector === block.selector; }); + if (outputBlock) { + // Turns a css string into an array of property-value pairs. + var expectedProperties = block.output + .split(';') + .map(function (propertyValuePair) { return propertyValuePair.trim(); }) + .filter(function (innerBlock) { return innerBlock !== ' {' && innerBlock !== '}'; }); + // This is the assertion itself! + return expectedProperties.every(function (property) { + return outputBlock.output.includes(property); + }); + } + return false; + }); + return results.every(function (result) { return result === true; }); +} +function finishCurrentAssertion(ctx) { + if (ctx.currentAssertion) { + ctx.currentTest.assertions.push(ctx.currentAssertion); + delete ctx.currentAssertion; + } +} +function finishCurrentTest(ctx) { + finishCurrentAssertion(ctx); + if (ctx.currentTest) { + ctx.currentModule.tests.push(ctx.currentTest); + delete ctx.currentTest; + } +} +function insertModule(paths, module, ctx) { + if (!ctx.modules) { + ctx.modules = []; + } + if (paths.length > 1) { + var newCtx = (0, lodash_1.find)(ctx.modules, { module: paths[0] }); + if (!newCtx) { + newCtx = { module: paths[0] }; + ctx.modules.push(newCtx); + } + insertModule(paths.slice(1), module, newCtx); + } + else { + ctx.modules.push(module); + } +} +function finishCurrentModule(ctx) { + finishCurrentTest(ctx); + if (ctx.currentModule) { + var paths = ctx.currentModule.module.split(constants_1.MODULE_NESTING_TOKEN); + ctx.currentModule.module = (0, lodash_1.last)(paths); + insertModule(paths, ctx.currentModule, ctx); + delete ctx.currentModule; + } +} +function describeModule(module, describe, it) { + describe(module.module, function () { + (0, lodash_1.forEach)(module.modules, function (submodule) { + describeModule(submodule, describe, it); + }); + (0, lodash_1.forEach)(module.tests, function (test) { + it(test.test, function () { + (0, lodash_1.forEach)(test.assertions, function (assertion) { + if (!assertion.passed) { + assert.fail(formatFailureMessage(assertion)); + } + }); + }); + }); + }); +} +function runSass(sassOptions, trueOptions) { + var sassOpts = Object.assign({}, sassOptions); + var trueOpts = Object.assign({}, trueOptions); + var sassPath = path.join(__dirname, '..', 'sass'); + if (sassOpts.includePaths) { + sassOpts.includePaths.push(sassPath); + } + else { + sassOpts.includePaths = [sassPath]; + } + var sass; + if (trueOpts.sass) { + sass = trueOpts.sass; + } + else { + // eslint-disable-next-line global-require + sass = require('sass'); + } + // eslint-disable-next-line no-sync + var parsedCss = sass.renderSync(sassOpts).css.toString(); + var modules = parse(parsedCss, trueOpts.contextLines); + (0, lodash_1.forEach)(modules, function (module) { + describeModule(module, trueOpts.describe, trueOpts.it); + }); +} +exports.runSass = runSass; +function parse(rawCss, ctxLines) { + var contextLines = typeof ctxLines === 'undefined' ? 10 : ctxLines; + var lines = rawCss.split(/\r?\n/); + function parseModule(rule, ctx) { + if (rule.type === 'comment') { + var text = rule.comment.trim(); + if (!text) { + return parseModule; + } + if ((0, utils_1.startsWith)(text, constants_1.MODULE_TOKEN)) { + finishCurrentModule(ctx); + ctx.currentModule = { + module: text.substring(constants_1.MODULE_TOKEN.length), + tests: [], + }; + return parseTest; + } + if ((0, utils_1.startsWith)(text, constants_1.SUMMARY_TOKEN)) { + return ignoreUntilEndSummary; + } + // ignore un-recognized comments, keep looking for module header. + return parseModule; + } + // ignore other rule types + return parseModule; + } + function parseCss() { + var ast = css.parse(rawCss); + var ctx = { modules: [] }; + var handler = parseModule; + (0, lodash_1.forEach)(ast.stylesheet.rules, function (rule) { + handler = handler(rule, ctx); + }); + finishCurrentModule(ctx); + return ctx.modules; + } + function parseError(msg, seeking, pos) { + var errorMsg = "Line ".concat(pos.start.line, ", ") + + "column ".concat(pos.start.column, ": ").concat(msg, "; ") + + "looking for ".concat(seeking, ".\n") + + "-- Context --\n".concat(lines + .slice(Math.max(0, pos.start.line - contextLines), pos.start.line) + .join('\n'), "\n").concat(' '.repeat(pos.start.column - 1), "^\n"); + return new Error(errorMsg); + } + var ignoreUntilEndSummary = function (rule) { + if ((0, utils_1.isCommentNode)(rule)) { + var text = rule.comment.trim(); + if ((0, utils_1.startsWith)(text, constants_1.END_SUMMARY_TOKEN)) { + return parseModule; + } + return ignoreUntilEndSummary; + } + throw parseError("Unexpected rule type \"".concat(rule.type, "\""), 'end summary', rule.position); + }; + var parseTest = function (rule, ctx) { + if ((0, utils_1.isCommentNode)(rule)) { + var text = rule.comment.trim(); + if (!text) { + return parseTest; + } + if (text.match(/^-+$/)) { + return parseTest; + } + if ((0, utils_1.startsWith)(text, constants_1.TEST_TOKEN)) { + finishCurrentTest(ctx); + ctx.currentTest = { + test: text.substring(constants_1.TEST_TOKEN.length), + assertions: [], + }; + return parseAssertion; + } + return parseModule(rule, ctx); + } + // ignore other rule types + return parseModule; + }; + var parseAssertion = function (rule, ctx) { + if ((0, utils_1.isCommentNode)(rule)) { + var text = rule.comment.trimStart(); + if (!text) { + return parseAssertion; + } + if ((0, utils_1.startsWith)(text, constants_1.PASS_TOKEN)) { + finishCurrentAssertion(ctx); + ctx.currentAssertion = { + description: text.substring(constants_1.PASS_TOKEN.length).trim() || '', + passed: true, + }; + return parseAssertion; + } + else if ((0, utils_1.startsWith)(text, constants_1.FAIL_TOKEN)) { + finishCurrentAssertion(ctx); + var endAssertionType = text.indexOf(constants_1.END_FAIL_TOKEN); + ctx.currentAssertion = { + description: text.substring(endAssertionType + 2).trim(), + passed: false, + assertionType: text + .substring(constants_1.FAIL_TOKEN.length, endAssertionType) + .trim(), + }; + return parseFailureDetail; + } + else if ((0, utils_1.startsWith)(text, constants_1.ASSERT_TOKEN)) { + finishCurrentAssertion(ctx); + ctx.currentAssertion = { + description: text.substring(constants_1.ASSERT_TOKEN.length).trim(), + assertionType: 'equal', + }; + return parseAssertionOutputStart; + } + return parseTest(rule, ctx); + } + // ignore other rule types + return parseModule; + }; + var parseFailureDetail = function (rule, ctx) { + if ((0, utils_1.isCommentNode)(rule)) { + var text = rule.comment.trim(); + if ((0, utils_1.startsWith)(text, constants_1.FAILURE_DETAIL_TOKEN)) { + var detail = text.substring(constants_1.FAILURE_DETAIL_TOKEN.length); + var outputOrExpected = void 0; + if ((0, utils_1.startsWith)(detail, constants_1.OUTPUT_TOKEN)) { + outputOrExpected = 'output'; + } + else if ((0, utils_1.startsWith)(detail, constants_1.EXPECTED_TOKEN)) { + outputOrExpected = 'expected'; + } + if (outputOrExpected) { + var startType = text.indexOf(constants_1.FAILURE_TYPE_START_TOKEN); + var endType = text.indexOf(constants_1.FAILURE_TYPE_END_TOKEN); + var type = text.substring(startType, endType + 1); + var content = text.substring(endType + 2); + ctx.currentAssertion[outputOrExpected] = "".concat(type, " ").concat(content); + return parseFailureDetail; + } + var splitAt = detail.indexOf(constants_1.DETAILS_SEPARATOR_TOKEN); + if (splitAt !== -1) { + var key = detail.substring(0, splitAt); + ctx.currentAssertion[key.toLowerCase()] = detail.substring(splitAt + constants_1.DETAILS_SEPARATOR_TOKEN.length); + return parseFailureDetail; + } + } + return parseAssertion(rule, ctx); + } + throw parseError("Unexpected rule type \"".concat(rule.type, "\""), 'output/expected', rule.position); + }; + var parseAssertionOutputStart = function (rule, ctx) { + if ((0, utils_1.isCommentNode)(rule)) { + var text = rule.comment.trim(); + if (!text) { + return parseAssertionOutputStart; + } + if (text === constants_1.OUTPUT_START_TOKEN) { + ctx.currentOutputRules = []; + return parseAssertionOutput; + } + throw parseError("Unexpected comment \"".concat(text, "\""), 'OUTPUT', rule.position); + } + throw parseError("Unexpected rule type \"".concat(rule.type, "\""), 'OUTPUT', rule.position); + }; + var parseAssertionOutput = function (rule, ctx) { + if ((0, utils_1.isCommentNode)(rule)) { + if (rule.comment.trim() === constants_1.OUTPUT_END_TOKEN) { + ctx.currentAssertion.output = css.stringify({ + stylesheet: { rules: ctx.currentOutputRules }, + }); + delete ctx.currentOutputRules; + return parseAssertionExpectedStart; + } + } + ctx.currentOutputRules.push(rule); + return parseAssertionOutput; + }; + var parseAssertionExpectedStart = function (rule, ctx) { + if ((0, utils_1.isCommentNode)(rule)) { + var text = rule.comment.trim(); + if (!text) { + return parseAssertionExpectedStart; + } + if (text === constants_1.EXPECTED_START_TOKEN) { + ctx.currentExpectedRules = []; + return parseAssertionExpected; + } + if (text === constants_1.CONTAINED_START_TOKEN) { + ctx.currentExpectedRules = []; + return parseAssertionContained; + } + throw parseError("Unexpected comment \"".concat(text, "\""), 'EXPECTED', rule.position); + } + throw parseError("Unexpected rule type \"".concat(rule.type, "\""), 'EXPECTED', rule.position); + }; + var parseAssertionExpected = function (rule, ctx) { + if ((0, utils_1.isCommentNode)(rule)) { + if (rule.comment.trim() === constants_1.EXPECTED_END_TOKEN) { + ctx.currentAssertion.expected = css.stringify({ + stylesheet: { rules: ctx.currentExpectedRules }, + }); + delete ctx.currentExpectedRules; + ctx.currentAssertion.passed = + ctx.currentAssertion.output === ctx.currentAssertion.expected; + return parseEndAssertion; + } + } + ctx.currentExpectedRules.push(rule); + return parseAssertionExpected; + }; + var parseEndAssertion = function (rule, ctx) { + if ((0, utils_1.isCommentNode)(rule)) { + var text = rule.comment.trim(); + if (!text) { + return parseEndAssertion; + } + if (text === constants_1.ASSERT_END_TOKEN) { + finishCurrentAssertion(ctx); + return parseAssertion; + } + throw parseError("Unexpected comment \"".concat(text, "\""), 'END_ASSERT', rule.position); + } + throw parseError("Unexpected rule type \"".concat(rule.type, "\""), 'END_ASSERT', rule.position); + }; + var parseAssertionContained = function (rule, ctx) { + if ((0, utils_1.isCommentNode)(rule)) { + if (rule.comment.trim() === constants_1.CONTAINED_END_TOKEN) { + ctx.currentAssertion.expected = css.stringify({ + stylesheet: { rules: ctx.currentExpectedRules }, + }); + delete ctx.currentExpectedRules; + ctx.currentAssertion.passed = contains(ctx.currentAssertion.output, ctx.currentAssertion.expected); + return parseEndAssertion; + } + } + ctx.currentExpectedRules.push(rule); + return parseAssertionContained; + }; + return parseCss(); +} +exports.parse = parse; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/index.js.map b/lib/index.js.map new file mode 100644 index 0000000..19bdff3 --- /dev/null +++ b/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/utils.d.ts b/lib/utils.d.ts new file mode 100644 index 0000000..66820fc --- /dev/null +++ b/lib/utils.d.ts @@ -0,0 +1,10 @@ +import { Comment, Node } from 'css'; +export declare function falsyValues(item?: any): boolean; +export declare function isCommentNode(node: Node): node is Comment; +export declare function startsWith(text: string, token: string): boolean; +export declare function removeNewLines(cssString: string): string; +export declare function cssStringToArrayOfRules(cssString: string): string[]; +export declare function splitSelectorAndProperties(blocks: string[]): { + selector: string; + output: string; +}[]; diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..8048fd9 --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,35 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.splitSelectorAndProperties = exports.cssStringToArrayOfRules = exports.removeNewLines = exports.startsWith = exports.isCommentNode = exports.falsyValues = void 0; +function falsyValues(item) { + return Boolean(item); +} +exports.falsyValues = falsyValues; +function isCommentNode(node) { + return node.type === 'comment'; +} +exports.isCommentNode = isCommentNode; +function startsWith(text, token) { + return text.indexOf(token) === 0; +} +exports.startsWith = startsWith; +function removeNewLines(cssString) { + return cssString.replace(/\n/g, ''); +} +exports.removeNewLines = removeNewLines; +function cssStringToArrayOfRules(cssString) { + return removeNewLines(cssString) + .split(/\s*}(?![\s]*["',}])/g) + .filter(falsyValues); +} +exports.cssStringToArrayOfRules = cssStringToArrayOfRules; +function splitSelectorAndProperties(blocks) { + return blocks.map(function (block) { + var temp = block.split('{'); + var selector = temp[0]; + var output = temp[1]; + return { selector: selector, output: output }; + }); +} +exports.splitSelectorAndProperties = splitSelectorAndProperties; +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/lib/utils.js.map b/lib/utils.js.map new file mode 100644 index 0000000..bd5f9a2 --- /dev/null +++ b/lib/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;AAEA,SAAgB,WAAW,CAAC,IAAU;IACpC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AAFD,kCAEC;AAED,SAAgB,aAAa,CAAC,IAAU;IACtC,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC;AACjC,CAAC;AAFD,sCAEC;AAED,SAAgB,UAAU,CAAC,IAAY,EAAE,KAAa;IACpD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAFD,gCAEC;AAED,SAAgB,cAAc,CAAC,SAAiB;IAC9C,OAAO,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAFD,wCAEC;AAED,SAAgB,uBAAuB,CAAC,SAAiB;IACvD,OAAO,cAAc,CAAC,SAAS,CAAC;SAC7B,KAAK,CAAC,sBAAsB,CAAC;SAC7B,MAAM,CAAC,WAAW,CAAC,CAAC;AACzB,CAAC;AAJD,0DAIC;AAED,SAAgB,0BAA0B,CAAC,MAAgB;IACzD,OAAO,MAAM,CAAC,GAAG,CAAC,UAAC,KAAK;QACtB,IAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,IAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACvB,OAAO,EAAE,QAAQ,UAAA,EAAE,MAAM,QAAA,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC;AAPD,gEAOC"} \ No newline at end of file diff --git a/package.json b/package.json index 788c873..c662a02 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "6.0.1", "description": "Unit testing for Sass.", "homepage": "https://www.oddbird.net/true/", - "main": "lib/main.js", + "main": "lib/index.js", "repository": { "type": "git", "url": "https://github.com/oddbird/true.git" @@ -26,6 +26,12 @@ "lodash": "^4.17.19" }, "devDependencies": { + "@types/chalk": "^2.2.0", + "@types/css": "0.0.33", + "@types/node": "^16.11.11", + "@types/sass": "^1.43.1", + "@typescript-eslint/eslint-plugin": "^4.33.0", + "@typescript-eslint/parser": "^4.33.0", "chai": "^4.1.2", "coveralls": "^3.1.0", "eslint": "^7.5.0", @@ -44,7 +50,8 @@ "stylelint-config-prettier": "^8.0.2", "stylelint-config-recommended": "^3.0.0", "stylelint-prettier": "^1.1.2", - "stylelint-scss": "^3.18.0" + "stylelint-scss": "^3.18.0", + "typescript": "^4.4.4" }, "eyeglass": { "needs": "*", @@ -53,12 +60,13 @@ "exports": false }, "scripts": { + "build": "tsc", "test": "yarn test:mocha; yarn test:jest", "test:mocha": "nyc --reporter=html --reporter=text mocha", "test:jest": "jest --testRegex test_ --env=node", "prettier:js": "prettier --write '**/*.js'", "prettier:other": "prettier --write '**/*.{json,md,yml}'", - "eslint": "eslint lib test --fix", + "eslint": "eslint src test --fix", "lint": "run-p lint:js lint:sass prettier:other", "lint:js": "run-s prettier:js eslint", "lint:sass": "stylelint '**/*.scss' --fix", diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..379a324 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,23 @@ +// Tokens defining the True CSS output language. +export const MODULE_TOKEN = '# Module: '; +export const MODULE_NESTING_TOKEN = ' :: '; +export const SUMMARY_TOKEN = '# SUMMARY '; +export const END_SUMMARY_TOKEN = '----------'; +export const TEST_TOKEN = 'Test: '; +export const PASS_TOKEN = '✔ '; +export const FAIL_TOKEN = '✖ FAILED: ['; +export const END_FAIL_TOKEN = ']'; +export const ASSERT_TOKEN = 'ASSERT: '; +export const FAILURE_DETAIL_TOKEN = '- '; +export const FAILURE_TYPE_START_TOKEN = '['; +export const FAILURE_TYPE_END_TOKEN = ']'; +export const OUTPUT_TOKEN = 'Output: '; +export const EXPECTED_TOKEN = 'Expected: '; +export const DETAILS_SEPARATOR_TOKEN = ': '; +export const OUTPUT_START_TOKEN = 'OUTPUT'; +export const OUTPUT_END_TOKEN = 'END_OUTPUT'; +export const EXPECTED_START_TOKEN = 'EXPECTED'; +export const EXPECTED_END_TOKEN = 'END_EXPECTED'; +export const CONTAINED_START_TOKEN = 'CONTAINED'; +export const CONTAINED_END_TOKEN = 'END_CONTAINED'; +export const ASSERT_END_TOKEN = 'END_ASSERT'; diff --git a/lib/main.js b/src/index.ts similarity index 76% rename from lib/main.js rename to src/index.ts index 34a8cf8..e32871e 100644 --- a/lib/main.js +++ b/src/index.ts @@ -1,64 +1,84 @@ /* eslint-disable no-plusplus, no-unused-vars, no-var, no-use-before-define */ -'use strict'; - -const path = require('path'); -const assert = require('assert'); - -const chalk = require('chalk'); -const css = require('css'); -const { find, forEach, last } = require('lodash'); - -// Tokens defining the True CSS output language. -const MODULE_TOKEN = '# Module: '; -const MODULE_NESTING_TOKEN = ' :: '; -const SUMMARY_TOKEN = '# SUMMARY '; -const END_SUMMARY_TOKEN = '----------'; -const TEST_TOKEN = 'Test: '; -const PASS_TOKEN = '✔ '; -const FAIL_TOKEN = '✖ FAILED: ['; -const END_FAIL_TOKEN = ']'; -const ASSERT_TOKEN = 'ASSERT: '; -const FAILURE_DETAIL_TOKEN = '- '; -const FAILURE_TYPE_START_TOKEN = '['; -const FAILURE_TYPE_END_TOKEN = ']'; -const OUTPUT_TOKEN = 'Output: '; -const EXPECTED_TOKEN = 'Expected: '; -const DETAILS_SEPARATOR_TOKEN = ': '; -const OUTPUT_START_TOKEN = 'OUTPUT'; -const OUTPUT_END_TOKEN = 'END_OUTPUT'; -const EXPECTED_START_TOKEN = 'EXPECTED'; -const EXPECTED_END_TOKEN = 'END_EXPECTED'; -const CONTAINED_START_TOKEN = 'CONTAINED'; -const CONTAINED_END_TOKEN = 'END_CONTAINED'; -const ASSERT_END_TOKEN = 'END_ASSERT'; - -var runSass = function (sassOptions, trueOptions) { - const sassOpts = Object.assign({}, sassOptions); - const trueOpts = Object.assign({}, trueOptions); - const sassPath = path.join(__dirname, '..', 'sass'); - if (sassOpts.includePaths) { - sassOpts.includePaths.push(sassPath); - } else { - sassOpts.includePaths = [sassPath]; - } - let sass; - if (trueOpts.sass) { - sass = trueOpts.sass; - } else { - // eslint-disable-next-line global-require - sass = require('sass'); - } - // eslint-disable-next-line no-sync - const parsedCss = sass.renderSync(sassOpts).css.toString(); - const modules = parse(parsedCss, trueOpts.contextLines); - - forEach(modules, (module) => { - describeModule(module, trueOpts.describe, trueOpts.it); - }); +import * as path from 'path'; +import * as assert from 'assert'; + +import type { Options } from 'sass'; +import * as css from 'css'; +import { find, forEach, last } from 'lodash'; +import { Comment, Node } from 'css'; +import * as chalk from 'chalk'; + +import { + ASSERT_END_TOKEN, + ASSERT_TOKEN, + CONTAINED_END_TOKEN, + CONTAINED_START_TOKEN, + DETAILS_SEPARATOR_TOKEN, + END_FAIL_TOKEN, + END_SUMMARY_TOKEN, + EXPECTED_END_TOKEN, + EXPECTED_START_TOKEN, + EXPECTED_TOKEN, + FAIL_TOKEN, + FAILURE_DETAIL_TOKEN, + FAILURE_TYPE_END_TOKEN, + FAILURE_TYPE_START_TOKEN, + MODULE_NESTING_TOKEN, + MODULE_TOKEN, + OUTPUT_END_TOKEN, + OUTPUT_START_TOKEN, + OUTPUT_TOKEN, + PASS_TOKEN, + SUMMARY_TOKEN, + TEST_TOKEN, +} from './constants'; +import { + cssStringToArrayOfRules, + falsyValues, + isCommentNode, + removeNewLines, + splitSelectorAndProperties, + startsWith, +} from './utils'; + +export interface TrueOptions { + sass?: typeof import('sass'); + describe: (description: string, fn: () => void) => void; + it: (description: string, fn: () => void) => void; + contextLines?: number; +} + +export interface Assertion { + description: string; + output?: string; + assertionType?: string; + expected?: string; + details?: string; + passed?: boolean; +} + +export interface Test { + test: string; + assertions: Assertion[]; +} + +export interface Module { + module: string; + tests: Test[]; + modules?: Module[]; +} + +export type Context = { + modules: Module[]; + currentModule?: Module; + currentTest?: Test; + currentAssertion?: Assertion; + currentOutputRules?: Node[]; + currentExpectedRules?: Node[]; }; -var formatFailureMessage = function (assertion) { +export function formatFailureMessage(assertion: Assertion) { let msg = assertion.description; msg = `${msg} ("${assertion.output}"`; msg = `${msg} ${assertion.assertionType} "${assertion.expected}"`; @@ -66,13 +86,139 @@ var formatFailureMessage = function (assertion) { msg = `${msg} -- ${assertion.details}`; } msg = `${msg})`; - msg = `${msg}\n ${chalk.green('+ expected ')}${chalk.red('- actual')}`; - msg = `${msg}\n\n ${chalk.red(`-${assertion.output}`)}`; - msg = `${msg}\n ${chalk.green(`+${assertion.expected}\n`)}`; + msg = `${msg}\n${chalk.green('+ expected ')}${chalk.red('- actual')}`; + msg = `${msg}\n\n${chalk.red(`-${assertion.output}`)}`; + msg = `${msg}\n${chalk.green(`+${assertion.expected}\n`)}`; return msg; -}; +} + +function dealWithAnnoyingMediaQueries(rawCSS: string) { + const matchMediaQuery = /(@[a-zA-Z0-9:()\s-]+)/g; + // eslint-disable-next-line max-len + const matchCSSWithinMediaQueryBlock = /@[a-zA-Z0-9:()\s-]+{([a-zA-Z0-9:()\s-;._\\n{}]+)(?!}\\n})/g; -var describeModule = function (module, describe, it) { + const mediaqueries = rawCSS.match(matchMediaQuery); + const rawCSSSansMediaQueries = rawCSS + .replace(matchMediaQuery, '') + .replace(matchCSSWithinMediaQueryBlock, '') + .replace(/^{/, ''); + let matches = matchCSSWithinMediaQueryBlock.exec(rawCSS); + let i = 0; + let mediaQueryBasedSelectors = []; + const mediaqueryRule = /* istanbul ignore next */ (rule) => + mediaqueries[i] + rule; + /* istanbul ignore next */ + while (matches !== null) { + // This is necessary to avoid infinite loops with zero-width matches + if (matches.index === matchCSSWithinMediaQueryBlock.lastIndex) { + matchCSSWithinMediaQueryBlock.lastIndex++; + } + + /* istanbul ignore next */ + const cssWithinMediaQuery = removeNewLines(matches[1]); + const cssRules = cssStringToArrayOfRules(cssWithinMediaQuery); + + mediaQueryBasedSelectors = mediaQueryBasedSelectors.concat( + cssRules.map(mediaqueryRule), + ); + + i++; + matches = matchCSSWithinMediaQueryBlock.exec(rawCSS); + } + + return { + mediaQueryBasedSelectors, + rawCSSSansMediaQueries, + }; +} + +function createSelectorsRulesPairs(cssString: string) { + const processedMediaQueries = dealWithAnnoyingMediaQueries(cssString); + const mediaQueries = splitSelectorAndProperties( + processedMediaQueries.mediaQueryBasedSelectors, + ); + const nonMediaQueries = processedMediaQueries.rawCSSSansMediaQueries; + + const blocks = cssStringToArrayOfRules(nonMediaQueries); + + const splitBlocks = splitSelectorAndProperties(blocks); + + return splitBlocks.concat(mediaQueries).filter(falsyValues); +} + +function contains(output, expected) { + const outputBlocks = createSelectorsRulesPairs(output); + const expectedBlocks = createSelectorsRulesPairs(expected); + + const results = expectedBlocks.map((block) => { + const outputBlock = outputBlocks.find( + (element) => element.selector === block.selector, + ); + if (outputBlock) { + // Turns a css string into an array of property-value pairs. + const expectedProperties = block.output + .split(';') + .map((propertyValuePair) => propertyValuePair.trim()) + .filter((innerBlock) => innerBlock !== ' {' && innerBlock !== '}'); + + // This is the assertion itself! + return expectedProperties.every((property) => + outputBlock.output.includes(property), + ); + } + return false; + }); + + return results.every((result) => result === true); +} + +function finishCurrentAssertion(ctx: Context) { + if (ctx.currentAssertion) { + ctx.currentTest.assertions.push(ctx.currentAssertion); + delete ctx.currentAssertion; + } +} + +function finishCurrentTest(ctx: Context) { + finishCurrentAssertion(ctx); + if (ctx.currentTest) { + ctx.currentModule.tests.push(ctx.currentTest); + delete ctx.currentTest; + } +} + +function insertModule(paths: string[], module: Module, ctx: Context) { + if (!ctx.modules) { + ctx.modules = []; + } + + if (paths.length > 1) { + let newCtx = find(ctx.modules, { module: paths[0] }); + if (!newCtx) { + newCtx = { module: paths[0] }; + ctx.modules.push(newCtx); + } + insertModule(paths.slice(1), module, newCtx); + } else { + ctx.modules.push(module); + } +} + +function finishCurrentModule(ctx: Context) { + finishCurrentTest(ctx); + if (ctx.currentModule) { + const paths = ctx.currentModule.module.split(MODULE_NESTING_TOKEN); + ctx.currentModule.module = last(paths); + insertModule(paths, ctx.currentModule, ctx); + delete ctx.currentModule; + } +} + +function describeModule( + module: Module, + describe: TrueOptions['describe'], + it: TrueOptions['it'], +) { describe(module.module, () => { forEach(module.modules, (submodule) => { describeModule(submodule, describe, it); @@ -87,38 +233,43 @@ var describeModule = function (module, describe, it) { }); }); }); -}; +} -var parse = function (rawCss, ctxLines) { - const contextLines = typeof ctxLines === 'undefined' ? 10 : ctxLines; - const lines = rawCss.split(/\r?\n/); - - var parseCss = function () { - const ast = css.parse(rawCss); - const ctx = { modules: [] }; - let handler = parseModule; +export function runSass(sassOptions: Options, trueOptions: TrueOptions): void { + const sassOpts = Object.assign({}, sassOptions); + const trueOpts = Object.assign({}, trueOptions); + const sassPath = path.join(__dirname, '..', 'sass'); + if (sassOpts.includePaths) { + sassOpts.includePaths.push(sassPath); + } else { + sassOpts.includePaths = [sassPath]; + } - forEach(ast.stylesheet.rules, (rule) => { - handler = handler(rule, ctx); - }); + let sass; + if (trueOpts.sass) { + sass = trueOpts.sass; + } else { + // eslint-disable-next-line global-require + sass = require('sass'); + } - finishCurrentModule(ctx); + // eslint-disable-next-line no-sync + const parsedCss = sass.renderSync(sassOpts).css.toString(); + const modules = parse(parsedCss, trueOpts.contextLines); - return ctx.modules; - }; + forEach(modules, (module) => { + describeModule(module, trueOpts.describe, trueOpts.it); + }); +} - var parseError = function (msg, seeking, pos) { - const errorMsg = - `Line ${pos.start.line}, ` + - `column ${pos.start.column}: ${msg}; ` + - `looking for ${seeking}.\n` + - `-- Context --\n${lines - .slice(Math.max(0, pos.start.line - contextLines), pos.start.line) - .join('\n')}\n${' '.repeat(pos.start.column - 1)}^\n`; - return new Error(errorMsg); - }; +export function parse( + rawCss: Readonly, + ctxLines?: Readonly, +): Module[] { + const contextLines = typeof ctxLines === 'undefined' ? 10 : ctxLines; + const lines = rawCss.split(/\r?\n/); - var parseModule = function (rule, ctx) { + function parseModule(rule: Comment, ctx: Context) { if (rule.type === 'comment') { const text = rule.comment.trim(); if (!text) { @@ -140,10 +291,35 @@ var parse = function (rawCss, ctxLines) { } // ignore other rule types return parseModule; - }; + } - var ignoreUntilEndSummary = function (rule, ctx) { - if (rule.type === 'comment') { + function parseCss() { + const ast = css.parse(rawCss); + const ctx: Context = { modules: [] }; + let handler = parseModule; + + forEach(ast.stylesheet.rules, (rule) => { + handler = handler(rule, ctx); + }); + + finishCurrentModule(ctx); + + return ctx.modules; + } + + function parseError(msg: string, seeking: string, pos: Node['position']) { + const errorMsg = + `Line ${pos.start.line}, ` + + `column ${pos.start.column}: ${msg}; ` + + `looking for ${seeking}.\n` + + `-- Context --\n${lines + .slice(Math.max(0, pos.start.line - contextLines), pos.start.line) + .join('\n')}\n${' '.repeat(pos.start.column - 1)}^\n`; + return new Error(errorMsg); + } + + const ignoreUntilEndSummary = (rule: Node) => { + if (isCommentNode(rule)) { const text = rule.comment.trim(); if (startsWith(text, END_SUMMARY_TOKEN)) { return parseModule; @@ -157,8 +333,8 @@ var parse = function (rawCss, ctxLines) { ); }; - var parseTest = function (rule, ctx) { - if (rule.type === 'comment') { + const parseTest = (rule: Node, ctx: Context) => { + if (isCommentNode(rule)) { const text = rule.comment.trim(); if (!text) { return parseTest; @@ -180,9 +356,9 @@ var parse = function (rawCss, ctxLines) { return parseModule; }; - var parseAssertion = function (rule, ctx) { - if (rule.type === 'comment') { - const text = rule.comment.trimLeft(); + const parseAssertion = (rule: Node, ctx: Context) => { + if (isCommentNode(rule)) { + const text = rule.comment.trimStart(); if (!text) { return parseAssertion; } @@ -219,8 +395,8 @@ var parse = function (rawCss, ctxLines) { return parseModule; }; - var parseFailureDetail = function (rule, ctx) { - if (rule.type === 'comment') { + const parseFailureDetail = (rule: Node, ctx: Context) => { + if (isCommentNode(rule)) { const text = rule.comment.trim(); if (startsWith(text, FAILURE_DETAIL_TOKEN)) { const detail = text.substring(FAILURE_DETAIL_TOKEN.length); @@ -241,10 +417,9 @@ var parse = function (rawCss, ctxLines) { const splitAt = detail.indexOf(DETAILS_SEPARATOR_TOKEN); if (splitAt !== -1) { const key = detail.substring(0, splitAt); - const value = detail.substring( + ctx.currentAssertion[key.toLowerCase()] = detail.substring( splitAt + DETAILS_SEPARATOR_TOKEN.length, ); - ctx.currentAssertion[key.toLowerCase()] = value; return parseFailureDetail; } } @@ -257,8 +432,8 @@ var parse = function (rawCss, ctxLines) { ); }; - var parseAssertionOutputStart = function (rule, ctx) { - if (rule.type === 'comment') { + const parseAssertionOutputStart = (rule: Node, ctx: Context) => { + if (isCommentNode(rule)) { const text = rule.comment.trim(); if (!text) { return parseAssertionOutputStart; @@ -276,8 +451,8 @@ var parse = function (rawCss, ctxLines) { ); }; - var parseAssertionOutput = function (rule, ctx) { - if (rule.type === 'comment') { + const parseAssertionOutput = (rule: Node, ctx: Context) => { + if (isCommentNode(rule)) { if (rule.comment.trim() === OUTPUT_END_TOKEN) { ctx.currentAssertion.output = css.stringify({ stylesheet: { rules: ctx.currentOutputRules }, @@ -290,8 +465,8 @@ var parse = function (rawCss, ctxLines) { return parseAssertionOutput; }; - var parseAssertionExpectedStart = function (rule, ctx) { - if (rule.type === 'comment') { + const parseAssertionExpectedStart = (rule: Node, ctx: Context) => { + if (isCommentNode(rule)) { const text = rule.comment.trim(); if (!text) { return parseAssertionExpectedStart; @@ -318,8 +493,8 @@ var parse = function (rawCss, ctxLines) { ); }; - var parseAssertionExpected = function (rule, ctx) { - if (rule.type === 'comment') { + const parseAssertionExpected = (rule: Node, ctx: Context) => { + if (isCommentNode(rule)) { if (rule.comment.trim() === EXPECTED_END_TOKEN) { ctx.currentAssertion.expected = css.stringify({ stylesheet: { rules: ctx.currentExpectedRules }, @@ -334,8 +509,8 @@ var parse = function (rawCss, ctxLines) { return parseAssertionExpected; }; - var parseEndAssertion = function (rule, ctx) { - if (rule.type === 'comment') { + const parseEndAssertion = (rule: Node, ctx: Context) => { + if (isCommentNode(rule)) { const text = rule.comment.trim(); if (!text) { return parseEndAssertion; @@ -357,8 +532,8 @@ var parse = function (rawCss, ctxLines) { ); }; - var parseAssertionContained = function (rule, ctx) { - if (rule.type === 'comment') { + const parseAssertionContained = (rule: Node, ctx: Context) => { + if (isCommentNode(rule)) { if (rule.comment.trim() === CONTAINED_END_TOKEN) { ctx.currentAssertion.expected = css.stringify({ stylesheet: { rules: ctx.currentExpectedRules }, @@ -376,160 +551,4 @@ var parse = function (rawCss, ctxLines) { }; return parseCss(); -}; - -var falsyValues = function (item) { - return Boolean(item); -}; - -var contains = function (output, expected) { - const outputBlocks = createSelectorsRulesPairs(output); - const expectedBlocks = createSelectorsRulesPairs(expected); - - const results = expectedBlocks.map((block) => { - const outputBlock = outputBlocks.find( - (element) => element.selector === block.selector, - ); - if (outputBlock) { - // Turns a css string into an array of property-value pairs. - const expectedProperties = block.output - .split(';') - .map((propertyValuePair) => propertyValuePair.trim()) - .filter((innerBlock) => innerBlock !== ' {' && innerBlock !== '}'); - - // This is the assertion itself! - return expectedProperties.every((property) => - outputBlock.output.includes(property), - ); - } - return false; - }); - - return results.every((result) => result === true); -}; - -var createSelectorsRulesPairs = function (cssString) { - const processedMediaQueries = dealWithAnnoyingMediaQueries(cssString); - const mediaQueries = splitSelectorAndProperties( - processedMediaQueries.mediaQueryBasedSelectors, - ); - const nonMediaQueries = processedMediaQueries.rawCSSSansMediaQueries; - - const blocks = cssStringToArrayOfRules(nonMediaQueries); - - const splitBlocks = splitSelectorAndProperties(blocks); - - return splitBlocks.concat(mediaQueries).filter(falsyValues); -}; - -var splitSelectorAndProperties = function (blocks) { - return blocks.map((block) => { - const temp = block.split('{'); - const selector = temp[0]; - const output = temp[1]; - const splitBlock = { selector, output }; - return splitBlock; - }); -}; - -var removeNewLines = function (cssString) { - return cssString.replace(/\n/g, ''); -}; - -var cssStringToArrayOfRules = function (cssString) { - return removeNewLines(cssString) - .split(/\s*}(?![\s]*["',}])/g) - .filter(falsyValues); -}; - -var dealWithAnnoyingMediaQueries = function (rawCSS) { - const matchMediaQuery = /(@[a-zA-Z0-9:()\s-]+)/g; - // eslint-disable-next-line max-len - const matchCSSWithinMediaQueryBlock = /@[a-zA-Z0-9:()\s-]+{([a-zA-Z0-9:()\s-;._\\n{}]+)(?!}\\n})/g; - - const mediaqueries = rawCSS.match(matchMediaQuery); - const rawCSSSansMediaQueries = rawCSS - .replace(matchMediaQuery, '') - .replace(matchCSSWithinMediaQueryBlock, '') - .replace(/^{/, ''); - let matches = matchCSSWithinMediaQueryBlock.exec(rawCSS); - let i = 0; - let mediaQueryBasedSelectors = []; - const mediaqueryRule = /* istanbul ignore next */ (rule) => - mediaqueries[i] + rule; - /* istanbul ignore next */ - while (matches !== null) { - // This is necessary to avoid infinite loops with zero-width matches - if (matches.index === matchCSSWithinMediaQueryBlock.lastIndex) { - matchCSSWithinMediaQueryBlock.lastIndex++; - } - - /* istanbul ignore next */ - const cssWithinMediaQuery = removeNewLines(matches[1]); - const cssRules = cssStringToArrayOfRules(cssWithinMediaQuery); - - mediaQueryBasedSelectors = mediaQueryBasedSelectors.concat( - cssRules.map(mediaqueryRule), - ); - - i++; - matches = matchCSSWithinMediaQueryBlock.exec(rawCSS); - } - - return { - mediaQueryBasedSelectors, - rawCSSSansMediaQueries, - }; -}; - -var finishCurrentModule = function (ctx) { - finishCurrentTest(ctx); - if (ctx.currentModule) { - const paths = ctx.currentModule.module.split(MODULE_NESTING_TOKEN); - ctx.currentModule.module = last(paths); - insertModule(paths, ctx.currentModule, ctx); - delete ctx.currentModule; - } -}; - -var finishCurrentTest = function (ctx) { - finishCurrentAssertion(ctx); - if (ctx.currentTest) { - ctx.currentModule.tests.push(ctx.currentTest); - delete ctx.currentTest; - } -}; - -var finishCurrentAssertion = function (ctx) { - if (ctx.currentAssertion) { - ctx.currentTest.assertions.push(ctx.currentAssertion); - delete ctx.currentAssertion; - } -}; - -var insertModule = function (paths, module, ctx) { - if (!ctx.modules) { - ctx.modules = []; - } - - if (paths.length > 1) { - let newCtx = find(ctx.modules, { module: paths[0] }); - if (!newCtx) { - newCtx = { module: paths[0] }; - ctx.modules.push(newCtx); - } - insertModule(paths.slice(1), module, newCtx); - } else { - ctx.modules.push(module); - } -}; - -var startsWith = function (text, token) { - return text.substring(0, token.length) === token; -}; - -module.exports = { - runSass, - formatFailureMessage, - parse, -}; +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..d8b6371 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,32 @@ +import { Comment, Node } from 'css'; + +export function falsyValues(item?: any) { + return Boolean(item); +} + +export function isCommentNode(node: Node): node is Comment { + return node.type === 'comment'; +} + +export function startsWith(text: string, token: string) { + return text.indexOf(token) === 0; +} + +export function removeNewLines(cssString: string) { + return cssString.replace(/\n/g, ''); +} + +export function cssStringToArrayOfRules(cssString: string) { + return removeNewLines(cssString) + .split(/\s*}(?![\s]*["',}])/g) + .filter(falsyValues); +} + +export function splitSelectorAndProperties(blocks: string[]) { + return blocks.map((block) => { + const temp = block.split('{'); + const selector = temp[0]; + const output = temp[1]; + return { selector, output }; + }); +} diff --git a/test/test_main.js b/test/test_main.js index 0daa106..1dabd95 100644 --- a/test/test_main.js +++ b/test/test_main.js @@ -1,7 +1,5 @@ /* eslint-env mocha, jest */ -'use strict'; - const path = require('path'); const chalk = require('chalk'); diff --git a/test/test_sass.js b/test/test_sass.js index bfb17a1..e1faa58 100644 --- a/test/test_sass.js +++ b/test/test_sass.js @@ -1,7 +1,5 @@ /* eslint-env mocha, jest */ -'use strict'; - const path = require('path'); const main = require('../lib/main.js'); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..92d9aef --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "sourceMap": true, + "outDir": "lib", + "declaration": true + }, + "exclude": ["node_modules", "lib"] +} diff --git a/yarn.lock b/yarn.lock index 258a90f..f0b331f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -554,11 +554,23 @@ dependencies: "@babel/types" "^7.3.0" +"@types/chalk@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba" + integrity sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw== + dependencies: + chalk "*" + "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/css@0.0.33": + version "0.0.33" + resolved "https://registry.yarnpkg.com/@types/css/-/css-0.0.33.tgz#d0b49c4090c09c8e5dc01364560627e5ebb770f2" + integrity sha512-qjeDgh86R0LIeEM588q65yatc8Yyo/VvSIYFqq8JOIHDolhGNX0rz7k/OuxqDpnpqlefoHj8X4Ai/6hT9IWtKQ== + "@types/graceful-fs@^4.1.2": version "4.1.3" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f" @@ -586,6 +598,11 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/json-schema@^7.0.7": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -601,6 +618,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.24.tgz#b0f86f58564fa02a28b68f8b55d4cdec42e3b9d6" integrity sha512-btt/oNOiDWcSuI721MdL8VQGnjsKjlTMdrKyTcLCKeQp/n4AAMFJ961wMbp+09y8WuGPClDEv07RIItdXKIXAA== +"@types/node@^16.11.11": + version "16.11.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234" + integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw== + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -621,6 +643,13 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== +"@types/sass@^1.43.1": + version "1.43.1" + resolved "https://registry.yarnpkg.com/@types/sass/-/sass-1.43.1.tgz#86bb0168e9e881d7dade6eba16c9ed6d25dc2f68" + integrity sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g== + dependencies: + "@types/node" "*" + "@types/stack-utils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" @@ -643,6 +672,76 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@^4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== + dependencies: + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" + debug "^4.3.1" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.1.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@^4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== + dependencies: + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== + +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== + dependencies: + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== + dependencies: + "@typescript-eslint/types" "4.33.0" + eslint-visitor-keys "^2.0.0" + a-sync-waterfall@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz#75b6b6aa72598b497a125e7a2770f14f4c8a1fa7" @@ -1472,6 +1571,11 @@ chai@^4.1.2: pathval "^1.1.0" type-detect "^4.0.5" +chalk@*: + version "5.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.0.tgz#bd96c6bb8e02b96e08c0c3ee2a9d90e050c7b832" + integrity sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ== + chalk@^1.0.0: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -2111,6 +2215,13 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" +debug@^4.3.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" @@ -2634,6 +2745,14 @@ eslint-scope@^5.1.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + eslint-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" @@ -2641,11 +2760,23 @@ eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + eslint@^7.5.0: version "7.5.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.5.0.tgz#9ecbfad62216d223b82ac9ffea7ef3444671d135" @@ -2716,6 +2847,13 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" @@ -2726,6 +2864,11 @@ estraverse@^5.1.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -3480,6 +3623,18 @@ globby@^11.0.1: merge2 "^1.3.0" slash "^3.0.0" +globby@^11.0.3: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@^8.0.1: version "8.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" @@ -5447,6 +5602,13 @@ lru-cache@^4.0.1: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + lunr@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.8.tgz#a8b89c31f30b5a044b97d2d28e2da191b6ba2072" @@ -7460,6 +7622,13 @@ semver@^7.2.1, semver@^7.3.2: resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + serialize-javascript@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.0.0.tgz#492e489a2d77b7b804ad391a5f5d97870952548e" @@ -8379,6 +8548,18 @@ tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -8442,6 +8623,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@^4.4.4: + version "4.5.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.2.tgz#8ac1fba9f52256fdb06fb89e4122fa6a346c2998" + integrity sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw== + typogr@^0.6.8: version "0.6.8" resolved "https://registry.yarnpkg.com/typogr/-/typogr-0.6.8.tgz#73490c0ddda2cbd20f88c10f7a6974deab455bb4" @@ -9015,6 +9201,11 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yaml@^1.7.2: version "1.10.0" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"