initial check0in

This commit is contained in:
atanasster 2020-01-19 23:35:50 -05:00
parent 4a5508dfec
commit 554b379bfa
20 changed files with 268 additions and 512 deletions

View File

@ -24,15 +24,19 @@
"*.d.ts"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"prepare": "node ../../scripts/prepare.js"
},
"dependencies": {
"@storybook/addons": "5.3.5",
"@storybook/api": "5.3.5",
"@storybook/components": "5.3.5",
"@storybook/core-events": "5.3.5",
"@storybook/router": "5.3.5",
"@storybook/source-loader": "5.3.5",
"@storybook/theming": "5.3.5",
"@types/react-syntax-highlighter": "11.0.2",
"core-js": "^3.0.1",
"estraverse": "^4.2.0",
"loader-utils": "^1.2.3",
@ -42,6 +46,9 @@
"regenerator-runtime": "^0.13.3",
"util-deprecate": "^1.0.2"
},
"devDependencies": {
"@types/react-syntax-highlighter": "^11.0.4"
},
"peerDependencies": {
"@storybook/source-loader": "*",
"react": "*"

View File

@ -1,188 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { styled } from '@storybook/theming';
import { Link } from '@storybook/router';
import { SyntaxHighlighter } from '@storybook/components';
import createElement from 'react-syntax-highlighter/dist/esm/create-element';
import { EVENT_ID } from './events';
const StyledStoryLink = styled(Link)(({ theme }) => ({
display: 'block',
textDecoration: 'none',
borderRadius: theme.appBorderRadius,
color: 'inherit',
'&:hover': {
background: theme.background.hoverable,
},
}));
const SelectedStoryHighlight = styled.div(({ theme }) => ({
background: theme.background.hoverable,
borderRadius: theme.appBorderRadius,
}));
const StyledSyntaxHighlighter = styled(SyntaxHighlighter)(({ theme }) => ({
fontSize: theme.typography.size.s2 - 1,
}));
const areLocationsEqual = (a, b) =>
a.startLoc.line === b.startLoc.line &&
a.startLoc.col === b.startLoc.col &&
a.endLoc.line === b.endLoc.line &&
a.endLoc.col === b.endLoc.col;
const getLocationKeys = locationsMap =>
locationsMap
? Array.from(Object.keys(locationsMap)).sort(
(key1, key2) => locationsMap[key1].startLoc.line - locationsMap[key2].startLoc.line
)
: [];
export default class StoryPanel extends Component {
state = { source: 'loading source...' };
componentDidMount() {
this.mounted = true;
const { api } = this.props;
api.on(EVENT_ID, this.listener);
}
componentDidUpdate() {
if (this.selectedStoryRef) {
this.selectedStoryRef.scrollIntoView();
}
}
componentWillUnmount() {
const { api } = this.props;
api.off(EVENT_ID, this.listener);
}
setSelectedStoryRef = ref => {
this.selectedStoryRef = ref;
};
listener = ({ edition: { source }, location: { currentLocation, locationsMap } }) => {
const locationsKeys = getLocationKeys(locationsMap);
this.setState({
source,
currentLocation,
locationsMap,
locationsKeys,
});
};
createPart = (rows, stylesheet, useInlineStyles) =>
rows.map((node, i) =>
createElement({
node,
stylesheet,
useInlineStyles,
key: `code-segement${i}`,
})
);
createStoryPart = (rows, stylesheet, useInlineStyles, location, id) => {
const { currentLocation } = this.state;
const first = location.startLoc.line - 1;
const last = location.endLoc.line;
const storyRows = rows.slice(first, last);
const story = this.createPart(storyRows, stylesheet, useInlineStyles);
const storyKey = `${first}-${last}`;
if (location && currentLocation && areLocationsEqual(location, currentLocation)) {
return (
<SelectedStoryHighlight key={storyKey} ref={this.setSelectedStoryRef}>
{story}
</SelectedStoryHighlight>
);
}
return (
<StyledStoryLink to={`/story/${id}`} key={storyKey}>
{story}
</StyledStoryLink>
);
};
createParts = (rows, stylesheet, useInlineStyles) => {
const { locationsMap, locationsKeys } = this.state;
const parts = [];
let lastRow = 0;
locationsKeys.forEach(key => {
const location = locationsMap[key];
const first = location.startLoc.line - 1;
const last = location.endLoc.line;
const start = this.createPart(rows.slice(lastRow, first), stylesheet, useInlineStyles);
const storyPart = this.createStoryPart(rows, stylesheet, useInlineStyles, location, key);
parts.push(start);
parts.push(storyPart);
lastRow = last;
});
const lastPart = this.createPart(rows.slice(lastRow), stylesheet, useInlineStyles);
parts.push(lastPart);
return parts;
};
lineRenderer = ({ rows, stylesheet, useInlineStyles }) => {
const { locationsMap, locationsKeys } = this.state;
// because of the usage of lineRenderer, all lines will be wrapped in a span
// these spans will receive all classes on them for some reason
// which makes colours casecade incorrectly
// this removed that list of classnames
const myrows = rows.map(({ properties, ...rest }) => ({
...rest,
properties: { className: [] },
}));
if (!locationsMap || !locationsKeys.length) {
return this.createPart(myrows, stylesheet, useInlineStyles);
}
const parts = this.createParts(myrows, stylesheet, useInlineStyles);
return <span>{parts}</span>;
};
render() {
const { active } = this.props;
const { source } = this.state;
return active ? (
<StyledSyntaxHighlighter
language="jsx"
showLineNumbers="true"
renderer={this.lineRenderer}
format={false}
copyable={false}
padded
>
{source}
</StyledSyntaxHighlighter>
) : null;
}
}
StoryPanel.propTypes = {
active: PropTypes.bool.isRequired,
api: PropTypes.shape({
selectStory: PropTypes.func.isRequired,
emit: PropTypes.func,
on: PropTypes.func,
off: PropTypes.func,
}).isRequired,
};

View File

@ -0,0 +1,209 @@
import React from 'react';
import { API } from '@storybook/api';
import { styled } from '@storybook/theming';
import { Link } from '@storybook/router';
import {
SyntaxHighlighter,
SyntaxHighlighterProps,
SyntaxHighlighterRendererProps,
} from '@storybook/components';
import createElement from 'react-syntax-highlighter/dist/esm/create-element';
const StyledStoryLink = styled(Link)<{ to: string; key: string }>(({ theme }) => ({
display: 'block',
textDecoration: 'none',
borderRadius: theme.appBorderRadius,
color: 'inherit',
'&:hover': {
background: theme.background.hoverable,
},
}));
const SelectedStoryHighlight = styled.div<{ ref: React.RefObject<HTMLDivElement>; key: string }>(
({ theme }) => ({
background: theme.background.hoverable,
borderRadius: theme.appBorderRadius,
})
);
const StyledSyntaxHighlighter = styled(SyntaxHighlighter)<SyntaxHighlighterProps>(({ theme }) => ({
fontSize: theme.typography.size.s2 - 1,
}));
interface SourceLoc {
line: number;
col: number;
}
interface SourceBlock {
startLoc: SourceLoc;
endLoc: SourceLoc;
}
const areLocationsEqual = (a: SourceBlock, b: SourceBlock): boolean =>
a.startLoc.line === b.startLoc.line &&
a.startLoc.col === b.startLoc.col &&
a.endLoc.line === b.endLoc.line &&
a.endLoc.col === b.endLoc.col;
interface LocationsMap {
[key: string]: SourceBlock;
}
const getLocationKeys = (locationsMap: LocationsMap) =>
locationsMap
? Array.from(Object.keys(locationsMap)).sort(
(key1, key2) => locationsMap[key1].startLoc.line - locationsMap[key2].startLoc.line
)
: [];
interface StoryPanelProps {
api: API;
}
interface SourceParams {
source: string;
locationsMap: LocationsMap;
}
export interface StoryData {
id: string;
kind?: string;
parameters?: {
storySource?: SourceParams;
};
}
export const StoryPanel: React.FC<StoryPanelProps> = ({ api }) => {
const [state, setState] = React.useState<SourceParams & { currentLocation?: SourceBlock }>({
source: 'loading source...',
locationsMap: {},
});
const story: StoryData | undefined = api.getCurrentStoryData();
const selectedStoryRef = React.useRef<HTMLDivElement>();
React.useEffect(() => {
if (story) {
const {
parameters: {
storySource: { source, locationsMap } = { source: '', locationsMap: {} },
} = {},
} = story;
const currentLocation =
locationsMap[
Object.keys(locationsMap).find((key: string) => {
const sourceLoaderId = key.split('--');
return story.id.endsWith(sourceLoaderId[sourceLoaderId.length - 1]);
})
];
setState({ source, locationsMap, currentLocation });
}
}, [story ? story.id : null]);
React.useEffect(() => {
if (selectedStoryRef.current) {
selectedStoryRef.current.scrollIntoView();
}
}, [selectedStoryRef.current]);
const { source, locationsMap, currentLocation } = state;
const createPart = ({ rows, stylesheet, useInlineStyles }: SyntaxHighlighterRendererProps) =>
rows.map((node, i) =>
createElement({
node,
stylesheet,
useInlineStyles,
key: `code-segement${i}`,
})
);
const createStoryPart = ({
rows,
stylesheet,
useInlineStyles,
location,
id,
}: SyntaxHighlighterRendererProps & { location: SourceBlock; id: string }): React.ReactNode => {
const first = location.startLoc.line - 1;
const last = location.endLoc.line;
const storyRows = rows.slice(first, last);
const storySource = createPart({ rows: storyRows, stylesheet, useInlineStyles });
const storyKey = `${first}-${last}`;
if (location && currentLocation && areLocationsEqual(location, currentLocation)) {
return (
<SelectedStoryHighlight key={storyKey} ref={selectedStoryRef}>
{storySource}
</SelectedStoryHighlight>
);
}
return (
<StyledStoryLink to={`/story/${id}`} key={storyKey}>
{storySource}
</StyledStoryLink>
);
};
const createParts = ({ rows, stylesheet, useInlineStyles }: SyntaxHighlighterRendererProps) => {
const parts = [];
let lastRow = 0;
Object.keys(locationsMap).forEach(key => {
const location = locationsMap[key];
const first = location.startLoc.line - 1;
const last = location.endLoc.line;
const { kind } = story;
// source loader ids are differnet from story id
const sourceIdParts = key.split('--');
const id = api.storyId(kind, sourceIdParts[sourceIdParts.length - 1]);
const start = createPart({ rows: rows.slice(lastRow, first), stylesheet, useInlineStyles });
const storyPart = createStoryPart({ rows, stylesheet, useInlineStyles, location, id });
parts.push(start);
parts.push(storyPart);
lastRow = last;
});
const lastPart = createPart({ rows: rows.slice(lastRow), stylesheet, useInlineStyles });
parts.push(lastPart);
return parts;
};
const lineRenderer = ({
rows,
stylesheet,
useInlineStyles,
}: SyntaxHighlighterRendererProps): React.ReactNode => {
// because of the usage of lineRenderer, all lines will be wrapped in a span
// these spans will receive all classes on them for some reason
// which makes colours casecade incorrectly
// this removed that list of classnames
const myrows = rows.map(({ properties, ...rest }) => ({
...rest,
properties: { className: [] },
}));
if (!locationsMap || !Object.keys(locationsMap).length) {
return createPart({ rows: myrows, stylesheet, useInlineStyles });
}
const parts = createParts({ rows: myrows, stylesheet, useInlineStyles });
return <span>{parts}</span>;
};
return (
<StyledSyntaxHighlighter
language="jsx"
showLineNumbers
renderer={lineRenderer}
format={false}
copyable={false}
padded
>
{source}
</StyledSyntaxHighlighter>
);
};

View File

@ -1,3 +1,2 @@
export const ADDON_ID = 'storybook/source-loader';
export const PANEL_ID = `${ADDON_ID}/panel`;
export const EVENT_ID = `${ADDON_ID}/set`;

View File

@ -1,8 +0,0 @@
import { ADDON_ID, PANEL_ID, EVENT_ID } from './events';
import { withStorySource } from './preview';
export { ADDON_ID, PANEL_ID, EVENT_ID, withStorySource };
if (module && module.hot && module.hot.decline) {
module.hot.decline();
}

View File

@ -0,0 +1,7 @@
import { ADDON_ID, PANEL_ID } from './events';
export { ADDON_ID, PANEL_ID };
if (module && module.hot && module.hot.decline) {
module.hot.decline();
}

View File

@ -1,15 +1,15 @@
/* eslint-disable react/prop-types */
import React from 'react';
import addons from '@storybook/addons';
import StoryPanel from './StoryPanel';
import { StoryPanel } from './StoryPanel';
import { ADDON_ID, PANEL_ID } from '.';
export function register() {
addons.register(ADDON_ID, api => {
addons.addPanel(PANEL_ID, {
title: 'Story',
render: ({ active, key }) => <StoryPanel key={key} api={api} active={active} />,
render: ({ active, key }) =>
active ? <StoryPanel key={key} api={api} active={active} /> : null,
paramKey: 'storysource',
});
});

View File

@ -1,21 +0,0 @@
import addons from '@storybook/addons';
import { EVENT_ID } from './events';
const getLocation = (context, locationsMap) => locationsMap[context.id];
function setStorySource(context, source, locationsMap) {
const currentLocation = getLocation(context, locationsMap);
addons.getChannel().emit(EVENT_ID, {
source,
currentLocation,
locationsMap,
});
}
export function withStorySource(source, locationsMap = {}) {
return (storyFn, context) => {
setStorySource(context, source, locationsMap);
return storyFn();
};
}

1
addons/storysource/src/typings.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module 'react-syntax-highlighter/dist/esm/create-element';

View File

@ -1,9 +1,7 @@
module.exports = {
stories: [
// FIXME: Breaks e2e tests './intro.stories.mdx',
'../../lib/ui/src/**/*.stories.(js|tsx|mdx)',
'../../lib/components/src/**/*.stories.(js|tsx|mdx)',
'./stories/**/*.stories.(js|tsx|mdx)',
'../../lib/ui/src/components/notifications/item.stories.js',
],
addons: [
'@storybook/addon-docs',

View File

@ -3,7 +3,11 @@ export { Badge } from './Badge/Badge';
// Typography
export { Link } from './typography/link/link';
export { DocumentWrapper } from './typography/DocumentWrapper';
export { SyntaxHighlighter } from './syntaxhighlighter/syntaxhighlighter';
export {
SyntaxHighlighter,
SyntaxHighlighterProps,
SyntaxHighlighterRendererProps,
} from './syntaxhighlighter/syntaxhighlighter';
// UI
export { ActionBar } from './ActionBar/ActionBar';

View File

@ -82,6 +82,11 @@ const Code = styled.code({
opacity: 1,
});
export interface SyntaxHighlighterRendererProps {
rows: any[];
stylesheet: string;
useInlineStyles: boolean;
}
export interface SyntaxHighlighterProps {
language: string;
copyable?: boolean;
@ -89,6 +94,7 @@ export interface SyntaxHighlighterProps {
padded?: boolean;
format?: boolean;
className?: string;
renderer?: (props: SyntaxHighlighterRendererProps) => React.ReactNode;
}
export interface SyntaxHighlighterState {

View File

@ -1,2 +0,0 @@
export const ADDON_ID = 'storybook/source-loader';
export const STORY_EVENT_ID = `${ADDON_ID}/set`;

View File

@ -1,100 +0,0 @@
import addons from '@storybook/addons';
import { logger } from '@storybook/client-logger';
import { STORY_EVENT_ID } from './events';
const getLocation = (context, locationsMap) => locationsMap[context.id];
function sendEvent(
context,
source,
locationsMap,
mainFileLocation,
dependencies,
localDependencies,
prefix,
idsToFrameworks
) {
if (!context || !context.id || !context.kind || !context.story) {
logger.warn(
'@storybook/source-loader was applied to a file which does not contain a story. Please check your webpack configuration and make sure to apply @storybook/source-loader only to files containg stories. Related file:'
);
logger.warn(source);
return;
}
const channel = addons.getChannel();
const currentLocation = getLocation(context, locationsMap);
channel.emit(STORY_EVENT_ID, {
edition: {
source,
mainFileLocation,
dependencies,
localDependencies,
prefix,
idsToFrameworks,
},
story: {
kind: context.kind,
story: context.story,
},
location: {
currentLocation,
locationsMap,
},
});
}
export function addSource(storyFn, sourceContext) {
const {
__STORY__: source,
__ADDS_MAP__: locationsMap = {},
__MAIN_FILE_LOCATION__: mainFileLocation = '/index.js',
__MODULE_DEPENDENCIES__: dependencies = [],
__LOCAL_DEPENDENCIES__: localDependencies = {},
__SOURCE_PREFIX__: prefix,
__IDS_TO_FRAMEWORKS__: idsToFrameworks,
} = sourceContext;
const decorated = (context = {}) => {
sendEvent(
context,
source,
locationsMap,
mainFileLocation,
dependencies,
localDependencies,
prefix,
idsToFrameworks
);
if (typeof storyFn === 'function') {
return storyFn(context);
}
return storyFn;
};
decorated.story = (storyFn || {}).story;
return decorated;
}
export function withSource(
source,
locationsMap = {},
mainFileLocation = '/index.js',
dependencies = [],
localDependencies = {},
prefix,
idsToFrameworks
) {
return (storyFn, context) => {
sendEvent(
context,
source,
locationsMap,
mainFileLocation,
dependencies,
localDependencies,
prefix,
idsToFrameworks
);
return storyFn(context);
};
}

View File

@ -3,7 +3,6 @@ import getParser from './parsers';
import {
splitSTORYOF,
findAddsMap,
findDependencies,
splitExports,
popParametersObjectFromDefaultExport,
findExportsMap as generateExportsMap,
@ -69,8 +68,8 @@ const ADD_PARAMETERS_STATEMENT =
'.addParameters({ storySource: { source: __STORY__, locationsMap: __ADDS_MAP__ } })';
const applyExportDecoratorStatement = part =>
part.declaration.isVariableDeclaration
? ` addSourceDecorator(${part.source}, {__STORY__, __ADDS_MAP__,__MAIN_FILE_LOCATION__,__MODULE_DEPENDENCIES__,__LOCAL_DEPENDENCIES__,__SOURCE_PREFIX__,__IDS_TO_FRAMEWORKS__});`
: ` const ${part.declaration.ident} = addSourceDecorator(${part.source}, {__STORY__, __ADDS_MAP__,__MAIN_FILE_LOCATION__,__MODULE_DEPENDENCIES__,__LOCAL_DEPENDENCIES__,__SOURCE_PREFIX__,__IDS_TO_FRAMEWORKS__});`;
? ` ${part.source};`
: ` const ${part.declaration.ident} = ${part.source};`;
export function generateSourceWithDecorators(source, ast, withParameters) {
const { comments = [] } = ast;
@ -120,7 +119,7 @@ export function generateAddsMap(ast, storiesOfIdentifiers) {
export function generateStoriesLocationsMap(ast, storiesOfIdentifiers) {
const usingAddsMap = generateAddsMap(ast, storiesOfIdentifiers);
const { addsMap } = usingAddsMap;
const addsMap = usingAddsMap;
if (Object.keys(addsMap).length > 0) {
return usingAddsMap;
@ -130,10 +129,6 @@ export function generateStoriesLocationsMap(ast, storiesOfIdentifiers) {
return usingExportsMap || usingAddsMap;
}
export function generateDependencies(ast) {
return findDependencies(ast);
}
export function generateStorySource({ source, ...options }) {
let storySource = source;

View File

@ -6,7 +6,6 @@ import {
generateSourceWithoutDecorators,
generateStorySource,
generateStoriesLocationsMap,
generateDependencies,
generateSourcesInExportedParameters,
} from './generate-helpers';
@ -21,7 +20,7 @@ function extendOptions(source, comments, filepath, options) {
}
function inject(source, filepath, options = {}, log = message => {}) {
const { injectDecorator = true, injectParameters = true, inspectDependencies } = options;
const { injectDecorator = true, injectParameters = true } = options;
const obviouslyNotCode = ['md', 'txt', 'json'].includes(options.parser);
let parser = null;
try {
@ -36,7 +35,6 @@ function inject(source, filepath, options = {}, log = message => {}) {
storySource: {},
addsMap: {},
changed: false,
dependencies: [],
};
}
const ast = parser.parse(source);
@ -48,10 +46,7 @@ function inject(source, filepath, options = {}, log = message => {}) {
const storySource = generateStorySource(extendOptions(source, comments, filepath, options));
const newAst = parser.parse(storySource);
const { dependencies, storiesOfIdentifiers } = inspectDependencies
? generateDependencies(newAst)
: { dependencies: [], storiesOfIdentifiers: {} };
const { addsMap, idsToFrameworks } = generateStoriesLocationsMap(newAst, storiesOfIdentifiers);
const addsMap = generateStoriesLocationsMap(newAst, []);
let newSource = cleanedSource;
if (exportTokenFound) {
@ -68,8 +63,6 @@ function inject(source, filepath, options = {}, log = message => {}) {
storySource,
addsMap: {},
changed,
dependencies,
idsToFrameworks: idsToFrameworks || {},
};
}
@ -78,8 +71,6 @@ function inject(source, filepath, options = {}, log = message => {}) {
storySource,
addsMap,
changed,
dependencies,
idsToFrameworks: idsToFrameworks || {},
};
}

View File

@ -139,7 +139,6 @@ export function splitExports(ast, source) {
export function findAddsMap(ast, storiesOfIdentifiers) {
const addsMap = {};
const idsToFrameworks = {};
estraverse.traverse(ast, {
fallback: 'iteration',
@ -149,17 +148,15 @@ export function findAddsMap(ast, storiesOfIdentifiers) {
if (node.type === 'MemberExpression') {
const { toAdd, idToFramework } = handleADD(node, parent, storiesOfIdentifiers);
Object.assign(addsMap, toAdd);
Object.assign(idsToFrameworks, idToFramework);
}
},
});
return { addsMap, idsToFrameworks };
return addsMap;
}
export function findExportsMap(ast) {
const addsMap = {};
const idsToFrameworks = {};
const program = (ast && ast.program) || ast;
const metaDeclaration =
program &&
@ -177,7 +174,7 @@ export function findExportsMap(ast) {
metaDeclaration.declaration.properties.find(p => p.key && p.key.name === 'title');
if (!titleProperty) {
return { addsMap, idsToFrameworks };
return addsMap;
}
const titleValue = titleProperty.value;
let title;
@ -229,32 +226,7 @@ export function findExportsMap(ast) {
},
});
}
return { addsMap, idsToFrameworks };
}
export function findDependencies(ast) {
const dependencies = [];
const storiesOfIdentifiers = {};
estraverse.traverse(ast, {
fallback: 'iteration',
enter: node => {
patchNode(node);
if (node.type === 'ImportDeclaration') {
const candidateSpecifier = (node.specifiers || []).find(
s => (s.imported || {}).name === 'storiesOf'
);
if (node.source.value.startsWith('@storybook/') && candidateSpecifier) {
Object.assign(storiesOfIdentifiers, {
[candidateSpecifier.local.name]: node.source.value,
});
}
dependencies.push(node.source.value);
}
},
});
return { dependencies, storiesOfIdentifiers };
return addsMap;
}
export function popParametersObjectFromDefaultExport(source, ast) {

View File

@ -1,54 +1,23 @@
import { readStory } from './dependencies-lookup/readAsObject';
import { getRidOfUselessFilePrefixes } from './dependencies-lookup/getRidOfUselessFilePrefixes';
export function transform(inputSource) {
return readStory(this, inputSource)
.then(sourceObject => {
// if source-loader had trouble parsing the story exports, return the original story
// example is
// const myStory = () => xxx
// export { myStory }
if (!sourceObject.source || sourceObject.source.length === 0) {
return { source: inputSource };
}
return getRidOfUselessFilePrefixes(sourceObject);
})
.then(
({
prefix,
resource,
source,
sourceJson,
addsMap,
dependencies,
localDependencies,
idsToFrameworks,
}) => {
const preamble = prefix
? `
/* eslint-disable */
// @ts-nocheck
// @ts-ignore
var withSourceLoader = require('@storybook/source-loader/preview').withSource;
// @ts-ignore
var addSourceDecorator = require("@storybook/source-loader/preview").addSource;
// @ts-ignore
var __SOURCE_PREFIX__ = "${prefix.replace(/\\([^\\ ])/g, '\\\\$1')}";
// @ts-ignore
var __STORY__ = ${sourceJson};
// @ts-ignore
var __ADDS_MAP__ = ${JSON.stringify(addsMap)};
// @ts-ignore
var __MAIN_FILE_LOCATION__ = ${JSON.stringify(resource)};
// @ts-ignore
var __MODULE_DEPENDENCIES__ = ${JSON.stringify(dependencies)};
// @ts-ignore
var __LOCAL_DEPENDENCIES__ = ${JSON.stringify(localDependencies)};
// @ts-ignore
var __IDS_TO_FRAMEWORKS__ = ${JSON.stringify(idsToFrameworks)};
`
: '';
return `${preamble}\n${source}`;
}
);
return readStory(this, inputSource).then(sourceObject => {
// if source-loader had trouble parsing the story exports, return the original story
// example is
// const myStory = () => xxx
// export { myStory }
if (!sourceObject.source || sourceObject.source.length === 0) {
return inputSource;
}
const { source, sourceJson, addsMap } = sourceObject;
const preamble = `
/* eslint-disable */
// @ts-nocheck
// @ts-ignore
var __STORY__ = ${sourceJson};
// @ts-ignore
var __ADDS_MAP__ = ${JSON.stringify(addsMap)};
`;
return `${preamble}\n${source}`;
});
}

View File

@ -1,46 +0,0 @@
import path from 'path';
function commonDir(...resources) {
const firstResource = (resources[0] || '').split(path.sep);
let i = 1;
while (
i < firstResource.length &&
// eslint-disable-next-line no-loop-func
resources.every(resource => resource.startsWith(firstResource.slice(0, i).join(path.sep)))
) {
i += 1;
}
return firstResource.slice(0, i - 1).join(path.sep);
}
export function getRidOfUselessFilePrefixes({
resource,
source,
sourceJson,
addsMap,
dependencies,
localDependencies,
idsToFrameworks,
}) {
const commondir = commonDir(resource, ...Object.keys(localDependencies || {}));
return {
prefix: commondir,
source,
sourceJson,
addsMap,
dependencies,
idsToFrameworks,
resource:
commondir === resource
? '/index.js'
: resource.substring(commondir.length).replace(path.sep === '\\' ? /\\/g : /\//g, '/'),
localDependencies: Object.assign(
{},
...Object.entries(localDependencies || {}).map(([depFileName, dependency]) => ({
[depFileName
.substring(commondir.length)
.replace(new RegExp(path.sep === '\\' ? /\\/g : /\//g, 'g'), '/')]: dependency,
}))
),
};
}

View File

@ -2,29 +2,8 @@ import { getOptions } from 'loader-utils';
import path from 'path';
import injectDecorator from '../abstract-syntax-tree/inject-decorator';
function extractDependenciesFrom(tree) {
return !Object.entries(tree || {}).length
? []
: Object.entries(tree)
.map(([, value]) =>
(value.dependencies || []).concat(extractDependenciesFrom(value.localDependencies))
)
.reduce((acc, value) => acc.concat(value), []);
}
function extractLocalDependenciesFrom(tree) {
return Object.assign(
{},
...Object.entries(tree || {}).map(([thisPath, value]) => ({
[thisPath]: { code: value.source || value.code },
...extractLocalDependenciesFrom(value.localDependencies),
}))
);
}
function readAsObject(classLoader, inputSource, mainFile) {
const options = getOptions(classLoader) || {};
const { inspectLocalDependencies } = options;
const result = injectDecorator(
inputSource,
classLoader.resourcePath,
@ -40,15 +19,10 @@ function readAsObject(classLoader, inputSource, mainFile) {
.replace(/\u2029/g, '\\u2029');
const addsMap = result.addsMap || {};
const dependencies = result.dependencies || [];
const source = mainFile ? result.source : inputSource;
const idsToFrameworks = result.idsToFrameworks || {};
const resource = classLoader.resourcePath || classLoader.resource;
const moduleDependencies = (result.dependencies || []).filter(d => d[0] === '.' || d[0] === '/');
const workspaceFileNames = inspectLocalDependencies
? moduleDependencies.map(d => path.join(path.dirname(resource), d))
: [];
const workspaceFileNames = [];
return Promise.all(
workspaceFileNames.map(
@ -97,22 +71,11 @@ function readAsObject(classLoader, inputSource, mainFile) {
)
)
)
.then(localDependencies => ({
.then(() => ({
resource,
source,
sourceJson,
addsMap,
idsToFrameworks,
dependencies: dependencies
.concat(extractDependenciesFrom(localDependencies))
.filter(d => d[0] !== '.' && d[0] !== '/')
.map(d => (d[0] === '@' ? `${d.split('/')[0]}/${d.split('/')[1]}` : d.split('/')[0])),
localDependencies: Object.assign(
...Object.entries(localDependencies).map(([name, value]) => ({
[name]: { code: value.source },
})),
extractLocalDependenciesFrom(localDependencies)
),
}));
}