Skip to content

Commit

Permalink
feat: component jsx explorer
Browse files Browse the repository at this point in the history
  • Loading branch information
atanasster committed Nov 30, 2020
1 parent 34f83b9 commit c530e29
Show file tree
Hide file tree
Showing 66 changed files with 11,856 additions and 8,913 deletions.
6 changes: 4 additions & 2 deletions core/config/test/__snapshots__/stories.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ Array [
"/Users/atanasster/component-controls/ui/components/src/LinkHeading/LinkHeading.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Markdown/Markdown.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Multiselect/Multiselect.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Navmenu/Navmenu.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Pagination/Pagination.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/PanelContainer/PanelContainer.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Popover/Popover.stories.tsx",
Expand All @@ -43,9 +42,11 @@ Array [
"/Users/atanasster/component-controls/ui/components/src/Title/Title.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/TitledImage/TitledImage.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Toggle/Toggle.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Tree/Tree.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Value/Value.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Zoom/Zoom.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/ComponentDependencies/ComponentDeps.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/ComponentJSX/ComponentJSX.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/ComponentSource/ComponentSource.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/Container/Container.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/Description/Description.stories.tsx",
Expand Down Expand Up @@ -104,7 +105,6 @@ Array [
"/Users/atanasster/component-controls/ui/components/src/LinkHeading/LinkHeading.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Markdown/Markdown.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Multiselect/Multiselect.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Navmenu/Navmenu.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Pagination/Pagination.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/PanelContainer/PanelContainer.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Popover/Popover.stories.tsx",
Expand All @@ -120,9 +120,11 @@ Array [
"/Users/atanasster/component-controls/ui/components/src/Title/Title.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/TitledImage/TitledImage.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Toggle/Toggle.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Tree/Tree.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Value/Value.stories.tsx",
"/Users/atanasster/component-controls/ui/components/src/Zoom/Zoom.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/ComponentDependencies/ComponentDeps.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/ComponentJSX/ComponentJSX.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/ComponentSource/ComponentSource.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/Container/Container.stories.tsx",
"/Users/atanasster/component-controls/ui/blocks/src/Description/Description.stories.tsx",
Expand Down
2 changes: 1 addition & 1 deletion core/core/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export interface ComponentInfo {

export type JSXNode = Partial<ImportType> & {
attributes?: string[];
children?: Partial<ImportType>[];
children?: JSXTree;
};
/**
* jsx tree of elements for the component
Expand Down
5 changes: 4 additions & 1 deletion core/core/src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export interface ImportType {
/**
* key into components table
*/
key?: string;
componentKey?: string;
}

export interface ImportTypes {
Expand Down Expand Up @@ -234,3 +234,6 @@ export const useAsync = <T, E = string>(

return { execute, status, value, error };
};

export const isLocalImport = (filePath: string): boolean =>
filePath.startsWith('.');
76 changes: 65 additions & 11 deletions core/instrument/src/babel/analyze-component.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,81 @@
import fs from 'fs';
import * as parser from '@babel/parser';
import path from 'path';
import traverse, { TraverseOptions } from '@babel/traverse';
import { Component, JSXNode, JSXTree } from '@component-controls/core';
import {
JSXIdentifier,
JSXMemberExpression,
JSXNamespacedName,
} from '@babel/types';
import * as resolve from 'resolve';
import {
Component,
JSXNode,
JSXTree,
ImportTypes,
isLocalImport,
} from '@component-controls/core';
import { collectAttributes } from './extract-attributes';
import { componentKey } from '../misc/hashStore';
import { followImports } from './follow-imports';
import { parseFile, parseImports } from '../misc/ast_store';
import { InstrumentOptions } from '../types';

type JSXLinkedNode = JSXNode & { parent?: JSXNode };
type JSXLinkedTree = JSXLinkedNode[];

export const traverseJSX = (jsx: JSXLinkedTree): TraverseOptions => {
const traverseJSX = (
jsx: JSXLinkedTree,
imports: ImportTypes,
filePath: string,
options?: InstrumentOptions,
): TraverseOptions => {
let current: JSXLinkedNode = { children: jsx };
return {
JSXElement: {
enter(path) {
const node = path.node;
const name = node.openingElement.name as { name: string };
enter({ node }) {
const nameNode = node.openingElement.name as {
name: string;
object: { name: string };
} & (JSXIdentifier | JSXMemberExpression | JSXNamespacedName);
const attributes = collectAttributes(node.openingElement);
const name =
nameNode.type === 'JSXMemberExpression'
? `${nameNode.object.name}.${nameNode.property.name}`
: nameNode.name;

const jsxNode: JSXLinkedNode = {
name: name.name,
name,
parent: current,
children: [],
attributes: Object.keys(attributes),
};
const nameParts = name.split('.');
const imported = imports[nameParts[0]];
if (imported) {
jsxNode.from = imported.from;
if (isLocalImport(imported.from)) {
const fileName = resolve.sync(imported.from, {
...options?.resolver,
basedir: path.dirname(filePath),
});
//its a local import
const followImport = followImports(
imported.importedName,
fileName,
undefined,
options,
);
if (followImport?.filePath) {
jsxNode.componentKey = componentKey(
followImport.filePath,
imported.importedName,
);
}
}
jsxNode.importedName =
nameParts.length > 1 && imported.importedName === 'default'
? nameParts[1]
: imported.importedName;
}
if (current.children) {
current.children.push(jsxNode);
}
Expand All @@ -40,10 +94,10 @@ export const analyze_components = (
options?: InstrumentOptions,
): void => {
const { parser: parserOptions } = options || {};
const source = fs.readFileSync(filePath, 'utf8');
const ast = parser.parse(source, parserOptions);
const { ast } = parseFile(filePath, parserOptions);
const imports = parseImports(filePath);
const jsx: JSXLinkedTree = [];
traverse(ast, traverseJSX(jsx));
traverse(ast, traverseJSX(jsx, imports, filePath, options));
const mapJSXTree = (input?: JSXLinkedTree): JSXTree => {
return input
? // eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
24 changes: 7 additions & 17 deletions core/instrument/src/babel/extract-component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import path from 'path';
import { File } from '@babel/types';
import * as resolve from 'resolve';
import {
Component,
Document,
PackageInfo,
Imports,
ImportTypes,
isLocalImport,
} from '@component-controls/core';
import { componentKey } from '../misc/hashStore';
import { followImports } from './follow-imports';
Expand All @@ -28,19 +28,12 @@ export const extractComponent = async (
filePath: string,
source?: string,
options?: InstrumentOptions,
initialAST?: File,
): Promise<ComponentParseData> => {
const cacheKey = `${filePath}-${componentName}`;
if (globalCache[cacheKey]) {
return globalCache[cacheKey];
}
const follow = followImports(
componentName,
filePath,
source,
options,
initialAST,
);
const follow = followImports(componentName, filePath, source, options);
const { components, resolver: resolveOptions } = options || {};
let component: Component;
let componentPackage: PackageInfo | undefined;
Expand All @@ -56,7 +49,7 @@ export const extractComponent = async (
const allImports = Object.keys(imports).reduce((acc: Imports, key) => {
const { name, from, importedName } = imports[key];
let importKey = undefined;
if (follow.filePath && from.startsWith('.')) {
if (follow.filePath && isLocalImport(from)) {
try {
const fileName = resolve.sync(from, {
...resolveOptions,
Expand All @@ -67,7 +60,6 @@ export const extractComponent = async (
fileName,
undefined,
options,
undefined,
);
if (followImport?.filePath) {
importKey = componentKey(followImport.filePath, importedName);
Expand All @@ -81,7 +73,7 @@ export const extractComponent = async (
[from]: [
...acc[from],
importKey
? { name, importedName, key: importKey }
? { name, importedName, componentKey: importKey }
: { name, importedName },
],
};
Expand All @@ -90,19 +82,19 @@ export const extractComponent = async (
...acc,
[from]: [
importKey
? { name, importedName, key: importKey }
? { name, importedName, componentKey: importKey }
: { name, importedName },
],
};
}, {});
component.externalDependencies = Object.keys(allImports)
.filter(key => !key.startsWith('.'))
.filter(key => !isLocalImport(key))
.reduce(
(acc, key) => ({ ...acc, [key]: (allImports as Imports)[key] }),
{},
);
component.localDependencies = Object.keys(allImports)
.filter(key => key.startsWith('.'))
.filter(key => isLocalImport(key))
.reduce((acc, key) => {
return { ...acc, [key]: (allImports as Imports)[key] };
}, {});
Expand Down Expand Up @@ -156,7 +148,6 @@ export const extractStoreComponent = async (
filePath: string,
source: string,
options?: InstrumentOptions,
initialAST?: File,
): Promise<void> => {
if (store.doc) {
const doc: Document = store.doc;
Expand All @@ -169,7 +160,6 @@ export const extractStoreComponent = async (
filePath,
source,
options,
initialAST,
);
if (component) {
if (componentPackage) {
Expand Down
10 changes: 5 additions & 5 deletions core/instrument/src/babel/extract-exports.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as parser from '@babel/parser';
import { ParserOptions } from '@babel/parser';
import traverse, { TraverseOptions } from '@babel/traverse';
import { CodeLocation } from '@component-controls/core';
import { sourceLocation } from '../misc/source-location';

import { parseFile } from '../misc/ast_store';
export interface ExportType {
name: string;
internalName: string;
Expand Down Expand Up @@ -207,13 +207,13 @@ export const traverseExports = (results: ExportTypes): TraverseOptions => {
};

export const extractExports = (
source: string,
parserOptions?: parser.ParserOptions,
fileName: string,
parserOptions?: ParserOptions,
): ExportTypes => {
const results: ExportTypes = {
named: {},
};
const ast = parser.parse(source, parserOptions);
const { ast } = parseFile(fileName, parserOptions);

traverse(ast as any, traverseExports(results));
return results;
Expand Down
1 change: 0 additions & 1 deletion core/instrument/src/babel/extract-function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export const extractFunction = (
filePath,
source,
_options,
ast,
);
}
case 'ObjectExpression': {
Expand Down
9 changes: 5 additions & 4 deletions core/instrument/src/babel/extract-imports.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as parser from '@babel/parser';
import { ParserOptions } from '@babel/parser';
import { ImportTypes } from '@component-controls/core';
import traverse, { TraverseOptions } from '@babel/traverse';
import { parseFile } from '../misc/ast_store';

export const traverseImports = (results: ImportTypes): TraverseOptions => {
return {
Expand Down Expand Up @@ -32,11 +33,11 @@ export const traverseImports = (results: ImportTypes): TraverseOptions => {
};

export const extractImports = (
source: string,
parserOptions?: parser.ParserOptions,
fileName: string,
parserOptions?: ParserOptions,
): ImportTypes => {
const results: ImportTypes = {};
const ast = parser.parse(source, parserOptions);
const { ast } = parseFile(fileName, parserOptions);

traverse(ast as any, traverseImports(results));
return results;
Expand Down
Loading

0 comments on commit c530e29

Please sign in to comment.