Skip to content

Commit

Permalink
Without pragma (#59)
Browse files Browse the repository at this point in the history
* add Dependabot

* remove pragma dependency

* add Global to import list

* build pkg post install script

* Create wild-carpets-repeat.md

* update dependency list
  • Loading branch information
kuldeepkeshwar committed Aug 6, 2020
1 parent 933d2e0 commit 4affc53
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 34 deletions.
7 changes: 7 additions & 0 deletions .changeset/wild-carpets-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"babel-plugin-filbert": patch
"@filbert-js/macro": patch
"@filbert-js/website": patch
---

remove pragma annotation dependency
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
],
"scripts": {
"develop": "lerna run --stream --parallel --ignore @filbert-js/examples-* --ignore benchmarks-* develop",
"postinstall": "lerna bootstrap",
"postinstall": "lerna bootstrap && yarn build-packages",
"build": "lerna run build",
"build-packages": "lerna run --ignore @filbert-js/website --ignore benchmarks-* --ignore @filbert-js/examples-* build",
"develop-packages": "lerna run --parallel --stream --ignore @filbert-js/website --ignore benchmarks-* --ignore @filbert-js/examples-* develop",
Expand Down
85 changes: 79 additions & 6 deletions packages/babel-plugin-filbert/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const babelPluginReactJSX = require('@babel/plugin-transform-react-jsx')
.default;
/**
* Prepend #__PURE__ comment to help minifiers with
* dead code elminiation (=DCE)
Expand All @@ -10,31 +12,102 @@ function prependPureComment(node) {
value: '#__PURE__',
});
}
const tags = ['css', 'keyframes'];
module.exports = function({ types: t }, options = {}) {
const name = options.name || 'styled';
const findLast = (arr, predicate) => {
for (let i = arr.length - 1; i >= 0; i--) {
if (predicate(arr[i])) {
return arr[i];
}
}
};

function addPragmaImport(path, t, pragmaOptions) {
const importDeclaration = t.importDeclaration(
[
t.importSpecifier(
t.identifier(pragmaOptions.import),
t.identifier(pragmaOptions.export),
),
],
t.stringLiteral(pragmaOptions.module),
);
const targetPath = findLast(path.get('body'), (p) => p.isImportDeclaration());

if (targetPath) {
targetPath.insertAfter([importDeclaration]);
} else {
// Apparently it's now safe to do this even if Program begins with directives.
path.unshiftContainer('body', importDeclaration);
}
}
const imports = {
Global: 'Global',
styled: 'styled',
css: 'css',
keyframes: 'keyframes',
};
const pragmaOptions = {
import: 'jsx',
export: 'jsx',
module: '@filbert-js/core',
};
function extractPragmaOptions(state) {
const [reactjsxPlugin] = state.file.opts.plugins.filter(
(p) => p.key === 'transform-react-jsx',
);
if (reactjsxPlugin && reactjsxPlugin.options) {
return { ...reactjsxPlugin.options, pragma: pragmaOptions.import };
} else {
return { pragma: pragmaOptions.import, pragmaFrag: 'React.Fragment' };
}
}
module.exports = function(babel, options = {}) {
const { types: t } = babel;
const _imports = { ...imports, ...options.imports };
// Enable pure by default if it is not set by the user
const pure = !('pure' in options) ? true : options.pure;
const importSpecifiers = Object.values(_imports);
return {
name: 'transform-filbert',
visitor: {
Program: {
exit: function(path, state) {
if (state.pragmaDetected) {
addPragmaImport(path, t, pragmaOptions);
babel.traverse(
path.parent,
babelPluginReactJSX(babel, extractPragmaOptions(state)).visitor,
undefined,
state,
);
}
},
},
JSXAttribute: function(path, state) {
if (path.node.name.name === 'css') {
state.pragmaDetected = true;
}
},
TaggedTemplateExpression(path, state) {
if (
t.isIdentifier(path.node.tag) &&
tags.includes(path.node.tag.name)
importSpecifiers.includes(path.node.tag.name)
) {
pure && prependPureComment(path.node);
} else if (
t.isIdentifier(path.node.tag.callee) &&
path.node.tag.callee.name === name
importSpecifiers.includes(path.node.tag.callee.name)
) {
pure && prependPureComment(path.node);
}
},
MemberExpression: {
exit(path) {
const node = path.node;
if (!t.isIdentifier(node.object) || node.object.name !== name) {

if (
!t.isIdentifier(node.object) ||
!importSpecifiers.includes(node.object.name)
) {
return;
}
pure && prependPureComment(path.node);
Expand Down
1 change: 1 addition & 0 deletions packages/babel-plugin-filbert/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
],
"license": "MIT",
"peerDependencies": {
"@babel/plugin-transform-react-jsx":"^7.10.4",
"@babel/core": "^7.0.0-0"
}
}
39 changes: 13 additions & 26 deletions packages/macro/index.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,29 @@
const { createMacro } = require('babel-plugin-macros');
const { addNamed } = require('@babel/helper-module-imports');

const babelPlugin = require('babel-plugin-filbert');

const source = '@filbert-js/core';
const name = 'styled';

function filbertMacro({ references, babel, state }) {
const program = state.file.path;

const imports = {};

Object.keys(references).forEach((refName) => {
const id = addNamed(program, refName, source);
const id = addNamed(program, refName, source, { nameHint: refName });

imports[refName] = id.name;
references[refName].forEach((referencePath) => {
referencePath.node.name = id.name;
});
});

const t = babel.types;

const namedReferences = references[name] || [];

namedReferences.forEach((referencePath) => {
const path = referencePath.parentPath;
const type = path.type;
const node = path.node;
if (type === 'MemberExpression') {
const functionName = node.object.name;
let elementName = node.property.name;

// Support custom elements
if (/[A-Z]/.test(elementName)) {
elementName = elementName.replace(/[A-Z]/g, '-$&').toLowerCase();
}

path.replaceWith(
t.callExpression(t.identifier(functionName), [
t.stringLiteral(elementName),
]),
);
}
});
babel.traverse(
program.parent,
babelPlugin(babel, { imports }).visitor,
undefined,
state,
);
}
module.exports = createMacro(filbertMacro);
1 change: 1 addition & 0 deletions packages/macro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
],
"license": "MIT",
"dependencies": {
"babel-plugin-filbert": "0.0.6",
"@babel/helper-module-imports": "7.10.4",
"babel-plugin-macros": "2.8.0"
}
Expand Down
36 changes: 36 additions & 0 deletions website/docs/CSS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,39 @@ const styles = css`

render(<button css={styles}>This is a Button component.</button>);
```

Or you can use `@filbert-js/macro`

```jsx
// @editor
import React from 'react';
import { css } from '@filbert-js/macro';

const styles = css`
background: pink;
border: solid 1px grey;
`;

render(<button css={styles}>This is a Button component.</button>);
```

Or you can use `@filbert-js/core` along with `babel-plugin-filbert`

```jsx
// @editor
import React from 'react';
import { css } from '@filbert-js/core';

const styles = css`
background: pink;
border: solid 1px grey;
`;

render(<button css={styles}>This is a Button component.</button>);
```

> Pragma annotation (`/*@jsx jsx*/`) is not required when using `babel-plugin-filbert` or `@filbert-js/macro`
Check out example

[![Edit kuldeepkeshwar/filbert-js-examples-with-cra](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/kuldeepkeshwar/filbert-js-examples-with-cra/tree/master/?fontsize=14&hidenavigation=1&theme=dark)
1 change: 0 additions & 1 deletion website/plugins/gatsby-remark-live-code/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const visit = require('unist-util-visit');
const escapeGoat = require('escape-goat');
const Babel = require('babel-standalone');

const livePattern = /^\s*\/\/ @live/;
const editorPattern = /^\s*\/\/ @editor/;

Expand Down

1 comment on commit 4affc53

@vercel
Copy link

@vercel vercel bot commented on 4affc53 Aug 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.