creevey
Version:
Cross-browser screenshot testing tool for Storybook with fancy UI Runner
174 lines (139 loc) • 6.18 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _path = _interopRequireDefault(require("path"));
var _codeFrame = require("@babel/code-frame");
var _loaderUtils = require("loader-utils");
var _schemaUtils = require("schema-utils");
var _parser = require("@babel/parser");
var _traverse = _interopRequireDefault(require("@babel/traverse"));
var _generator = _interopRequireDefault(require("@babel/generator"));
var _helpers = require("../../storybook/helpers");
var _helpers2 = require("../babel/helpers");
var _logger = require("../../logger");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function transform(ast) {
(0, _traverse.default)(ast, { ..._helpers2.commonVisitor,
...(fileType == _helpers2.FileType.Preview ? _helpers2.previewVisitor : undefined),
...(fileType == _helpers2.FileType.Story ? _helpers2.storyVisitor : undefined),
...(isMDX ? _helpers2.mdxVisitor : undefined)
}, undefined, {
resourcePath,
fileType,
isMDX,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
visitedTopPaths: new Set(),
visitedBindings: new Set(),
reexportedStories
});
return (0, _generator.default)(ast, {
retainLines: true
}).code;
}
function toPosix(filePath) {
return filePath.split(_path.default.win32.sep).join(_path.default.posix.sep).replace(/^[a-z]:/i, '');
}
function getIssuerResource(context) {
var _context$_module, _context$_module$issu;
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return
return (_context$_module = context._module) === null || _context$_module === void 0 ? void 0 : (_context$_module$issu = _context$_module.issuer) === null || _context$_module$issu === void 0 ? void 0 : _context$_module$issu.resource;
}
function getIssuerConstructorName(context) {
var _context$_module2, _context$_module2$iss, _context$_module2$iss2;
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return
return (_context$_module2 = context._module) === null || _context$_module2 === void 0 ? void 0 : (_context$_module2$iss = _context$_module2.issuer) === null || _context$_module2$iss === void 0 ? void 0 : (_context$_module2$iss2 = _context$_module2$iss.constructor) === null || _context$_module2$iss2 === void 0 ? void 0 : _context$_module2$iss2.name;
}
function isEntry(context) {
return getIssuerConstructorName(context) == 'MultiModule';
}
function isPreview(context, options) {
const {
dir: resourceDir,
name: resourceName
} = _path.default.posix.parse(toPosix(context.resourcePath));
const storybookDir = typeof options.storybookDir == 'string' ? toPosix(options.storybookDir) : '';
const isConfigFile = resourceDir == storybookDir && (resourceName == 'preview' || resourceName == 'config');
if ((0, _helpers.isStorybookVersionLessThan)(6)) {
return isEntry(context) && isConfigFile;
}
const issuerResource = getIssuerResource(context);
return Boolean(issuerResource && entries.has(issuerResource) && isConfigFile);
}
function isStoryFile(context) {
var _reexportedStories$ge, _context$_module3;
const issuerResource = getIssuerResource(context);
return getIssuerConstructorName(context) == 'ContextModule' || // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Boolean(issuerResource && ((_reexportedStories$ge = reexportedStories.get(issuerResource)) === null || _reexportedStories$ge === void 0 ? void 0 : _reexportedStories$ge.has((_context$_module3 = context._module) === null || _context$_module3 === void 0 ? void 0 : _context$_module3.rawRequest))) || issuerResource == previewPath && _path.default.posix.parse(toPosix(previewPath)).name == 'config';
} // NOTE: non-story files before preview => issuer.resource is entry
const schema = {
type: 'object',
properties: {
debug: {
type: 'boolean'
},
storybookDir: {
type: 'string'
}
}
};
let fileType = _helpers2.FileType.Invalid;
let isMDX = false;
let previewPath = '';
let resourcePath = '';
const entries = new Set();
const stories = new Set();
const reexportedStories = new Map();
const isTest = process.env.__CREEVEY_ENV__ == 'test';
const defaultOptions = {
debug: isTest,
storybookDir: process.cwd()
};
function _default(source) {
const options = this ? (0, _loaderUtils.getOptions)(this) || defaultOptions : defaultOptions;
(0, _schemaUtils.validate)(schema, options, {
name: 'Creevey Stories Loader'
});
fileType = _helpers2.FileType.Invalid;
if (this) {
const issuerResource = getIssuerResource(this);
resourcePath = this.resourcePath;
if (isStoryFile(this)) {
fileType = _helpers2.FileType.Story;
isMDX = _path.default.parse(resourcePath).ext == '.mdx';
stories.add(this.resourcePath);
} else if (isPreview(this, options)) {
fileType = _helpers2.FileType.Preview;
previewPath = this.resourcePath;
} else if (isEntry(this)) {
fileType = _helpers2.FileType.Entry;
entries.add(this.resourcePath);
return source;
} else if (issuerResource && stories.has(issuerResource) && options.debug) {
_logger.logger.warn('Trying to transform possible non-story file', this.resourcePath, 'Please check the', issuerResource); // TODO Add link to docs, how creevey works and what user should do in this situation
}
}
if (isTest && !Number.isNaN(Number(process.env.CREEVEY_LOADER_FILE_TYPE))) {
fileType = Number(process.env.CREEVEY_LOADER_FILE_TYPE);
}
try {
const ast = (0, _parser.parse)(source, {
sourceType: 'module',
plugins: ['classProperties', 'decorators-legacy', 'jsx', 'typescript']
});
return transform(ast);
} catch (error) {
this && _logger.logger.warn('Failed to transform file', this.resourcePath);
if ('loc' in error) {
_logger.logger.warn((0, _codeFrame.codeFrameColumns)(source, {
start: error.loc
}, {
highlightCode: true
}));
} else {
_logger.logger.warn(error);
}
return source;
}
}