Repository: callstack/linaria Branch: master Commit: 8bb4e92c481b Files: 282 Total size: 720.8 KB Directory structure: gitextract_xouc4tvv/ ├── .all-contributorsrc ├── .changeset/ │ ├── README.md │ └── config.json ├── .codecov.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .git-blame-ignore-revs ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── config.yml │ │ ├── enhancement_request.md │ │ └── feature_request.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── labels.json │ └── workflows/ │ ├── check.yml │ ├── main.yml │ ├── release.yml │ └── site-deploy.yml ├── .gitignore ├── .npmrc ├── .prettierrc ├── .syncpackrc.js ├── .vscode/ │ └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── commitlint.config.js ├── docs/ │ ├── API.md │ ├── ATOMIC_CSS.md │ ├── BASICS.md │ ├── BENEFITS.md │ ├── BUNDLERS_INTEGRATION.md │ ├── CLI.md │ ├── CONFIGURATION.md │ ├── CRITICAL_CSS.md │ ├── DYNAMIC_STYLES.md │ ├── FEATURE_FLAGS.md │ ├── HOW_IT_WORKS.md │ ├── LINTING.md │ ├── MIGRATION_GUIDE.md │ └── THEMING.md ├── examples/ │ ├── astro-solid/ │ │ ├── astro.config.js │ │ ├── package.json │ │ ├── pages/ │ │ │ ├── csr.tsx │ │ │ ├── csr_child.tsx │ │ │ ├── external.ts │ │ │ └── index.astro │ │ └── tsconfig.json │ ├── esbuild/ │ │ ├── .gitignore │ │ ├── app.js │ │ ├── build.js │ │ └── package.json │ ├── rollup/ │ │ ├── .gitignore │ │ ├── app.js │ │ ├── babel.config.js │ │ ├── package.json │ │ └── rollup.config.mjs │ ├── vite/ │ │ ├── .linariarc.mjs │ │ ├── app.js │ │ ├── index.html │ │ ├── package.json │ │ └── vite.config.js │ ├── vpssr-linaria-solid/ │ │ ├── package.json │ │ ├── pages/ │ │ │ ├── html-js/ │ │ │ │ ├── _default.page.client.js │ │ │ │ └── index.page.server.tsx │ │ │ ├── html-only/ │ │ │ │ └── index.page.server.tsx │ │ │ ├── index.page.server.tsx │ │ │ ├── spa/ │ │ │ │ └── index.page.client.tsx │ │ │ └── ssr/ │ │ │ ├── Counter.tsx │ │ │ └── index.page.tsx │ │ ├── renderer/ │ │ │ ├── _default.page.client.tsx │ │ │ └── _default.page.server.tsx │ │ ├── server.js │ │ ├── tsconfig.json │ │ └── vite.config.js │ └── webpack5/ │ ├── app.js │ ├── babel.config.js │ ├── package.json │ └── webpack.config.js ├── greenkeeper.json ├── jest.config.js ├── link-wyw.sh ├── package.json ├── packages/ │ ├── atomic/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── processors/ │ │ │ ├── css.js │ │ │ └── styled.js │ │ ├── src/ │ │ │ ├── CSSProperties.ts │ │ │ ├── css.ts │ │ │ ├── index.ts │ │ │ └── processors/ │ │ │ ├── css.ts │ │ │ ├── helpers/ │ │ │ │ ├── atomize.ts │ │ │ │ └── propertyPriority.ts │ │ │ └── styled.ts │ │ └── tsconfig.json │ ├── core/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── __dtslint__/ │ │ │ ├── core.ts │ │ │ ├── index.d.ts │ │ │ ├── tsconfig.eslint.json │ │ │ └── tsconfig.json │ │ ├── __tests__/ │ │ │ ├── cx.test.ts │ │ │ └── detect-core-js.test.ts │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── processors/ │ │ │ └── css.js │ │ ├── src/ │ │ │ ├── CSSProperties.ts │ │ │ ├── css.ts │ │ │ ├── cx.ts │ │ │ ├── index.ts │ │ │ └── processors/ │ │ │ └── css.ts │ │ └── tsconfig.json │ ├── interop/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ ├── __snapshots__/ │ │ │ │ └── index.test.ts.snap │ │ │ └── index.test.ts │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── linaria/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── babel/ │ │ │ └── package.json │ │ ├── babel.config.js │ │ ├── evaluators/ │ │ │ └── package.json │ │ ├── loader/ │ │ │ └── package.json │ │ ├── package.json │ │ ├── react/ │ │ │ └── package.json │ │ ├── rollup/ │ │ │ └── package.json │ │ ├── server/ │ │ │ └── package.json │ │ ├── src/ │ │ │ ├── core.ts │ │ │ ├── react.ts │ │ │ └── server.ts │ │ ├── stylelint-config/ │ │ │ └── package.json │ │ └── tsconfig.json │ ├── postcss-linaria/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ ├── __utils__/ │ │ │ │ └── index.ts │ │ │ ├── locationCorrection.test.ts │ │ │ ├── parse.test.ts │ │ │ ├── stringify.test.ts │ │ │ ├── stylelint.test.ts │ │ │ └── utils.test.ts │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ ├── locationCorrection.ts │ │ │ ├── parse.ts │ │ │ ├── stringify.ts │ │ │ └── util.ts │ │ └── tsconfig.json │ ├── react/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── __dtslint-react17__/ │ │ │ ├── index.d.ts │ │ │ ├── react17.tsx │ │ │ ├── stubs/ │ │ │ │ ├── jsx-runtime.d.ts │ │ │ │ └── react17.d.ts │ │ │ ├── tsconfig.eslint.json │ │ │ └── tsconfig.json │ │ ├── __dtslint__/ │ │ │ ├── index.d.ts │ │ │ ├── styled.ts │ │ │ ├── tsconfig.eslint.json │ │ │ └── tsconfig.json │ │ ├── __tests__/ │ │ │ ├── __snapshots__/ │ │ │ │ └── styled.test.tsx.snap │ │ │ ├── detect-core-js.test.ts │ │ │ └── styled.test.tsx │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── processors/ │ │ │ └── styled.js │ │ ├── src/ │ │ │ ├── index.ts │ │ │ ├── processors/ │ │ │ │ └── styled.ts │ │ │ ├── react-html-attributes.d.ts │ │ │ └── styled.ts │ │ └── tsconfig.json │ ├── server/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── __tests__/ │ │ │ ├── __snapshots__/ │ │ │ │ └── collect.test.ts.snap │ │ │ └── collect.test.ts │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── collect.ts │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── stylelint/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ └── preprocessor.ts │ │ └── tsconfig.json │ ├── stylelint-config-standard-linaria/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.js │ │ └── tsconfig.json │ └── testkit/ │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src/ │ │ ├── __fixtures__/ │ │ │ ├── assignToExport.js │ │ │ ├── bar.js │ │ │ ├── circular-imports/ │ │ │ │ ├── bar.js │ │ │ │ ├── constants.js │ │ │ │ ├── foo.js │ │ │ │ └── index.js │ │ │ ├── complex-component.js │ │ │ ├── components-library.js │ │ │ ├── computedKeys.js │ │ │ ├── enums.ts │ │ │ ├── escape-character.js │ │ │ ├── foo-nonstatic.js │ │ │ ├── foo.js │ │ │ ├── linaria-ui-library/ │ │ │ │ ├── components/ │ │ │ │ │ └── index.js │ │ │ │ ├── hocs.js │ │ │ │ ├── non-linaria-components.js │ │ │ │ ├── package.json │ │ │ │ └── types.ts │ │ │ ├── loop/ │ │ │ │ ├── a.js │ │ │ │ ├── ab.js │ │ │ │ ├── b.js │ │ │ │ ├── ba.js │ │ │ │ └── index.js │ │ │ ├── module-reexport.js │ │ │ ├── non-linaria-ui-library/ │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ ├── objectExport.js │ │ │ ├── re-exports/ │ │ │ │ ├── constants.js │ │ │ │ ├── empty.js │ │ │ │ ├── foo.js │ │ │ │ └── index.js │ │ │ ├── reexports.js │ │ │ ├── runNearFramePaint.js │ │ │ ├── sample-data.json │ │ │ ├── sample-script.cjs │ │ │ ├── sample-script.js │ │ │ ├── sample-typescript.tsx │ │ │ ├── self-import.js │ │ │ ├── sequenceExport.js │ │ │ ├── slugify.js │ │ │ ├── ts-compiled-re-exports/ │ │ │ │ ├── constants.js │ │ │ │ └── index.js │ │ │ ├── ts-data.ts │ │ │ └── with-babelrc/ │ │ │ ├── .babelrc.js │ │ │ └── index.js │ │ ├── __snapshots__/ │ │ │ ├── babel.test.ts.snap │ │ │ └── transform.test.ts.snap │ │ ├── __utils__/ │ │ │ └── linaria-snapshot-serializer.ts │ │ ├── babel.test.ts │ │ └── transform.test.ts │ └── tsconfig.json ├── pnpm-workspace.yaml ├── react/ │ └── package.json ├── tsconfig.eslint.json ├── tsconfig.json ├── tsconfig.prod.json ├── tslint.json ├── turbo.json └── website/ ├── .eslintrc ├── CHANGELOG.md ├── babel.config.js ├── index.html ├── linaria.config.js ├── package.json ├── serve.config.js ├── src/ │ ├── .eslintrc │ ├── api/ │ │ ├── index.js │ │ └── react/ │ │ └── index.js │ ├── components/ │ │ ├── App.jsx │ │ ├── Container.js │ │ ├── Example.js │ │ ├── Header.jsx │ │ └── Hero.jsx │ ├── index.jsx │ ├── server.jsx │ └── styles/ │ ├── constants.js │ └── utils.js ├── stylelint.config.js └── webpack.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .all-contributorsrc ================================================ { "projectName": "linaria", "projectOwner": "callstack", "files": [ "README.md" ], "imageSize": 100, "commit": false, "contributors": [ { "login": "zamotany", "name": "Paweł Trysła", "avatar_url": "https://avatars2.githubusercontent.com/u/17573635?v=4", "profile": "https://twitter.com/_zamotany", "contributions": [ "code", "doc", "ideas" ] }, { "login": "satya164", "name": "Satyajit Sahoo", "avatar_url": "https://avatars2.githubusercontent.com/u/1174278?v=4", "profile": "https://medium.com/@satya164", "contributions": [ "code", "doc", "ideas" ] }, { "login": "thymikee", "name": "Michał Pierzchała", "avatar_url": "https://avatars2.githubusercontent.com/u/5106466?v=4", "profile": "https://github.com/thymikee", "contributions": [ "code", "doc", "ideas" ] }, { "login": "AgtLucas", "name": "Lucas", "avatar_url": "https://avatars1.githubusercontent.com/u/1909761?v=4", "profile": "https://lcs.sh", "contributions": [ "doc" ] }, { "login": "pronevich", "name": "Alexey Pronevich", "avatar_url": "https://avatars0.githubusercontent.com/u/680439?v=4", "profile": "https://github.com/pronevich", "contributions": [ "doc" ] }, { "login": "wojteg1337", "name": "Wojtek Szafraniec", "avatar_url": "https://avatars3.githubusercontent.com/u/18573330?v=4", "profile": "https://github.com/wojteg1337", "contributions": [ "code" ] }, { "login": "Anber", "name": "Anton Evzhakov", "avatar_url": "https://avatars3.githubusercontent.com/u/148258?v=4", "profile": "http://twitter.com/anber_dev", "contributions": [ "code", "ideas", "doc" ] }, { "login": "Tushkiz", "name": "Tushar Sonawane", "avatar_url": "https://avatars1.githubusercontent.com/u/1854763?v=4", "profile": "https://twitter.com/tushkiz", "contributions": [ "doc", "example" ] }, { "login": "ferrannp", "name": "Ferran Negre", "avatar_url": "https://avatars2.githubusercontent.com/u/774577?v=4", "profile": "http://twitter.com/ferrannp", "contributions": [ "doc" ] }, { "login": "jukben", "name": "Jakub Beneš", "avatar_url": "https://avatars3.githubusercontent.com/u/8135252?v=4", "profile": "https://jukben.cz", "contributions": [ "code", "doc" ] }, { "login": "oBusk", "name": "Oscar Busk", "avatar_url": "https://avatars2.githubusercontent.com/u/13413409?v=4", "profile": "https://github.com/oBusk", "contributions": [ "bug", "code" ] }, { "login": "Trancever", "name": "Dawid", "avatar_url": "https://avatars3.githubusercontent.com/u/18584155?v=4", "profile": "https://github.com/Trancever", "contributions": [ "code", "doc" ] }, { "login": "Esemesek", "name": "Kacper Wiszczuk", "avatar_url": "https://avatars2.githubusercontent.com/u/9092510?v=4", "profile": "https://twitter.com/esemesek", "contributions": [ "code", "doc" ] }, { "login": "que-etc", "name": "Denis Rul", "avatar_url": "https://avatars3.githubusercontent.com/u/2401842?v=4", "profile": "https://github.com/que-etc", "contributions": [ "code" ] }, { "login": "johanholmerin", "name": "Johan Holmerin", "avatar_url": "https://avatars0.githubusercontent.com/u/7433263?v=4", "profile": "https://github.com/johanholmerin", "contributions": [ "code", "doc" ] }, { "login": "pgilad", "name": "Gilad Peleg", "avatar_url": "https://avatars0.githubusercontent.com/u/4533329?v=4", "profile": "https://www.giladpeleg.com/", "contributions": [ "doc" ] }, { "login": "giuseppeg", "name": "Giuseppe", "avatar_url": "https://avatars3.githubusercontent.com/u/711311?v=4", "profile": "http://giuseppe.pizza", "contributions": [ "code" ] }, { "login": "silvenon", "name": "Matija Marohnić", "avatar_url": "https://avatars2.githubusercontent.com/u/471278?v=4", "profile": "https://silvenon.com", "contributions": [ "code", "doc" ] }, { "login": "Schubidu", "name": "Stefan Schult", "avatar_url": "https://avatars2.githubusercontent.com/u/120432?v=4", "profile": "http://schultstefan.de", "contributions": [ "code" ] }, { "login": "wardpeet", "name": "Ward Peeters", "avatar_url": "https://avatars3.githubusercontent.com/u/1120926?v=4", "profile": "http://www.coding-tech.be", "contributions": [ "code" ] }, { "login": "radoslaw-medryk", "name": "radoslaw-medryk", "avatar_url": "https://avatars0.githubusercontent.com/u/43260833?v=4", "profile": "https://github.com/radoslaw-medryk", "contributions": [ "code" ] }, { "login": "dr2009", "name": "杨兴洲", "avatar_url": "https://avatars1.githubusercontent.com/u/8262650?v=4", "profile": "http://dr2009.com", "contributions": [ "code" ] }, { "login": "hinok", "name": "Dawid Karabin", "avatar_url": "https://avatars2.githubusercontent.com/u/1313605?v=4", "profile": "https://github.com/hinok", "contributions": [ "doc" ] }, { "login": "chrisabrams", "name": "Chris Abrams", "avatar_url": "https://avatars1.githubusercontent.com/u/527740?s=460&v=4", "profile": "https://github.com/chrisabrams", "contributions": [ "code", "doc", "ideas" ] }, { "login": "Jayphen", "name": "Jayphen", "avatar_url": "https://avatars0.githubusercontent.com/u/329184?v=4", "profile": "http://hyperlab.se", "contributions": [ "code" ] }, { "login": "bolasblack", "name": "c4605", "avatar_url": "https://avatars0.githubusercontent.com/u/382011?v=4", "profile": "https://github.com/bolasblack", "contributions": [ "code" ] }, { "login": "koba04", "name": "Toru Kobayashi", "avatar_url": "https://avatars2.githubusercontent.com/u/250407?v=4", "profile": "https://koba04.com/", "contributions": [ "code" ] }, { "login": "jayu", "name": "Jakub Mazurek", "avatar_url": "https://avatars.githubusercontent.com/u/11561585?v=4", "profile": "https://github.com/jayu", "contributions": [ "code" ] }, { "login": "jpnelson", "name": "Joshua Nelson", "avatar_url": "https://avatars.githubusercontent.com/u/1518604?v=4", "profile": "http://subsecond.dev/", "contributions": [ "code", "ideas", "doc" ] }, { "login": "TMaszko", "name": "Tomasz Krzyżowski", "avatar_url": "https://avatars.githubusercontent.com/u/16257732?v=4", "profile": "https://twitter.com/TMaszko", "contributions": [ "code" ] }, { "login": "dfrkp", "name": "Martin Schulze", "avatar_url": "https://avatars.githubusercontent.com/u/1476435?v=4", "profile": "https://www.slash-m.com/", "contributions": [ "code" ] }, { "login": "wmzy", "name": "wmzy", "avatar_url": "https://avatars.githubusercontent.com/u/5526525?v=4", "profile": "https://github.com/wmzy", "contributions": [ "code" ] }, { "login": "cometkim", "name": "Hyeseong Kim", "avatar_url": "https://avatars.githubusercontent.com/u/9696352?v=4", "profile": "https://blog.cometkim.kr/", "contributions": [ "code" ] }, { "login": "Hotell", "name": "Martin Hochel", "avatar_url": "https://avatars.githubusercontent.com/u/1223799?v=4", "profile": "https://github.com/Hotell", "contributions": [ "code" ] }, { "login": "Daniel15", "name": "Daniel Lo Nigro", "avatar_url": "https://avatars.githubusercontent.com/u/91933?v=4", "profile": "https://d.sb/", "contributions": [ "code" ] }, { "login": "0xflotus", "name": "0xflotus", "avatar_url": "https://avatars.githubusercontent.com/u/26602940?v=4", "profile": "https://github.com/0xflotus", "contributions": [ "code" ] }, { "login": "afzalsayed96", "name": "Afzal Sayed", "avatar_url": "https://avatars.githubusercontent.com/u/14029371?v=4", "profile": "https://github.com/afzalsayed96", "contributions": [ "code" ] }, { "login": "aiji42", "name": "AijiUejima", "avatar_url": "https://avatars.githubusercontent.com/u/6711766?v=4", "profile": "https://github.com/aiji42", "contributions": [ "code" ] }, { "login": "le0pard", "name": "Oleksii Vasyliev", "avatar_url": "https://avatars.githubusercontent.com/u/98444?v=4", "profile": "https://leopard.in.ua/", "contributions": [ "code" ] }, { "login": "alicanerdogan", "name": "Alican Erdoğan", "avatar_url": "https://avatars.githubusercontent.com/u/1814803?v=4", "profile": "https://github.com/alicanerdogan", "contributions": [ "code" ] }, { "login": "amankkg", "name": "Aman Kubanychbek", "avatar_url": "https://avatars.githubusercontent.com/u/3933028?v=4", "profile": "https://amank.me/", "contributions": [ "code" ] }, { "login": "kinetifex", "name": "Andrew Gerard", "avatar_url": "https://avatars.githubusercontent.com/u/82775?v=4", "profile": "http://kinetifex.com/", "contributions": [ "code" ] }, { "login": "frolovdev", "name": "Andrey Frolov", "avatar_url": "https://avatars.githubusercontent.com/u/30667180?v=4", "profile": "https://www.linkedin.com/in/andrey-frolov-3b8579155/", "contributions": [ "code" ] }, { "login": "soluml", "name": "Benjamin Solum", "avatar_url": "https://avatars.githubusercontent.com/u/589571?v=4", "profile": "https://github.com/soluml", "contributions": [ "code" ] }, { "login": "billykwok", "name": "Billy Kwok", "avatar_url": "https://avatars.githubusercontent.com/u/8078716?v=4", "profile": "https://billykwok.me/", "contributions": [ "code" ] }, { "login": "chrstntdd", "name": "Christian Todd", "avatar_url": "https://avatars.githubusercontent.com/u/17863654?v=4", "profile": "https://github.com/chrstntdd", "contributions": [ "code" ] }, { "login": "dpeek", "name": "David Peek", "avatar_url": "https://avatars.githubusercontent.com/u/128329?v=4", "profile": "https://estii.com/", "contributions": [ "code" ] }, { "login": "dskiba", "name": "Denis Skiba", "avatar_url": "https://avatars.githubusercontent.com/u/28356785?v=4", "profile": "https://github.com/dskiba", "contributions": [ "code" ] }, { "login": "geakstr", "name": "Dima Kharitonov", "avatar_url": "https://avatars.githubusercontent.com/u/1496368?v=4", "profile": "https://github.com/geakstr", "contributions": [ "code" ] }, { "login": "GabbeV", "name": "Gabriel Valfridsson", "avatar_url": "https://avatars.githubusercontent.com/u/13839236?v=4", "profile": "https://github.com/GabbeV", "contributions": [ "code" ] }, { "login": "GitaiQAQ", "name": "Gitai", "avatar_url": "https://avatars.githubusercontent.com/u/5354788?v=4", "profile": "http://t.cn/EvDFUFF", "contributions": [ "code" ] }, { "login": "hampuskraft", "name": "Hampus Kraft", "avatar_url": "https://avatars.githubusercontent.com/u/24176136?v=4", "profile": "https://hampuskraft.com/", "contributions": [ "code" ] }, { "login": "isumix", "name": "Igor Sukharev", "avatar_url": "https://avatars.githubusercontent.com/u/16747416?v=4", "profile": "https://github.com/isumix", "contributions": [ "code" ] }, { "login": "eltociear", "name": "Ikko Ashimine", "avatar_url": "https://avatars.githubusercontent.com/u/22633385?v=4", "profile": "https://bandism.net/", "contributions": [ "code" ] }, { "login": "ImanMh", "name": "Iman Mohamadi", "avatar_url": "https://avatars.githubusercontent.com/u/4482199?v=4", "profile": "http://jsdecorator.com/", "contributions": [ "code" ] }, { "login": "codecorsair", "name": "JB ", "avatar_url": "https://avatars.githubusercontent.com/u/9878445?v=4", "profile": "https://github.com/codecorsair", "contributions": [ "code" ] }, { "login": "Jack-Works", "name": "Jack Works", "avatar_url": "https://avatars.githubusercontent.com/u/5390719?v=4", "profile": "https://jack-works.github.io/", "contributions": [ "code" ] }, { "login": "jamesgeorge007", "name": "James George", "avatar_url": "https://avatars.githubusercontent.com/u/25279263?v=4", "profile": "https://ghuser.io/jamesgeorge007", "contributions": [ "code" ] }, { "login": "jedmao", "name": "Jed Mao", "avatar_url": "https://avatars.githubusercontent.com/u/1058243?v=4", "profile": "https://appleid.apple.com/", "contributions": [ "code" ] }, { "login": "lencioni", "name": "Joe Lencioni", "avatar_url": "https://avatars.githubusercontent.com/u/195534?v=4", "profile": "https://github.com/lencioni", "contributions": [ "code" ] }, { "login": "joeycozza", "name": "Joey Cozza", "avatar_url": "https://avatars.githubusercontent.com/u/3885959?v=4", "profile": "https://github.com/joeycozza", "contributions": [ "code" ] }, { "login": "juanferreras", "name": "Juan Ferreras", "avatar_url": "https://avatars.githubusercontent.com/u/8507996?v=4", "profile": "https://github.com/juanferreras", "contributions": [ "code" ] }, { "login": "kazuma1989", "name": "Kazuma Ebina", "avatar_url": "https://avatars.githubusercontent.com/u/15844862?v=4", "profile": "https://www.linkedin.com/in/kazuma1989/", "contributions": [ "code" ] }, { "login": "webpro", "name": "Lars Kappert", "avatar_url": "https://avatars.githubusercontent.com/u/456426?v=4", "profile": "https://webpro.nl/", "contributions": [ "code" ] }, { "login": "lmammino", "name": "Luciano Mammino", "avatar_url": "https://avatars.githubusercontent.com/u/205629?v=4", "profile": "https://loige.co/", "contributions": [ "code" ] }, { "login": "madhavarshney", "name": "Madhav Varshney", "avatar_url": "https://avatars.githubusercontent.com/u/40002855?v=4", "profile": "https://github.com/madhavarshney", "contributions": [ "code" ] }, { "login": "malash", "name": "Malash", "avatar_url": "https://avatars.githubusercontent.com/u/1812118?v=4", "profile": "https://malash.me/", "contributions": [ "code" ] }, { "login": "Swaagie", "name": "Martijn Swaagman", "avatar_url": "https://avatars.githubusercontent.com/u/670951?v=4", "profile": "https://github.com/Swaagie", "contributions": [ "code" ] }, { "login": "moitias", "name": "Matias Lahti", "avatar_url": "https://avatars.githubusercontent.com/u/1009280?v=4", "profile": "https://github.com/moitias", "contributions": [ "code" ] }, { "login": "majames", "name": "Michael James", "avatar_url": "https://avatars.githubusercontent.com/u/7553458?v=4", "profile": "https://github.com/majames", "contributions": [ "code" ] }, { "login": "kryops", "name": "Michael Strobel", "avatar_url": "https://avatars.githubusercontent.com/u/1042594?v=4", "profile": "https://github.com/kryops", "contributions": [ "code" ] }, { "login": "michalchudziak", "name": "Michał Chudziak", "avatar_url": "https://avatars.githubusercontent.com/u/7837457?v=4", "profile": "https://twitter.com/michalchudziak", "contributions": [ "code" ] }, { "login": "mkanyar", "name": "Mike ", "avatar_url": "https://avatars.githubusercontent.com/u/33469024?v=4", "profile": "https://github.com/mkanyar", "contributions": [ "code" ] }, { "login": "mikestopcontinues", "name": "Mike Stop Continues", "avatar_url": "https://avatars.githubusercontent.com/u/150434?v=4", "profile": "https://www.mikestopcontinues.com/", "contributions": [ "code" ] }, { "login": "Mokshit06", "name": "Mokshit Jain", "avatar_url": "https://avatars.githubusercontent.com/u/50412128?v=4", "profile": "https://github.com/Mokshit06", "contributions": [ "code" ] }, { "login": "layershifter", "name": "Oleksandr Fediashov", "avatar_url": "https://avatars.githubusercontent.com/u/14183168?v=4", "profile": "https://www.linkedin.com/in/layershifter/", "contributions": [ "code" ] }, { "login": "paddyobrien", "name": "Paddy O'Brien", "avatar_url": "https://avatars.githubusercontent.com/u/846372?v=4", "profile": "https://github.com/paddyobrien", "contributions": [ "code" ] }, { "login": "SogoCZE", "name": "Patrik Smělý", "avatar_url": "https://avatars.githubusercontent.com/u/8431593?v=4", "profile": "https://sogocze.cz/", "contributions": [ "code" ] }, { "login": "Nedgeva", "name": "Pavel Udaloff", "avatar_url": "https://avatars.githubusercontent.com/u/19298874?v=4", "profile": "https://github.com/Nedgeva", "contributions": [ "code" ] }, { "login": "pbitkowski", "name": "Przemysław Bitkowski", "avatar_url": "https://avatars.githubusercontent.com/u/22204594?v=4", "profile": "https://github.com/pbitkowski", "contributions": [ "code" ] }, { "login": "ri7nz", "name": "RiN", "avatar_url": "https://avatars.githubusercontent.com/u/16365952?v=4", "profile": "https://rin.rocks/", "contributions": [ "code" ] }, { "login": "pustomytnyk", "name": "Roman Sokhan", "avatar_url": "https://avatars.githubusercontent.com/u/9644824?v=4", "profile": "https://github.com/pustomytnyk", "contributions": [ "code" ] }, { "login": "SeokminHong", "name": "Seokmin Hong (Ray)", "avatar_url": "https://avatars.githubusercontent.com/u/11614766?v=4", "profile": "https://github.com/SeokminHong", "contributions": [ "code" ] }, { "login": "lebedev", "name": "Serge K Lebedev", "avatar_url": "https://avatars.githubusercontent.com/u/5000549?v=4", "profile": "https://github.com/lebedev", "contributions": [ "code" ] }, { "login": "funsis", "name": "Sergey Korovin", "avatar_url": "https://avatars.githubusercontent.com/u/28862758?v=4", "profile": "https://github.com/funsis", "contributions": [ "code" ] }, { "login": "shreyas44", "name": "Shreyas Sreenivas", "avatar_url": "https://avatars.githubusercontent.com/u/46835608?v=4", "profile": "https://github.com/shreyas44", "contributions": [ "code" ] }, { "login": "skywickenden", "name": "Sky Wickenden", "avatar_url": "https://avatars.githubusercontent.com/u/4930551?v=4", "profile": "https://github.com/skywickenden", "contributions": [ "code" ] }, { "login": "s-panferov", "name": "Stanislav Panferov", "avatar_url": "https://avatars.githubusercontent.com/u/198327?v=4", "profile": "https://www.linkedin.com/in/stanislavpanferov", "contributions": [ "code" ] }, { "login": "jsbalrog", "name": "Ted Jenkins", "avatar_url": "https://avatars.githubusercontent.com/u/2457489?v=4", "profile": "https://github.com/jsbalrog", "contributions": [ "code" ] }, { "login": "trongthanh", "name": "Thanh Tran", "avatar_url": "https://avatars.githubusercontent.com/u/234226?v=4", "profile": "https://int3ractive.com/", "contributions": [ "code" ] }, { "login": "tamorim", "name": "Thor Amorim", "avatar_url": "https://avatars.githubusercontent.com/u/5040487?v=4", "profile": "https://github.com/tamorim", "contributions": [ "code" ] }, { "login": "tobenna", "name": "tobenna", "avatar_url": "https://avatars.githubusercontent.com/u/12450941?v=4", "profile": "https://github.com/tobenna", "contributions": [ "code" ] }, { "login": "wereHamster", "name": "Tomas Carnecky", "avatar_url": "https://avatars.githubusercontent.com/u/34538?v=4", "profile": "https://caurea.org/", "contributions": [ "code" ] }, { "login": "Tsubasa1218", "name": "Tsubasa1218", "avatar_url": "https://avatars.githubusercontent.com/u/20498480?v=4", "profile": "https://github.com/Tsubasa1218", "contributions": [ "code" ] }, { "login": "turadg", "name": "Turadg Aleahmad", "avatar_url": "https://avatars.githubusercontent.com/u/21505?v=4", "profile": "http://turadg.aleahmad.net/", "contributions": [ "code" ] }, { "login": "buzinas", "name": "Vitor Buzinaro", "avatar_url": "https://avatars.githubusercontent.com/u/7298695?v=4", "profile": "https://github.com/buzinas", "contributions": [ "code" ] }, { "login": "Mistereo", "name": "Mistereo", "avatar_url": "https://avatars.githubusercontent.com/u/1505518?v=4", "profile": "https://github.com/Mistereo", "contributions": [ "code" ] }, { "login": "5angel", "name": "Vladislav Kozulya", "avatar_url": "https://avatars.githubusercontent.com/u/351676?v=4", "profile": "https://ru.linkedin.com/in/govnokoder", "contributions": [ "code" ] }, { "login": "yuheiy", "name": "Yuhei Yasuda", "avatar_url": "https://avatars.githubusercontent.com/u/11547305?v=4", "profile": "https://yuheiy.com/", "contributions": [ "code" ] }, { "login": "dkamyshov", "name": "Danil Kamyshov", "avatar_url": "https://avatars.githubusercontent.com/u/26835323?v=4", "profile": "https://github.com/dkamyshov", "contributions": [ "code" ] }, { "login": "dword-design", "name": "Sebastian Landwehr", "avatar_url": "https://avatars.githubusercontent.com/u/13484795?v=4", "profile": "https://sebastianlandwehr.com/", "contributions": [ "code" ] }, { "login": "everdimension", "name": "everdimension", "avatar_url": "https://avatars.githubusercontent.com/u/5347023?v=4", "profile": "https://github.com/everdimension", "contributions": [ "code" ] }, { "login": "ptol", "name": "ptol", "avatar_url": "https://avatars.githubusercontent.com/u/17497724?v=4", "profile": "https://github.com/ptol", "contributions": [ "code" ] }, { "login": "roottool", "name": "roottool", "avatar_url": "https://avatars.githubusercontent.com/u/11808736?v=4", "profile": "https://roottool.vercel.app/", "contributions": [ "code" ] }, { "login": "ryamaguchi0220", "name": "ryamaguchi0220", "avatar_url": "https://avatars.githubusercontent.com/u/14275842?v=4", "profile": "https://github.com/ryamaguchi0220", "contributions": [ "code" ] }, { "login": "simka", "name": "simka", "avatar_url": "https://avatars.githubusercontent.com/u/16965735?v=4", "profile": "https://www.simka.dev/", "contributions": [ "code" ] }, { "login": "SoYoung210", "name": "soso", "avatar_url": "https://avatars.githubusercontent.com/u/18658235?v=4", "profile": "https://so-so.dev/", "contributions": [ "code" ] }, { "login": "ChALkeR", "name": "Nikita Skovoroda", "avatar_url": "https://avatars.githubusercontent.com/u/291301?v=4", "profile": "https://twitter.com/skovorodan", "contributions": [ "code" ] }, { "login": "huang-xiao-jian", "name": "黄小健", "avatar_url": "https://avatars.githubusercontent.com/u/4002210?v=4", "profile": "https://github.com/huang-xiao-jian", "contributions": [ "code" ] }, { "login": "iMoses", "name": "iMoses", "avatar_url": "https://avatars.githubusercontent.com/u/1083065?v=4", "profile": "https://github.com/iMoses", "contributions": [ "code" ] }, { "login": "jneander", "name": "Jeremy Neander", "avatar_url": "https://avatars.githubusercontent.com/u/880186?v=4", "profile": "http://jneander.com", "contributions": [ "code" ] }, { "login": "andparsons", "name": "Andy Parsons", "avatar_url": "https://avatars.githubusercontent.com/u/1213447?v=4", "profile": "https://evensix.com", "contributions": [ "code" ] }, { "login": "Platane", "name": "Platane", "avatar_url": "https://avatars.githubusercontent.com/u/1659820?v=4", "profile": "http://platane.github.io", "contributions": [ "doc" ] }, { "login": "kutnickclose", "name": "Tim Kutnick", "avatar_url": "https://avatars.githubusercontent.com/u/6117662?v=4", "profile": "https://github.com/kutnickclose", "contributions": [ "doc" ] }, { "login": "aspirisen", "name": "Dmitrii Pikulin", "avatar_url": "https://avatars.githubusercontent.com/u/3620639?v=4", "profile": "https://github.com/aspirisen", "contributions": [ "code" ] } ], "repoType": "github", "contributorsPerLine": 7, "commitConvention": "none" } ================================================ FILE: .changeset/README.md ================================================ # Changesets Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets) We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config@2.0.0/schema.json", "changelog": "@changesets/cli/changelog", "commit": false, "fixed": [], "linked": [], "access": "restricted", "baseBranch": "master", "updateInternalDependencies": "patch", "ignore": [] } ================================================ FILE: .codecov.yml ================================================ coverage: precision: 2 round: down range: 70...100 status: project: true patch: true changes: false comment: false ================================================ FILE: .editorconfig ================================================ # EditorConfig helps developers define and maintain consistent # coding styles between different editors and IDEs # editorconfig.org root = true [*] # change these settings to your own preference indent_style = space indent_size = 2 # we recommend you to keep these unchanged end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.md] trim_trailing_whitespace = false ================================================ FILE: .eslintignore ================================================ __fixtures__/ coverage/ lib/ esm/ packages/*/bin/ packages/*/types/ dist/ build/ node_modules/ vendor/ examples/ ================================================ FILE: .eslintrc.js ================================================ const noRestrictedSyntax = // eslint-disable-next-line import/no-extraneous-dependencies require('eslint-config-airbnb-base/rules/style').rules[ 'no-restricted-syntax' ].filter( (rule) => typeof rule === 'string' || rule.selector !== 'ForOfStatement' ); // Workaround for https://github.com/import-js/eslint-plugin-import/issues/1810 const noUnresolved = ['error', { ignore: ['@linaria/*'] }]; const memberOrder = [ 'warn', { default: { memberTypes: [ // Index signature 'signature', 'call-signature', // Fields 'public-static-field', 'protected-static-field', 'private-static-field', '#private-static-field', 'public-decorated-field', 'protected-decorated-field', 'private-decorated-field', 'public-instance-field', 'protected-instance-field', 'private-instance-field', '#private-instance-field', 'public-abstract-field', 'protected-abstract-field', 'public-field', 'protected-field', 'private-field', '#private-field', 'static-field', 'instance-field', 'abstract-field', 'decorated-field', 'field', // Static initialization 'static-initialization', // Constructors 'public-constructor', 'protected-constructor', 'private-constructor', 'constructor', // Getters & Setters ['public-static-get', 'public-static-set'], ['protected-static-get', 'protected-static-set'], ['private-static-get', 'private-static-set'], ['#private-static-get', '#private-static-set'], ['public-decorated-get', 'public-decorated-set'], ['protected-decorated-get', 'protected-decorated-set'], ['private-decorated-get', 'private-decorated-set'], ['public-instance-get', 'public-instance-set'], ['protected-instance-get', 'protected-instance-set'], ['private-instance-get', 'private-instance-set'], ['#private-instance-get', '#private-instance-set'], ['public-abstract-get', 'public-abstract-set'], ['protected-abstract-get', 'protected-abstract-set'], ['public-get', 'public-set'], ['protected-get', 'protected-set'], ['private-get', 'private-set'], ['#private-get', '#private-set'], ['static-get', 'static-set'], ['instance-get', 'instance-set'], ['abstract-get', 'abstract-set'], ['decorated-get', 'decorated-set'], ['get', 'set'], // Methods 'public-static-method', 'protected-static-method', 'private-static-method', '#private-static-method', 'public-decorated-method', 'protected-decorated-method', 'private-decorated-method', 'public-instance-method', 'protected-instance-method', 'private-instance-method', '#private-instance-method', 'public-abstract-method', 'protected-abstract-method', 'public-method', 'protected-method', 'private-method', '#private-method', 'static-method', 'instance-method', 'abstract-method', 'decorated-method', 'method', ], order: 'alphabetically', }, }, ]; const importOrder = [ 'warn', { 'newlines-between': 'always', alphabetize: { order: 'asc', }, groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'], pathGroups: [ { pattern: '@linaria/**', group: 'internal', position: 'before', }, ], pathGroupsExcludedImportTypes: [], }, ]; module.exports = { plugins: ['prettier', 'import'], rules: { 'import/no-extraneous-dependencies': [ 'error', { devDependencies: [ '**/*.test.{js,ts,jsx,tsx}', 'src/{babel,server}/**/*.{js,ts,jsx,tsx}', ], }, ], 'import/no-unresolved': noUnresolved, 'max-len': [ 'error', 150, 2, { ignoreComments: true, ignoreStrings: true, ignoreTemplateLiterals: true, ignoreUrls: true, }, ], 'prettier/prettier': 'error', }, globals: { JSX: 'readonly', }, settings: { 'import/resolver': { node: { extensions: ['.js', '.jsx', '.ts', '.tsx'], }, }, }, overrides: [ { files: ['*.ts', '*.tsx'], extends: [ 'airbnb-base', 'airbnb-typescript/base', 'plugin:@typescript-eslint/recommended', 'prettier', 'plugin:prettier/recommended', 'plugin:import/recommended', 'plugin:import/typescript', ], parserOptions: { project: './tsconfig.eslint.json', }, rules: { 'import/extensions': 0, 'import/no-unresolved': noUnresolved, 'import/order': importOrder, 'import/prefer-default-export': 0, 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }], '@typescript-eslint/consistent-type-imports': [ 'error', { prefer: 'type-imports' }, ], '@typescript-eslint/member-ordering': memberOrder, // TODO '@typescript-eslint/ban-ts-comment': 0, '@typescript-eslint/comma-dangle': 0, '@typescript-eslint/no-non-null-assertion': 0, '@typescript-eslint/no-var-requires': 0, 'global-require': 0, 'import/no-dynamic-require': 0, 'no-underscore-dangle': 0, 'no-restricted-syntax': noRestrictedSyntax, }, }, { files: ['**/processors/**/*.ts'], rules: {}, }, { files: ['*.js', '*.jsx'], extends: [ 'airbnb-base', 'plugin:prettier/recommended', 'plugin:import/recommended', ], parser: '@babel/eslint-parser', parserOptions: { requireConfigFile: false, }, rules: { 'import/no-unresolved': noUnresolved, }, }, { files: [ 'packages/testkit/**/*.test.ts', '**/__tests__/**/*.test.ts', '**/__tests__/**/*.test.tsx', '**/__utils__/**/*.ts', ], rules: { '@typescript-eslint/naming-convention': [ 'error', { selector: 'variable', format: ['camelCase', 'PascalCase', 'UPPER_CASE'], }, { selector: 'function', leadingUnderscore: 'allow', format: ['camelCase', 'PascalCase'], }, { selector: 'typeLike', format: ['PascalCase'], }, ], '@typescript-eslint/no-explicit-any': 0, '@typescript-eslint/no-non-null-assertion': 0, '@typescript-eslint/no-var-requires': 0, 'global-require': 0, 'no-template-curly-in-string': 0, }, }, { files: ['**/__dtslint__/**/*.ts'], rules: { '@typescript-eslint/ban-types': 0, '@typescript-eslint/no-explicit-any': 0, '@typescript-eslint/no-non-null-assertion': 0, '@typescript-eslint/no-unused-expressions': 0, }, }, { files: ['website/**/*.jsx'], extends: [ 'airbnb', 'plugin:prettier/recommended', 'plugin:import/recommended', ], parser: '@babel/eslint-parser', settings: { react: { version: 'detect', }, }, parserOptions: { requireConfigFile: false, babelOptions: { presets: ['@babel/preset-react'], }, }, rules: { 'import/no-unresolved': noUnresolved, 'global-require': 0, }, }, ], }; ================================================ FILE: .git-blame-ignore-revs ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: '🐛 Report a bug' about: 'Report a reproducible bug or reproducible regression.' labels: 'bug report 🦗, needs: triage 🏷, needs: complete repro 🖥️' --- ## Environment - Linaria version: - Bundler (+ version): - Node.js version: - OS: ## Description ## Reproducible Demo ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: 🤔 Questions and Help url: https://discord.gg/fAbHe67 about: Reach the community on discord if you need help or have a question. ================================================ FILE: .github/ISSUE_TEMPLATE/enhancement_request.md ================================================ --- name: '💬 Enhancement proposal' about: Suggest an possible improvement of existing features. labels: 'enhancement: proposal 💬' --- ## Describe the enhancement ## Motivation ## Possible implementations ## Related Issues ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: '💬 Feature proposal' about: Suggest introduction of a new feature. labels: 'feature: proposal 💬' --- ## Describe the feature ## Motivation ## Possible implementations ## Related Issues ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Motivation ## Summary ## Test plan ================================================ FILE: .github/labels.json ================================================ { "labels": { "babel-plugin": { "name": "babel-plugin", "description": "", "colour": "006b75" }, "bug-report": { "name": "bug report 🦗", "description": "Issue is probably a bug, but it needs to be checked", "colour": "f8c4c4" }, "bug": { "name": "bug 🐛", "description": "Issue is a confirmed bug", "colour": "ee0701" }, "bundler-parcel": { "name": "bundler: parcel 🎁", "description": "Issue is related to parcel bundler", "colour": "e5e5e5" }, "bundler-rollup": { "name": "bundler: rollup 🗞️", "description": "Issue is related to rollup bundler", "colour": "e5e5e5" }, "bundler-webpack": { "name": "bundler: webpack 📦", "description": "Issue is related to webpack bundler", "colour": "e5e5e5" }, "cat-documentation": { "name": "cat: documentation 📖", "description": "Work focused on writing documentation", "colour": "f9acca" }, "cat-extend-support": { "name": "cat: extend support 🤝", "description": "Support for a new bundler/platform", "colour": "f9acca" }, "cat-extend-syntax": { "name": "cat: extend syntax ✍", "description": "Support for a new syntax", "colour": "f9acca" }, "cat-improve-publishing": { "name": "cat: improve publishing 🚢", "description": "Issues about improvement of publishing libs with Linaria", "colour": "f9acca" }, "cat-modules-aliasing": { "name": "cat: modules aliasing 🔗", "description": "Issue related to modules aliasing", "colour": "f9acca" }, "cat-monorepo": { "name": "cat: monorepo 🔱", "description": "Issues related to usage of linaria in monorepo", "colour": "f9acca" }, "cat-performance": { "name": "cat: performance 🚀", "description": "Issue is related to performance", "colour": "f9acca" }, "cat-testing": { "name": "cat: testing 🛡", "description": "Issue related to testing components", "colour": "f9acca" }, "cat-typings": { "name": "cat: typings 👮", "description": "Typescript types related issues", "colour": "f9acca" }, "core-team": { "name": "core team 🧬", "description": "Issues reserved for the core team", "colour": "fef2c0" }, "duplicate": { "name": "duplicate", "description": "Issue is a duplicate of another issue", "colour": "cccccc" }, "enhancement-approved": { "name": "enhancement: approved ✅", "description": "Improvement of the current behaviour that has been approved", "colour": "1d76db" }, "enhancement-proposal": { "name": "enhancement: proposal 💬", "description": "Improvement of current behaviour that needs to be discussed", "colour": "1d76db" }, "enhancement-rejected": { "name": "enhancement: rejected ❌", "description": "Improvement of the current behaviour that has been rejected", "colour": "1d76db" }, "feature-approved": { "name": "feature: approved ✅", "description": "New feature that has been approved", "colour": "1d3082" }, "feature-proposal": { "name": "feature: proposal 💬", "description": "New feature proposal that needs to be discussed", "colour": "1d3082" }, "feature-rejected": { "name": "feature: rejected ❌", "description": "New feature that has been rejected", "colour": "1d3082" }, "good-first-issue": { "name": "good first issue 😊", "description": "It is a good issue for new comers", "colour": "5319e7" }, "greenkeeper": { "name": "greenkeeper", "description": "", "colour": "00c775" }, "hacktoberfest": { "name": "hacktoberfest 🍺", "description": "https://hacktoberfest.digitalocean.com/", "colour": "FF8C00" }, "needs-complete-repro": { "name": "needs: complete repro 🖥️", "description": "Issue need to have complete repro provided", "colour": "b2ffbb" }, "needs-help": { "name": "needs: help 🆘", "description": "Help is needed", "colour": "b2ffbb" }, "needs-investigation": { "name": "needs: investigation 🔎", "description": "Issue has to be investigated for reason or solution", "colour": "b2ffbb" }, "needs-more-info": { "name": "needs: more info ℹ", "description": "Not enough information was provided to work on issue", "colour": "b2ffbb" }, "needs-response": { "name": "needs: response 📩", "description": "Response from author/commenters is requested", "colour": "b2ffbb" }, "needs-to-be-grouped": { "name": "needs: to be grouped", "description": "Issue needs to be grouped with other similar issues", "colour": "b2ffbb" }, "needs-triage": { "name": "needs: triage 🏷", "description": "Issue needs to be checked and prioritized", "colour": "b2ffbb" }, "platform-electron": { "name": "platform: electron 🛠️", "description": "Issue related to electron platform", "colour": "00e5e5" }, "platform-next.js": { "name": "platform: next.js 🛠️", "description": "Issue related to next.js", "colour": "00e5e5" }, "platform-react": { "name": "platform: react 🛠️", "description": "Issue related to react", "colour": "00e5e5" }, "platform-ssr": { "name": "platform: ssr 🛠️", "description": "Issue related to SSR", "colour": "00e5e5" }, "platform-vanilla": { "name": "platform: vanilla 🛠️", "description": "Issue related to vanilla css tags", "colour": "00e5e5" }, "platform-svelte": { "name": "platform: svelte 🛠️", "description": "Issue related to svelte", "colour": "00e5e5" }, "priority-critical": { "name": "priority: critical ☢️", "description": "Issue is a critical bug that affects most of the users", "colour": "000000" }, "priority-high": { "name": "priority: high ⚠️", "description": "Issue is important and should be prioritized among others", "colour": "e093f7" }, "priority-low": { "name": "priority: low 📉", "description": "Something nice to have", "colour": "ebebeb" }, "priority-medium": { "name": "priority: medium 💻", "description": "Issue is important but not the most important", "colour": "ffb732" }, "question": { "name": "question ❔", "description": "Question related to the library", "colour": "f9acca" }, "status-has-PR": { "name": "status: has PR 😍", "description": "Issue has opened PR", "colour": "feffa5" }, "status-in-progress": { "name": "status: in progress 🚧", "description": "Someone is working on the issue", "colour": "feffa5" }, "status-merged": { "name": "status: merged 🎉", "description": "Solution was merged", "colour": "feffa5" }, "status-up-for-grabs": { "name": "status: up for grabs 🙏", "description": "research is done and issue is ready to be grabbed", "colour": "feffa5" }, "status-wontfix": { "name": "status: wontfix ⚰", "description": "Issue will not be fixed", "colour": "feffa5" }, "workaround-exist": { "name": "workaround exist", "description": "Workaround for the issue exist", "colour": "70f488" }, "skip-labeling": { "name": "skip autolabeling", "description": "Use it to disable auto laberer bot for an issue/pr", "colour": "D9BBF9" } }, "issue": { "bundler-rollup": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/rollup/i" }, { "type": "descriptionMatches", "pattern": "/rollup/i" } ] }, "bundler-webpack": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/webpack/i" }, { "type": "descriptionMatches", "pattern": "/webpack/i" } ] }, "bundler-parcel": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/parcel/i" }, { "type": "descriptionMatches", "pattern": "/parcel/i" } ] }, "platform-svelte": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/svelte/i" }, { "type": "descriptionMatches", "pattern": "/svelte/i" } ] }, "platform-next.js": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/next(\\.){0,1}js/i" }, { "type": "descriptionMatches", "pattern": "/next(\\.){0,1}js/i" } ] }, "platform-ssr": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/(ssr)|(server)/i" }, { "type": "descriptionMatches", "pattern": "/(ssr)|(server)/i" } ] }, "platform-electron": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/electron/i" }, { "type": "descriptionMatches", "pattern": "/electron/i" } ] }, "cat-performance": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/(slow)|(build[\\s\\S]*time)|(time[\\s\\S]*build)(performance)/i" }, { "type": "descriptionMatches", "pattern": "/(slow)|(build[\\s\\S]*time)|(time[\\s\\S]*build)(performance)/i" } ] }, "cat-testing": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/(test)|(jest)/i" } ] }, "cat-monorepo": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/(monorepo)|(workspace)|(lerna)/i" }, { "type": "descriptionMatches", "pattern": "/(monorepo)|(workspace)|(lerna)/i" } ] }, "cat-modules-aliasing": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/(alias)|(namemapper)/i" }, { "type": "descriptionMatches", "pattern": "/(alias)|(namemapper)/i" } ] }, "cat-typings": { "requires": 1, "conditions": [ { "type": "titleMatches", "pattern": "/typescript/i" }, { "type": "titleMatches", "pattern": "/TS/" } ] } }, "issue_fallback": { "fallbackActivationValue": 2, "labels": [ "needs-triage" ] }, "pr": {}, "skip_labeling": "skip-labeling" } ================================================ FILE: .github/workflows/check.yml ================================================ name: Node.js CI on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ${{ matrix.os }} env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} strategy: fail-fast: false matrix: os: [ubuntu-latest] node-version: [20.x, 22.x] include: - os: windows-latest node-version: 20.x steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v3 with: version: 9 run_install: false - name: Get pnpm store directory id: pnpm-cache shell: bash run: | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - name: Setup pnpm cache uses: actions/cache@v4 with: path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('./pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store- - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Install and prepare run: pnpm install --frozen-lockfile --strict-peer-dependencies - name: ESLint if: matrix.os == 'ubuntu-latest' && matrix.node-version == '20.x' run: pnpm lint - name: TSLint if: matrix.os == 'ubuntu-latest' && matrix.node-version == '20.x' run: pnpm turbo run test:dts - name: Tests run: pnpm turbo run test ================================================ FILE: .github/workflows/main.yml ================================================ name: labeler on: issues: types: [opened, edited, reopened] pull_request: types: [opened, edited, reopened, ready_for_review, synchronize] jobs: labeler: runs-on: ubuntu-latest name: label issues and pull requests steps: - name: check-out-repository uses: actions/checkout@v4 - name: labeler uses: jayu/super-labeler-action@develop env: ACTIONS_STEP_DEBUG: ${{ secrets.ACTIONS_STEP_DEBUG }} with: github-token: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: push: branches: - master concurrency: ${{ github.workflow }}-${{ github.ref }} permissions: contents: write pull-requests: write id-token: write jobs: release: name: Release runs-on: ubuntu-latest env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} steps: - name: Checkout Repo uses: actions/checkout@v4 - uses: pnpm/action-setup@v3 with: version: 9 run_install: false - name: Get pnpm store directory id: pnpm-cache shell: bash run: | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - name: Setup pnpm cache uses: actions/cache@v4 with: path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('./pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store- - name: Setup Node.js 20.x uses: actions/setup-node@v4 with: node-version: 20.x registry-url: 'https://registry.npmjs.org' - name: Upgrade npm for trusted publishing (OIDC) run: npm i -g npm@11.5.1 - name: Install and prepare run: pnpm install --frozen-lockfile --strict-peer-dependencies - name: Create Release Pull Request or Publish to npm id: changesets uses: changesets/action@v1 with: publish: pnpm run release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/site-deploy.yml ================================================ name: Build and Deploy on: push: branches: - master jobs: build-and-deploy: runs-on: ubuntu-latest env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v3 with: version: 9 run_install: false - name: Get pnpm store directory id: pnpm-cache shell: bash run: | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - name: Setup pnpm cache uses: actions/cache@v4 with: path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('./pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store- - name: Use Node.js 20.x uses: actions/setup-node@v4 with: node-version: 20.x - name: Install and prepare run: pnpm install --frozen-lockfile --strict-peer-dependencies - name: Deploy 🚀 uses: JamesIves/github-pages-deploy-action@3.7.1 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages FOLDER: website CLEAN: true ================================================ FILE: .gitignore ================================================ ### OS Junk ### .DS_Store *~ .history ### Node ### # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Optional npm cache directory .npm # Turborepo cache directory .turbo # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env # generated files lib/ esm/ types/ dist/ build/ tsconfig.tsbuildinfo .linaria-cache .wyw-cache # debug *.debug.ts **/linaria-debug **/wyw-debug ================================================ FILE: .npmrc ================================================ lockfile = true ================================================ FILE: .prettierrc ================================================ { "endOfLine": "auto", "trailingComma": "es5", "singleQuote": true } ================================================ FILE: .syncpackrc.js ================================================ module.exports = { dependencyTypes: ['dev', 'overrides', 'pnpmOverrides', 'prod', 'resolutions'], filter: '.', indent: ' ', semverGroups: [], semverRange: '', sortAz: [ 'contributors', 'dependencies', 'devDependencies', 'keywords', 'peerDependencies', 'resolutions', 'scripts', ], // https://github.com/keithamus/sort-package-json/blob/master/defaultRules.md sortFirst: [ '$schema', 'name', 'displayName', 'version', 'private', 'description', 'categories', 'keywords', 'homepage', 'bugs', 'repository', 'funding', 'license', 'qna', 'author', 'maintainers', 'contributors', 'publisher', 'sideEffects', 'type', 'imports', 'exports', 'main', 'svelte', 'umd:main', 'jsdelivr', 'unpkg', 'module', 'source', 'jsnext:main', 'browser', 'react-native', 'types', 'typesVersions', 'typings', 'style', 'example', 'examplestyle', 'assets', 'bin', 'man', 'directories', 'files', 'workspaces', 'binary', 'wyw-in-js', 'scripts', 'betterScripts', 'contributes', 'activationEvents', 'husky', 'simple-git-hooks', 'pre-commit', 'commitlint', 'lint-staged', 'config', 'nodemonConfig', 'browserify', 'babel', 'browserslist', 'xo', 'prettier', 'eslintConfig', 'eslintIgnore', 'npmpackagejsonlint', 'release', 'remarkConfig', 'stylelint', 'ava', 'jest', 'mocha', 'nyc', 'tap', 'resolutions', 'dependencies', 'devDependencies', 'dependenciesMeta', 'peerDependencies', 'peerDependenciesMeta', 'optionalDependencies', 'bundledDependencies', 'bundleDependencies', 'extensionPack', 'extensionDependencies', 'flat', 'packageManager', 'engines', 'engineStrict', 'volta', 'languageName', 'os', 'cpu', 'preferGlobal', 'publishConfig', 'icon', 'badges', 'galleryBanner', 'preview', 'markdown', 'tsup', ], source: [], versionGroups: [ { dependencies: [ '@types/enhanced-resolve', 'css-loader', 'enhanced-resolve', 'mini-css-extract-plugin', 'webpack', ], packages: ['@linaria/webpack4-loader', 'webpack4-example'], }, ], workspace: true, }; ================================================ FILE: .vscode/settings.json ================================================ { "typescript.tsdk": "website/node_modules/typescript/lib" } ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [oss@callstack.io](mailto:oss@callstack.io). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct/ [homepage]: https://www.contributor-covenant.org ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Linaria ## [Code of Conduct](/CODE_OF_CONDUCT.md) We want this community to be friendly and respectful to each other. Please read [the full text](/CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated. ## Our Development Process The core team works directly on GitHub and all work is public. ### Development workflow > **Working on your first pull request?** You can learn how from this *free* series: [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). 1. Fork the repo and create your branch from `master` (a guide on [how to fork a repository](https://help.github.com/articles/fork-a-repo/)). 1. Linaria uses [Pnpm](https://pnpm.io) for running development scripts. If you haven't already done so, please [install Pnpm](https://pnpm.io/installation). 1. Run `pnpm bootstrap` to setup the development environment. 1. When working on the code, you can use the watch mode to watch and compiles changed files: ```sh pnpm watch ``` 1. If you've added code that should be tested, add tests. 1. You can test the changes you are making in our website located under the `website/` folder in the repo. 1. If you've changed APIs, remember to update the documentation under `docs/`. ### Working on the website If you are making changes to the website, test the website folder and run the server to check if your changes are being displayed accurately. To run the development server with live reloading, run: ```sh pnpm website start ``` ### Commit message convention We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages: * `fix`: bug fixes, e.g. fix wrong classname generated by babel plugin. * `feat`: new features, e.g. add support for a config file. * `refactor`: code refactor, e.g. split the babel plugin into multiple visitors. * `docs`: changes into documentation, e.g. add usage example for styled tag. * `test`: adding or updating tests, eg unit, snapshot testing. * `chore`: tooling changes, e.g. change the eslint config. * `BREAKING CHANGE`: for changes that break existing usage, e.g. change the API or behaviour. Our pre-commit hooks verify that your commit message matches this format when committing. If you are working on some in progress commits and don't care about the pre-commit hook, pass the `--no-verify` (`-n`) flag to git when committing (e.g. `git commit -n -m "wip"`). ### Linting and tests We use `eslint` with `prettier` for linting and formatting the code, and `jest` for testing. Our pre-commit hooks verify that the linter and tests pass when commiting. You can also run the following commands manually: * `pnpm typecheck`: run tests for typescript definitions. * `pnpm lint`: lint files with eslint and prettier. * `pnpm test`: run unit tests with jest. ### Sending a pull request When you're sending a pull request: * Prefer small pull requests focused on one change. * Verify that `eslint` and all tests are passing. * Run `pnpm changeset` to generate a changeset. * Preview the documentation to make sure it looks good. * Follow the pull request template when opening a pull request. ## How to try a development build of Linaria in a project To link `linaria` on the command line to local copy in a development build: ```sh cd /path/to/your/linaria_clone/ yarn yarn link cd /path/to/test_project/ yarn link linaria ``` To unlink it: ```sh yarn unlink linaria ``` ### Debugging and deep dive into babel plugin To understand what is actually going in under the hood of Linaria we recommend to first read the top-level [How it works](/docs/HOW_IT_WORKS.md). Then you can run Linaria in debug mode for a specific file from you project and see step-by-step logs informing what is happening. ```sh DEBUG=linaria* LINARIA_LOG=debug npx babel -d dist PATH_TO_COMPONENT ``` > In example we use `npx` to run babel, but you can also put this script into package.json with removed `npx` to run it. You will see how the babel part of Linaria work, result JS file will be stored in `dist` directory. You will not see the resulting CSS file, because this is the role of next layer - bundlers (CSS content is stored in babel metadata to be consumed by bundler). ### Publishing a release We use [release-it](https://github.com/webpro/release-it) to automate our release. If you have publish access to the NPM package, run the following from the master branch to publish a new release: ```sh yarn release ``` NOTE: You must have a `GITHUB_TOKEN` environment variable available. You can create a GitHub access token with the "repo" access [here](https://github.com/settings/tokens). ## Reporting New Issues The best way to get your bug fixed is to provide a reduced test case. Please provide a public repository with a runnable example. ## How to Get in Touch * Callstack Open Source Discord - [#linaria](https://discord.gg/zwR2Cdh). ## Code Conventions We use Prettier with ESLint integration for linting and formatting. To fix any auto-fixable lint or matting errors, run: ```sh pnpm lint -- --fix ``` ## License By contributing to Linaria, you agree that your contributions will be licensed under its MIT license. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2017 Callstack Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ Linaria

Zero-runtime CSS in JS library.

--- [![Build Status][build-badge]][build] [![Code Coverage][coverage-badge]][coverage] [![Version][version-badge]][package] [![MIT License][license-badge]][license] [![All Contributors][all-contributors-badge]](#contributors) [![PRs Welcome][prs-welcome-badge]][prs-welcome] [![Chat][chat-badge]][chat] [![Code of Conduct][coc-badge]][coc] [![Greenkeeper][greenkeeper-badge]][greenkeeper] [![Sponsored by Callstack][callstack-badge]][callstack] [![tweet][tweet-badge]][tweet] ## Features - Write CSS in JS, but with **zero runtime**, CSS is extracted to CSS files during build - Familiar **CSS syntax** with Sass like nesting - Use **dynamic prop based styles** with the React bindings, uses CSS variables behind the scenes - Easily find where the style was defined with **CSS sourcemaps** - **Lint your CSS** in JS with [stylelint](https://github.com/stylelint/stylelint) - Use **JavaScript for logic**, no CSS preprocessor needed - Optionally use any **CSS preprocessor** such as Sass or PostCSS - Supports **atomic styles** with `@linaria/atomic` **[Why use Linaria](/docs/BENEFITS.md)** **[Learn how Airbnb improved both developer experience and web performance with Linaria](https://medium.com/airbnb-engineering/airbnbs-trip-to-linaria-dc169230bd12)** ## Installation ```sh npm install @linaria/core @linaria/react @wyw-in-js/babel-preset ``` or ```sh yarn add @linaria/core @linaria/react @wyw-in-js/babel-preset ``` ## Setup Linaria is now built on top of [wyw-in-js.dev](https://wyw-in-js.dev/). It supports various bundlers to extract the CSS at build time. To configure your bundler, check the following guides on the wyw-in-js.dev site: - [webpack](https://wyw-in-js.dev/bundlers/webpack) - [esbuild](https://wyw-in-js.dev/bundlers/esbuild) - [Rollup](https://wyw-in-js.dev/bundlers/rollup) - [Vite](https://wyw-in-js.dev/bundlers/vite) - [Svelte](https://wyw-in-js.dev/bundlers/svelte) See [Configuration](https://wyw-in-js.dev/configuration) to customize how Linaria processes your files. ## Stability Linaria relies on WyW (`@wyw-in-js/*`) to evaluate your modules at build time and extract CSS. If you hit issues like slow builds, invalidation storms, or unexpected code being executed during the build, it’s usually related to the WyW evaluation model and how your modules are structured. Linaria 7 requires Node.js `>=20` (WyW 1.x enforces this via `engines`). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. ## Syntax Linaria can be used with any framework, with additional helpers for React. The basic syntax looks like this: ```js import { css } from '@linaria/core'; import { modularScale, hiDPI } from 'polished'; import fonts from './fonts'; // Write your styles in `css` tag const header = css` text-transform: uppercase; font-family: ${fonts.heading}; font-size: ${modularScale(2)}; ${hiDPI(1.5)} { font-size: ${modularScale(2.5)}; } `; // Then use it as a class name

Hello world

; ``` You can use imported variables and functions for logic inside the CSS code. They will be evaluated at build time. If you're using [React](https://reactjs.org/), you can use the `styled` helper, which makes it easy to write React components with dynamic styles with a styled-component like syntax: ```js import { styled } from '@linaria/react'; import { families, sizes } from './fonts'; // Write your styles in `styled` tag const Title = styled.h1` font-family: ${families.serif}; `; const Container = styled.div` font-size: ${sizes.medium}px; color: ${props => props.color}; border: 1px solid red; &:hover { border-color: blue; } ${Title} { margin-bottom: 24px; } `; // Then use the resulting component Hello world ; ``` Dynamic styles will be applied using CSS custom properties (aka CSS variables) and don't require any runtime. See [Basics](/docs/BASICS.md) for a detailed information about the syntax. ## Demo [![Edit Linaria Demo](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/linaria-react-vite-ts-qyj5xd) ## Documentation - [Basics](/docs/BASICS.md) - [API and usage](/docs/API.md) - [Client APIs](/docs/API.md#client-apis) - [Server APIs](/docs/API.md#server-apis) - [Configuration](/docs/CONFIGURATION.md) - [Dynamic styles with `css` tag](/docs/DYNAMIC_STYLES.md) - [Theming](/docs/THEMING.md) - [Critical CSS extraction](/docs/CRITICAL_CSS.md) - [Bundlers integration](/docs/BUNDLERS_INTEGRATION.md) - [webpack](/docs/BUNDLERS_INTEGRATION.md#webpack) - [Rollup](/docs/BUNDLERS_INTEGRATION.md#rollup) - [CLI](/docs/CLI.md) - [Linting](/docs/LINTING.md) - [How it works](/docs/HOW_IT_WORKS.md) - [Example](/website) ## Contributing We appreciate any support in library development! Take a look on [Contributing](CONTRIBUTING.md) docs to check how you can run Linaria in development mode. ## Trade-offs - No IE11 support when using dynamic styles in components with `styled`, since it uses CSS custom properties - Dynamic styles are not supported with `css` tag. See [Dynamic styles with `css` tag](/docs/DYNAMIC_STYLES.md) for alternative approaches. - Modules used in the CSS rules cannot have side-effects. For example: ```js import { css } from '@linaria/core'; import colors from './colors'; const title = css` color: ${colors.text}; `; ``` Here, there should be no side-effects in the `colors.js` file, or any file it imports. We recommend to move helpers and shared configuration to files without any side-effects. ## Interoperability with other CSS-in-JS libraries Linaria can work together with other CSS-in-JS libraries out-of-the-box. However, if you want to use styled components from Linaria as selectors in `styled-components`/`emotion`, you need to use [@linaria/interop](/packages/interop/README.md) ## Editor Plugins ### VSCode - Syntax Highlighting - [language-babel](https://marketplace.visualstudio.com/items?itemName=mgmcdermott.vscode-language-babel) - Autocompletion - [vscode-styled-components](https://marketplace.visualstudio.com/items?itemName=styled-components.vscode-styled-components) - Linting - [stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) ### Atom - Syntax Highlighting and Autocompletion - [language-babel](https://atom.io/packages/language-babel) ### Webstorm - Syntax Highlighting & Autocompletion - [webstorm-styled-components](https://github.com/styled-components/webstorm-styled-components) ### Sublime Text - Syntax Highlighting & Autocompletion - [Naomi](https://packagecontrol.io/packages/Naomi), [JSCustom](https://packagecontrol.io/packages/JSCustom) (refer to document on how to turn on Styled Component syntax) - Linting - [SublimeLinter-stylelint](https://packagecontrol.io/packages/SublimeLinter-stylelint), [LSP Stylelint](https://packagecontrol.io/packages/LSP-stylelint) ## Recommended Libraries - [gatsby-plugin-linaria](https://github.com/cometkim/gatsby-plugin-linaria) – Gatsby plugin that sets up Babel and webpack configuration for Linaria. - [polished.js](https://polished.js.org/) - A lightweight toolset for writing styles in JavaScript. - [craco-linaria](https://github.com/jedmao/craco-linaria) - A [Craco](https://www.npmjs.com/package/@craco/craco) plugin that allows you to use Linaria [without ejecting](https://create-react-app.dev/docs/alternatives-to-ejecting) from a [CRA](https://create-react-app.dev/). ## Inspiration - [glam](https://github.com/threepointone/glam) - [styled-components](https://github.com/styled-components/styled-components) - [css-literal-loader](https://github.com/4Catalyzer/css-literal-loader) ## Acknowledgements This project wouldn't have been possible without the following libraries or the people behind them. - [babel](https://babeljs.io/) - [stylis.js](https://github.com/thysultan/stylis.js) Special thanks to [@kentcdodds](https://github.com/kentcdodds) for his babel plugin and [@threepointone](https://github.com/threepointone) for his suggestions and encouragement. ## Made with ❤️ at Callstack Linaria is an open source project and will always remain free to use. If you think it's cool, please star it 🌟. [Callstack](https://callstack.com) is a group of React and React Native geeks, contact us at [hello@callstack.com](mailto:hello@callstack.com) if you need any help with these or just want to say hi! Like the project? ⚛️ [Join the team](https://callstack.com/careers/?utm_campaign=Senior_RN&utm_source=github&utm_medium=readme) who does amazing stuff for clients and drives React Native Open Source! 🔥 ## Sponsors

{callstack}

Servers.com

## Contributors Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):
Paweł Trysła
Paweł Trysła

💻 📖 🤔
Satyajit Sahoo
Satyajit Sahoo

💻 📖 🤔
Michał Pierzchała
Michał Pierzchała

💻 📖 🤔
Lucas
Lucas

📖
Alexey Pronevich
Alexey Pronevich

📖
Wojtek Szafraniec
Wojtek Szafraniec

💻
Anton Evzhakov
Anton Evzhakov

💻 🤔 📖
Tushar Sonawane
Tushar Sonawane

📖 💡
Ferran Negre
Ferran Negre

📖
Jakub Beneš
Jakub Beneš

💻 📖
Oscar Busk
Oscar Busk

🐛 💻
Dawid
Dawid

💻 📖
Kacper Wiszczuk
Kacper Wiszczuk

💻 📖
Denis Rul
Denis Rul

💻
Johan Holmerin
Johan Holmerin

💻 📖
Gilad Peleg
Gilad Peleg

📖
Giuseppe
Giuseppe

💻
Matija Marohnić
Matija Marohnić

💻 📖
Stefan Schult
Stefan Schult

💻
Ward Peeters
Ward Peeters

💻
radoslaw-medryk
radoslaw-medryk

💻
杨兴洲
杨兴洲

💻
Dawid Karabin
Dawid Karabin

📖
Chris Abrams
Chris Abrams

💻 📖 🤔
Jayphen
Jayphen

💻
c4605
c4605

💻
Toru Kobayashi
Toru Kobayashi

💻
Jakub Mazurek
Jakub Mazurek

💻
Joshua Nelson
Joshua Nelson

💻 🤔 📖
Tomasz Krzyżowski
Tomasz Krzyżowski

💻
Martin Schulze
Martin Schulze

💻
wmzy
wmzy

💻
Hyeseong Kim
Hyeseong Kim

💻
Martin Hochel
Martin Hochel

💻
Daniel Lo Nigro
Daniel Lo Nigro

💻
0xflotus
0xflotus

💻
Afzal Sayed
Afzal Sayed

💻
AijiUejima
AijiUejima

💻
Oleksii Vasyliev
Oleksii Vasyliev

💻
Alican Erdoğan
Alican Erdoğan

💻
Aman Kubanychbek
Aman Kubanychbek

💻
Andrew Gerard
Andrew Gerard

💻
Andrey Frolov
Andrey Frolov

💻
Benjamin Solum
Benjamin Solum

💻
Billy Kwok
Billy Kwok

💻
Christian Todd
Christian Todd

💻
David Peek
David Peek

💻
Denis Skiba
Denis Skiba

💻
Dima Kharitonov
Dima Kharitonov

💻
Gabriel Valfridsson
Gabriel Valfridsson

💻
Gitai
Gitai

💻
Hampus Kraft
Hampus Kraft

💻
Igor Sukharev
Igor Sukharev

💻
Ikko Ashimine
Ikko Ashimine

💻
Iman Mohamadi
Iman Mohamadi

💻
JB <codecorsair>
JB

💻
Jack Works
Jack Works

💻
James George
James George

💻
Jed Mao
Jed Mao

💻
Joe Lencioni
Joe Lencioni

💻
Joey Cozza
Joey Cozza

💻
Juan Ferreras
Juan Ferreras

💻
Kazuma Ebina
Kazuma Ebina

💻
Lars Kappert
Lars Kappert

💻
Luciano Mammino
Luciano Mammino

💻
Madhav Varshney
Madhav Varshney

💻
Malash
Malash

💻
Martijn Swaagman
Martijn Swaagman

💻
Matias Lahti
Matias Lahti

💻
Michael James
Michael James

💻
Michael Strobel
Michael Strobel

💻
Michał Chudziak
Michał Chudziak

💻
Mike
Mike

💻
Mike Stop Continues
Mike Stop Continues

💻
Mokshit Jain
Mokshit Jain

💻
Oleksandr Fediashov
Oleksandr Fediashov

💻
Paddy O'Brien
Paddy O'Brien

💻
Patrik Smělý
Patrik Smělý

💻
Pavel Udaloff
Pavel Udaloff

💻
Przemysław Bitkowski
Przemysław Bitkowski

💻
RiN
RiN

💻
Roman Sokhan
Roman Sokhan

💻
Seokmin Hong (Ray)
Seokmin Hong (Ray)

💻
Serge K Lebedev
Serge K Lebedev

💻
Sergey Korovin
Sergey Korovin

💻
Shreyas Sreenivas
Shreyas Sreenivas

💻
Sky Wickenden
Sky Wickenden

💻
Stanislav Panferov
Stanislav Panferov

💻
Ted Jenkins
Ted Jenkins

💻
Thanh Tran
Thanh Tran

💻
Thor Amorim
Thor Amorim

💻
tobenna
tobenna

💻
Tomas Carnecky
Tomas Carnecky

💻
Tsubasa1218
Tsubasa1218

💻
Turadg Aleahmad
Turadg Aleahmad

💻
Vitor Buzinaro
Vitor Buzinaro

💻
Mistereo
Mistereo

💻
Vladislav Kozulya
Vladislav Kozulya

💻
Yuhei Yasuda
Yuhei Yasuda

💻
Danil Kamyshov
Danil Kamyshov

💻
Sebastian Landwehr
Sebastian Landwehr

💻
everdimension
everdimension

💻
ptol
ptol

💻
roottool
roottool

💻
ryamaguchi0220
ryamaguchi0220

💻
simka
simka

💻
soso
soso

💻
Nikita Skovoroda
Nikita Skovoroda

💻
黄小健
黄小健

💻
iMoses
iMoses

💻
Jeremy Neander
Jeremy Neander

💻
Andy Parsons
Andy Parsons

💻
Platane
Platane

📖
Tim Kutnick
Tim Kutnick

📖
Dmitrii Pikulin
Dmitrii Pikulin

💻
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! [build-badge]: https://img.shields.io/circleci/project/github/callstack/linaria/master.svg?style=flat-square [build]: https://circleci.com/gh/callstack/linaria [coverage-badge]: https://img.shields.io/codecov/c/github/callstack/linaria.svg?style=flat-square [coverage]: https://codecov.io/github/callstack/linaria [version-badge]: https://img.shields.io/npm/v/linaria.svg?style=flat-square [package]: https://www.npmjs.com/package/linaria [license-badge]: https://img.shields.io/npm/l/linaria.svg?style=flat-square [license]: https://opensource.org/licenses/MIT [prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square [prs-welcome]: https://github.com/callstack/linaria/blob/master/CONTRIBUTING.md [coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square [coc]: https://github.com/callstack/linaria/blob/master/CODE_OF_CONDUCT.md [all-contributors-badge]: https://img.shields.io/badge/all_contributors-23-orange.svg?style=flat-square [chat-badge]: https://img.shields.io/discord/426714625279524876.svg?style=flat-square&colorB=758ED3 [chat]: https://discord.gg/zwR2Cdh [tweet-badge]: https://img.shields.io/badge/tweet-%23linaria-blue.svg?style=flat-square&colorB=1DA1F2&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAUCAYAAACXtf2DAAAAAXNSR0IArs4c6QAAAaRJREFUOBGtlM8rBGEYx3cWtRHJRaKcuMtBSitxkCQ3LtzkP9iUUu5ODspRHLhRLtq0FxeicEBC2cOivcge%2FMgan3fNM8bbzL4zm6c%2BPT%2Fe7%2FO8887svrFYBWbbtgWzsAt3sAcpqJFxxF1QV8oJFqFPFst5dLWQAT87oTgPB7DtziFRT1EA4yZolsFkhwjGYFRO8Op0KD8HVe7unoB6PRTBZG8IctAmG1xrHcfkQ2B55sfI%2ByGMXSBqV71xZ8CWdxBxN6ThFuECDEAL%2Bc9HIzDYumVZ966GZnX0SzCZvEqTbkaGywkyFE6hKAsBPhFQ18uPUqh2ggJ%2BUor%2F4M%2F%2FzOC8g6YzR1i%2F8g4vvSI%2ByD7FFNjexQrjHd8%2BnjABI3AU4Wl16TuF1qANGll81jsi5qu%2Bw6XIsCn4ijhU5FmCJpkV6BGNw410hfSf6JKBQ%2FUFxHGYBnWnmOwDwYQ%2BwzdHqO75HtiAMJfaC7ph32FSRJCENUhDHsLaJkL%2FX4wMF4%2BwA5bgAcrZE4sr0Cu9Jq9fxyrvBHWbNkMD5CEHWTjjT2m6r5D92jfmbbKJEWuMMAAAAABJRU5ErkJggg%3D%3D [tweet]: https://twitter.com/intent/tweet?text=Check%20out%20linaria!%20https://github.com/callstack/linaria%20%F0%9F%91%8D [greenkeeper-badge]: https://badges.greenkeeper.io/callstack/linaria.svg [greenkeeper]: https://greenkeeper.io/ [callstack-badge]: https://callstack.com/images/callstack-badge.svg [callstack]: https://callstack.com/open-source/?utm_source=github.com&utm_medium=referral&utm_campaign=linaria&utm_term=readme ================================================ FILE: babel.config.js ================================================ /* * The following environments are supported: * * (unspecified): Produces ES module output, no language features * (except non-standard ones) are transpiled. * "legacy": Produces CommonJS output, uses @babel/preset-env to target * Node.js 12 and specific browsers. * "test": Used by Jest, produces CommonJS output, targetting * the same version as legacy. */ /* * Configuration for the legacy build */ const commonJSTargets = { browsers: '> 0.25% and supports array-includes', // browsers: 'chrome > 90', node: '12', }; module.exports = { presets: ['@babel/preset-typescript'], plugins: ['@babel/plugin-proposal-explicit-resource-management'], env: { legacy: { presets: [ [ '@babel/preset-env', { targets: { node: commonJSTargets.node, }, }, ], ], }, test: { presets: [ [ '@babel/preset-env', { targets: { node: commonJSTargets.node, }, }, ], '@babel/preset-typescript', ], }, }, overrides: [ { /** * only react and core packages are targeted to be run in the browser */ test: /[\\/]packages[\\/](?:atomic|core|react)[\\/](?!src[\\/]processors[\\/])/, presets: ['@babel/preset-react'], env: { legacy: { presets: [ [ '@babel/preset-env', { targets: commonJSTargets.browsers, loose: true, // our styled component should not need to use any polyfill. We do not include core-js in dependencies. However, we leave this to detect if future changes would not introduce any need for polyfill useBuiltIns: 'usage', // Even core-js doesn't remember IE11 exclude: ['es.array.includes', 'web.dom-collections.iterator'], corejs: 3, // this is used to test if we do not introduced core-js polyfill debug: process.env.DEBUG_CORE_JS === 'true', }, ], ], }, }, }, { /** * we have to transpile JSX in tests */ test: /[\\/](__tests__|__fixtures__|packages[\\/]teskit[\\/]src)[\\/]/, presets: ['@babel/preset-react'], }, ], }; ================================================ FILE: commitlint.config.js ================================================ module.exports = { extends: ['@commitlint/config-conventional'], }; ================================================ FILE: docs/API.md ================================================ # API Linaria exposes a core `css` method alongside with small, but just enough amount of helpers. Inside `@linaria/core` module you can find following methods: ## Client APIs ### `css` String tag for tagged template literals consisting CSS code. The tagged template literal is evaluated to a unique class name by the Babel plugin: ```js import { css } from '@linaria/core'; const flower = css` display: inline; color: violet; `; // flower === flower__9o5awv –> with babel plugin ``` All rules inside the template literal are scoped to the class name, including media queries and animations. For example, we can declare CSS animation like so: ```js import { css } from '@linaria/core'; const box = css` animation: rotate 1s linear infinite; @keyframes rotate { { from: 0deg; } { to: 360deg; } } `; ``` ### `cx(...classNames: Array) => string` Takes a list of class names and returns a concatenated string with the class names. Falsy values are ignored. ```js import { css, cx } from '@linaria/core'; const cat = css` font-weight: bold; `; const yarn = css` color: violet; `; const fun = css` display: flex; `; function App({ isPlaying }) { return ; } ``` Unlike the [`classnames`](https://www.npmjs.com/package/classnames) library, this doesn't handle objects. If you want or need the features of the `classnames` library, you can use it instead. ### `styled` Helper to build React components. It allows you to write your components in a similar syntax as [`styled-components`](https://www.styled-components.com/): The syntax is similar to the `css` tag. Additionally, you can use function interpolations that receive the component's props: ```js import { styled } from '@linaria/react'; import colors from './colors.json'; const Container = styled.div` background-color: ${colors.background}; color: ${(props) => props.color}; width: ${100 / 3}%; border: 1px solid red; &:hover { border-color: blue; } `; ``` All rules inside the template literal are scoped to the component, similar to the `css` tag. Dynamic function interpolations are replaced with CSS custom properties. A dynamic function interpolation will receive the `props` of the component as it's arguments and the returned result will be used as the value for the variable. When using this, a tiny helper is imported so that we don't duplicate the code for creating the component in all files. You can also interpolate a component to refer to it: ```js const Title = styled.h1` font-size: 36px; `; const Article = styled.article` font-size: 16px; /* this will evaluate to the selector that refers to `Title` */ ${Title} { margin-bottom: 24px; } `; ``` If you want to swap out the tag that's rendered, you can use the `as` prop: ```js // Here `Button` is defined as a `button` tag const Button = styled.button` background-color: rebeccapurple; `; // You can switch it to use an `a` tag with the `as` prop ; ``` You can also decorate another styled component with `styled`: ```js const Button = styled.button` background-color: rebeccapurple; `; // The background-color in FancyButton will take precedence const FancyButton = styled(Button)` background-color: black; `; ``` ### Atomic `css` In addition to `css` from `@linaria/core`, the `@linaria/atomic` package exports its own `css` template literal which produces _atomic_ styles. See [the atomic css documentation](./ATOMIC_CSS.md) on this for more information. ## Server APIs (`@linaria/server`) ### `collect(html: string, css: string) => string` Takes HTML and CSS strings and returns the critical CSS used in the page by analyzing the class names. It can be used to determine critical CSS for server side rendering. ```js import { collect } from '@linaria/server'; const css = fs.readFileSync('./dist/styles.css', 'utf8'); const html = ReactDOMServer.renderToString(); const { critical, other } = collect(html, css); // critical – returns critical CSS for given html // other – returns the rest of styles ``` This will only detect critical CSS based on class names, so if you have any other type of selectors, they'll get added to the critical CSS. Also note that extracting critical CSS this way will change the order of class names. It's not a problem if you're primarily using Linaria for styling. However if you're using a third party framework which imports its own CSS, then it's not recommended to use this helper on the extracted CSS. ================================================ FILE: docs/ATOMIC_CSS.md ================================================ # Atomic CSS ## What is Atomic CSS? Atomic CSS is an approach to styling that reduces payload sizes for style delivery, and allows style composition and reuse easily. This document describes the concept of Atomic CSS, its advantage and use cases. Atomic CSS is a way of writing CSS such that each CSS rule has exactly one declaration (an "atom"). For example, ```css /** A normal class */ .myClass { background: red; width: 100%; height: 100%; } /** Can be written atomically as: */ .a { background: red; } .b { width: 100%; } .c { height: 100%; } ``` ## Usage in Linaria Atomic styles can be enabled in the linaria config by providing an `atomizer` function (see [configuration](./CONFIGURATION.md) for details). Once enabled, it is possible to write atomic styles by importing the `css` template literal from `@linaria/atomic`: ```tsx import { cx } from '@linaria/core'; import { css } from '@linaria/atomic'; const atomicCss = css` background: red; width: 100%; height: 100%; border: 1px solid black; `; const blueBackground = css` background: blue; border: 1px solid black; `; // In React:
; // In vanilla JS: const div = document.createElement('div'); div.setAttribute('class', cx(atomicCss, blueBackground)); document.body.appendChild(div); ``` Which at build time, is transformed into: ```ts import { cx } from '@linaria/core'; import { css } from '@linaria/atomic'; const atomicCss = 'atm_background_abcd atm_width_efgh atm_height_ijkl atm_border_mnop'; const blueBackground = 'atm_background_qrst atm_border_mnop'; // In React:
; //
// In vanilla JS: const div = document.createElement('div'); div.setAttribute('class', cx(atomicCss, blueBackground)); // same as React example document.body.appendChild(div); ``` (Note: in the example above, the slugs in the atoms are lengthened for readability) The format of these atoms is `atm_${propertySlug}_${valueSlug}` which lets us deduplicate based on the `propertySlug` part of the atom. As you can see in the above example, `atm_border_mnop` can be removed as it duplicated, and we see two atoms with the `background` property slug, and can remove one of them. ### at-rules, pseudo classes and keyframes Linaria's atomic css also supports creating (nested) at-rules, pseudo classes and keyframes: ```ts import { css } from '@linaria/atomic'; // Note: animation name namespacing does not happen automatically with @linaria/atomic. Keyframe animations are pulled out to the top level and not atomized. export const animation = css` @keyframes my-animation { from { opacity: 0; } to { opacity: 1; } } animation: my-animation 1s infinite; `; export const pseudoClass = css` &:hover { color: pink; } `; export const mediaQuery = css` @media (max-width: 400px) { background: orange; } `; ``` These can also be combined for further nesting. ### Property priorities Using atomic CSS, longhand properties such as `padding-top` have a _higher_ priority than their shorthand equivalents like `padding`. For example: ```ts import { css } from '@linaria/atomic'; const noPadding = css` padding: 0; `; const paddingTop = css` padding-top: 5px: `; // In react:
...
; ``` The result will be that the div has `padding-top: 5px;`, as that is higher priority than `padding: 0`. The way linaria achieves this is through property priorities. See [this blog post](https://weser.io/blog/the-shorthand-longhand-problem-in-atomic-css) for more details on the concept, and the problems it solves. The method used in linaria is to increase the specificity of the rules: see `@linaria/atomic`'s `propertyPriority` function for a list of longhand and shorthand properties supported by this. The basic rules are: - Longhand properties have higher priority than shorthand properties - Declarations in @media rules (and any @-rule, such as @supports) have higher priority than those outside of them ## Use cases ### Reducing number of rules One advantage of writing styles in this way is that we can reuse CSS more effectively. In many cases, declarations are repeated in CSS, and atomic CSS allows heavy reuse of these classes. For example if we have the classes, ```html //here I use it ); export default Header; ``` > You can also use the `styled` variant, importing from `@linaria/react`. If you run `npm run dev`, you should be able to see a button next to the nav title, with red bold text. You can take a look at this example [here](../examples/Preact) ## Gatsby If you wish you use Gatsby, we recommend you to use the `gatsby-cli` and start from there. The following configuration assumes you are using the default template provided by gatsby-cli. Start by creating your project using: ``` npx gatsby new my-project ``` Now, you have two options. You can use `gatsby-plugin-linaria` or create a custom config. ### gatsby-plugin-linaria This is an easier and more straightforward way of integrating Linaria with Gatsby. Check [plugin docs](https://github.com/cometkim/gatsby-plugin-linaria) for instructions. You can also take a look at the example [here](../examples/gatsby/plugin) ### Custom config This is a bit more advanced way of integrating Linaria into your Gatsby project. First, you will need to install `@linaria/babel-preset` and `babel-preset-gatsby`. Then, create `babel.config.js` in the root of your project with the following contents: ```js module.exports = { presets: [ 'babel-preset-gatsby', [ '@linaria', { evaluate: true, displayName: process.env.NODE_ENV !== 'production', }, ], ], }; ``` You can read more about configuring Babel in Gatsby projects in [their docs](https://www.gatsbyjs.org/docs/babel/). Besides that, you will need to alter Gatsby's Webpack config to modify the Babel loader. This can be done in `gatsby-node.js` file. Consider the following snippet: ```js exports.onCreateWebpackConfig = ({ actions, loaders, getConfig, stage }) => { const config = getConfig(); config.module.rules = [ ...config.module.rules.filter( (rule) => String(rule.test) !== String(/\.js?$/) ), { ...loaders.js(), test: /\.js?$/, loader: '@linaria/webpack-loader', options: { sourceMap: stage.includes('develop'), displayName: stage.includes('develop'), babelOptions: { presets: ['babel-preset-gatsby'], }, }, exclude: /node_modules/, }, ]; actions.replaceWebpackConfig(config); }; ``` If you want to know more about extending Webpack config in Gatsby projects, check out [relevant Gatsby docs](https://www.gatsbyjs.org/docs/add-custom-webpack-config/). With that done, you should be all set! You can take a look at the minimal example using the above configuration [here](../examples/gatsby/custom-config). ================================================ FILE: docs/CRITICAL_CSS.md ================================================ # Critical CSS extraction Since Linaria extracts the CSS statically at build time, you don't need to setup a server rendering. Usually, critical CSS extraction will be automatic if you are code splitting your code and using something like [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) for webpack to generate your CSS files. If you're not code splitting, or the initial CSS chunk is not representative of initially rendered content, you might want to extract critical CSS using the `collect` helper we provide to ship the minimal amount of CSS used in the page to the browser. To be able to use the `collect` helper, you need to provide the initial HTML, which usually means that you need to have SSR setup for your web app. The `collect` method takes some HTML and CSS and gives you the critical CSS: ```js import { collect } from '@linaria/server'; const { critical, other } = collect(html, css); ``` For example, in an express app with React, you could do something like the following: ```js import fs from 'fs'; import express from 'express'; import crypto from 'crypto'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; import { collect } from '@linaria/server'; import App from './App'; const cache = {}; const css = fs.readFileSync('./dist/styles.css', 'utf8'); const app = express(); app.get('/', (req, res) => { const html = ReactDOMServer.renderToString(); const { critical, other } = collect(html, css); const slug = crypto.createHash('md5').update(other).digest('hex'); cache[slug] = other; res.end(` App
${html}
`); }); app.get('/styles/:slug', (req, res) => { res.type('text/css'); res.end(cache[req.params.slug]) }); app.listen(3242); ``` By placing the non-critical CSS at the end of `body`, you can make sure that page rendering is not blocked until the CSS is loaded. You can also load the non-critical CSS lazily with JavaScript once the page has loaded for a more efficient strategy. However, it's highly recommended that you take advantage of code splitting in webpack which gives you automatic CSS chunks in addition to critical CSS. ================================================ FILE: docs/DYNAMIC_STYLES.md ================================================ # Dynamic styles with `css` tag Sometimes we have some styles based on component's props or state, or dynamic in some way. If you use the `styled` helper with React, this is automatically handled using CSS custom properties. But we cannot do the same for `css` tags since they aren't linked to any component, and so we don't have access to state and props. However, there are some approaches to tackle this, each with their own limitations. ## Inline styles Inline styles are the most straightforward way to use dynamic styles. Pass a `style` object with the dynamic styles, and you're done. ```js import React from 'react'; export function Pager({ index, children }) { return (
{children}
); } ``` However, it's not possible to use inline styles with pseudo-selectors or media queries. ## CSS custom properties [CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) can be used to expose dynamic properties to the CSS. ```js import React from 'react'; import { css } from '@linaria/core'; const box = css` height: var(--box-size); width: var(--box-size); `; export function Box({ size }) { return (
); } ``` The [browser support for CSS custom properties](http://caniuse.com/#feat=css-variables) is limited, and it's not polyfilled. Therefore it's not a viable approach if you need to support older browsers. Worth noting that custom properties cascade, so if you don't override the value for the current element, and a custom property with the same name exists for a parent element, it'll be used instead. ## Data attributes In cases where you know the values ahead of time, you can use [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes) to dynamically switch the styles that are applied. ```js import React from 'react'; import { css } from '@linaria/core'; const box = css` &[data-valid] { color: yellow; } &[data-valid="invalid"] { color: red; } &[data-valid="valid"] { color: green; } ` export function Box({ color, valid }) { return (
); } ``` ## `currentColor` For color values, browsers support a `currentColor` property which points to the text color of the element. It is well supported in all browsers. ```js import React from 'react'; import { css } from '@linaria/core'; const box = css` background-color: currentColor; `; const content = css` color: white; `; export function Box({ color }) { return (
¯\_(ツ)_/¯
); } ``` You cannot use this approach if the dynamic value is not a color, or the element contains some text which needs to be styled with a different color. If the element has children, you will need to reset the `color` property for the text. ================================================ FILE: docs/FEATURE_FLAGS.md ================================================ # Feature Flags Feature flags are used to enable or disable specific features provided. The `features` option in the configuration allows you to control the availability of these features. ## Syntax for Specifying Flags - `true`: Enables the feature for all files. - `false`: Disables the feature for all files. - `"glob"`: Enables the feature only for files that match the specified glob pattern. - `["glob1", "glob2"]`: Enables the feature for files matching any of the specified glob patterns. - `["glob1", "!glob2"]`: Enables the feature for files matching `glob1` but excludes files that match `glob2`. # `dangerousCodeRemover` Feature The `dangerousCodeRemover` is a flag that is enabled by default. It is designed to enhance the static evaluation of values that are interpolated in styles and to optimize the processing of styled-wrapped components during the build stage. This optimization is crucial for maintaining a stable and fast build process. It is important to note that the `dangerousCodeRemover` does not impact the runtime code; it solely focuses on the code used during the build. ## How It Works During the build process, Linaria statically analyzes the CSS-in-JS codebase and evaluates the styles and values that are being interpolated. The `dangerousCodeRemover` steps in at this stage to remove potentially unsafe code, which includes code that might interact with browser-specific APIs, make HTTP requests, or perform other runtime-specific operations. By removing such code, the evaluation becomes more reliable, predictable, and efficient. ## Benefits Enabling the `dangerousCodeRemover` feature provides several benefits: 1. **Stability**: The removal of potentially unsafe code ensures that the build process remains stable. It minimizes the chances of encountering build-time errors caused by unsupported browser APIs or non-static operations. 2. **Performance**: Removing unnecessary code results in faster build times. The build tool can efficiently process and evaluate the styles and components without unnecessary overhead, leading to quicker development cycles. ## Fine-Tuning the Removal While the `dangerousCodeRemover` is highly effective at optimizing the build process, there may be cases where it becomes overly aggressive and removes code that is actually required for your specific use case. In such situations, you have the flexibility to fine-tune the behavior of the remover. By leveraging the `features` option in the configuration, you can selectively disable the `dangerousCodeRemover` for specific files. This allows you to preserve valuable code that may not be safely evaluated during the build process. ### Example Suppose you have a file named `specialComponent.js` that contains code that should not be deleted. By adding the following entry to your `features` configuration: ```js { features: { dangerousCodeRemover: ["**/*", "!**/specialComponent.js"], }, } ``` You are instructing Linaria to exclude the `specialComponent.js` file from the removal process. As a result, any code within this file that would have been removed by the `dangerousCodeRemover` will be retained in the build output. # `globalCache` Feature The `globalCache` is enabled by default. Linaria uses two levels of caching to improve the performance of the build process. The first level is used to cache transformation and evaluation results for each `transform` call, usually a single call of Webpack's loader or Vite's transform hook. The second level is used to cache the results of the entire build process. The `globalCache` feature controls the second level of caching. Turning off this feature will result in a slower build process but decreased memory usage. # `happyDOM` Feature The `happyDOM` is enabled by default. This feature enables usage of https://github.com/capricorn86/happy-dom to emulate a browser environment during the build process. Typically, the `dangerousCodeRemover` feature should remove all browser-related code. However, some libraries may still contain browser-specific code that cannot be statically evaluated. In such cases, the `happyDOM` feature can be used to emulate a browser environment during the build process. This allows Linaria to evaluate the code without encountering errors caused by missing browser APIs. # `softErrors` Feature The `softErrors` is disabled by default. It is designed to provide a more lenient evaluation of styles and values that are interpolated in styles. This flag is useful for debugging and prevents the build from failing even if some files cannot be processed with Linaria. # 'useBabelConfigs' Feature The `useBabelConfigs` feature is enabled by default. If it is enabled, Linaria will try to resolve the `.babelrc` file for each processed file. Otherwise, it will use the default Babel configuration from `babelOptions` in the configuration. Please note that the default value of `useBabelConfigs` will be changed to `false` in the next major release. ================================================ FILE: docs/HOW_IT_WORKS.md ================================================ # How it works Linaria consists of 2 parts: 1. Babel plugin 2. Bundler integration ## Babel plugin The Babel plugin will look for `css` and `styled` tags in your code, extract the CSS out and return it in the file's metadata. It will also generate unique class names based on the hash of the filename. > To get a deep dive into Linaria babel plugin internals, check [debugging section of Contributing docs](../CONTRIBUTING.md#debugging-and-deep-dive-into-babel-plugin) When using the `styled` tag, dynamic interpolations will be replaced with CSS custom properties. References to constants in the scope will also be inlined. If the same expression is used multiple times, the plugin will create a single CSS custom property for those. The interpolations used for the CSS custom properties are left in the file, and are passed to the helper which creates the React components. Function interpolations receive the component's props and their return value will be used as the value for the CSS custom property. For other expressions, their result is used as is. If the resulting values aren't strings, they'll be converted to a string before setting the property. Inline styles are used to set the custom properties. For example, the plugin will transpile this: ```js import { styled } from '@linaria/react'; import { families, sizes } from './fonts'; const background = 'yellow'; const Title = styled.h1` font-family: ${families.serif}; `; const Container = styled.div` font-size: ${sizes.medium}px; background-color: ${background}; color: ${props => props.color}; width: ${100 / 3}%; border: 1px solid red; &:hover { border-color: blue; } `; ``` To this: ```js import { styled } from '@linaria/react'; import { families, sizes } from './fonts'; const background = 'yellow'; const Title = styled('h1')({ name: 'Title', class: 'Title_t1ugh8t', vars: { 't1ugh8t9-0': [families.serif], }, }); const Container = styled('div')({ name: 'Container', class: 'Container_c1ugh8t', vars: { 'c1ugh8t9-0': [sizes.medium, 'px'], 'c1ugh8t9-2': [props => props.color], }, }); ``` The extracted CSS will look something like this: ```css .Title_t1ugh8t9 { font-family: var(--t1ugh8t-0); } .Container_c1ugh8t9 { font-size: var(--c1ugh8t-0); background-color: yellow; color: var(--c1ugh8t-2); width: 33.333333333333336%; border: 1px solid red; } .Container_c1ugh8t9:hover { border-color: blue; } ``` If we encounter a valid unit directly after the interpolation, it'll be passed to the helper so that the correct unit is used when setting the property. This allows you to write this: ```js const Title = styled.h1` font-size: ${large}px; `; ``` Instead of having to write this: ```js const Title = styled.h1` font-size: ${large + 'px'}; `; ``` It's necessary since if we just replaced the interpolation as is, it wouldn't be a valid syntax: ```css .Title_t1ugh8t9 { font-size: var(--t1ugh8t9-0-0)px; /* you can't have 'px' after the `var(..)` */ } ``` If we encounter a JS object when inlining, the JS object is assumed to be a style rule and converted to a CSS string before inlining it. For example, if you write this: ```js const absoluteFill = { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, }; const Container = styled.h1` background-color: papayawhip; ${Box} { ${absoluteFill} } `; ``` It is equivalent to writing this: ```js const Container = styled.h1` background-color: papayawhip; ${Box} { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } `; ``` We support this usage because it allows you to use a library such as [polished.js](https://polished.js.org) which outputs object based styles along with Linaria. If you've configured the plugin to evaluate expressions with `evaluate: true` (default), any dynamic expressions we encounter will be evaluated during the build-time in a sandbox, and the result will be included in the CSS. Since these expressions are evaluated at build time in Node, you cannot use any browser specific APIs or any API which is only available in runtime. Access to Node native modules such as `fs` is also not allowed inside the sandbox to prevent malicious scripts. In addition, to achieve consistent build output, you should also avoid doing any side effects in these expressions and keep them pure. You might want to skip evaluating a certain interpolation if you're using a browser API, a global variable which is only available at runtime, or a module which breaks when evaluating in the sandbox for some reason. To skip evaluating an interpolation, you can always wrap it in a function, like so: ```js const Box = styled.h1` height: ${() => window.innerHeight * 2}; `; ``` But keep in mind that if you're doing SSR for your app, this won't work with SSR. In this particular case, better option will be to use the `calc` function along with the `vh` unit for the viewport height (e.g. `calc(100vh * 2)`). ### Evaluators Linaria can use different strategies for evaluating the interpolated values. Currently, we have two built-in strategies: - `extractor` was the default strategy in `1.x` version. It takes an interpolated expression, finds all the referenced identifiers, gets all its declarations, repeats cycle for all identifiers in found declarations, and then constructs a new tree of statements from all found declarations. It's a pretty simple strategy, but it significantly changes an evaluated code and doesn't work for non-primitive js-constructions. - `shaker` was introduced as an option in `1.4` and became the default in `2.0` version. In contrast to `extractor`, `shaker` tries to find all irrelevant code and cuts it out of the file. As a result, interpolated values can be defined without any restrictions. If an interpolated value or one of its dependencies is imported from another module, that module will be also processed with an evaluator (the implementation of evaluator will be chosen by matching `rules` from [the Linaria config](./CONFIGURATION.md#options)). Sometimes it can be useful to implement your own strategy (it can be just a mocked version of some heavy or browser-only library). You can do it by implementing `Evaluator` function: ```typescript type Evaluator = ( filename: string, // the name of processed file options: StrictOptions, // Linaria config text: string, // source code only: string[] | null // list of exported values or `null` for everything ) => [string, Map | null]; ``` The function should return an array with two elements: source code prepared for evaluation and `Map` with imported files in keys and list of the identifiers in values. ## Bundler integration Plugins for bundlers such as webpack and Rollup use the Babel plugin internally and write the CSS text along with the sourcemap to a CSS file. The CSS file is then picked up and processed by the bundler (e.g. - `css-loader` in case of webpack) to generate the final CSS. ================================================ FILE: docs/LINTING.md ================================================ # Linting There are separate installations based on whether you use stylelint v13 or stylelint v14 ## Stylelint 13 For linting styles with [stylelint 13](https://stylelint.io/), use `@linaria/stylelint`. ### Installation Install `stylelint` and optionally your favorite config (such as `stylelint-config-recommended`) in your project: ```bash yarn add --dev stylelint stylelint-config-recommended @linaria/stylelint ``` ### Configuring stylelint All you need to do is to set your config to extend from `@linaria/stylelint`. Here's the example `.stylelintrc` configuration file: ```json { "extends": [ "stylelint-config-recommended", "@linaria/stylelint" ] } ``` Please refer to the [official stylelint documentation](https://stylelint.io/user-guide/configuration/) for more info about configuration. The preprocessor will use the [options from the configuration file](/docs/CONFIGURATION.md) for processing your files. ## Stylelint 14 For linting styles with [stylelint 14](https://stylelint.io/), use `@linaria/stylelint-config-standard-linaria`. ### Installation Install `stylelint` and `@linaria/stylelint-config-standard-linaria` ```bash yarn add --dev stylelint @linaria/stylelint-config-standard-linaria ``` ### Configuring stylelint For the standard configuration you can extend from `@linaria/stylelint-config-standard-linaria`. Here's an example `.stylelintrc` configuration file: ```json { "extends": [ "@linaria/stylelint-config-standard-linaria" ] } ``` `@linaria/stylelint-config-standard-linaria` extends `stylelint-config-standard` which extends `stylelint-config-recommended` so you do NOT need to add those separately. It also sets the customSyntax as `@linaria/postcss-linaria` and adds a few rules. Alternatively, to just use the custom syntax you can add `@linaria/postcss-linaria` Here's an example `.stylelintrc` configuration file: ```json { "customSyntax": "@linaria/postcss-linaria" } ``` Please refer to the [official stylelint documentation](https://stylelint.io/user-guide/configuration/) for more info about configuration. ### Why did the configuration change between Stylelint v13 and v14? Stylelint 14 encourages the use of a [custom syntax](https://stylelint.io/developer-guide/syntaxes/) instead of a processor. `@linaria/stylelint-config-standard-linaria` sets the custom syntax to `@linaria/postcss-linaria`, a custom syntax for linaria, whereas @linaria/stylelint uses a processor. The custom syntax has the benefit of being able to support `stylelint --fix` whereas the processor cannot. ## Usage ### Linting your files Add the following to your `package.json` scripts: ```json "lint:css": "stylelint src/**/*.js" ``` Now, you can run `yarn lint:css` to lint the CSS in your JS files with stylelint. For more information refer to [stylelint documentation](https://stylelint.io/user-guide/cli/). ## Editor Setup In order to make the [vscode-stylelint](https://github.com/stylelint/vscode-stylelint) extension work with this syntax correctly, you must configure it to validate the files you use linaria in by specifying an array of [language identifiers](https://code.visualstudio.com/docs/languages/overview#_changing-the-language-for-the-selected-file). You can do this by following these [instructions](https://github.com/stylelint/vscode-stylelint#stylelintvalidate). For example: ```json { "stylelint.validate": ["typescriptreact"] } ``` ================================================ FILE: docs/MIGRATION_GUIDE.md ================================================ # Migration Guide # 7.x from 6.x ## For Users Linaria 7 updates the WyW toolchain (`@wyw-in-js/*`) to `^1.0.0` (stable). This affects build-time evaluation (CSS extraction) and can surface previously hidden issues in evaluated modules. - Review https://wyw-in-js.dev/stability for the evaluation model, common pitfalls, and performance guidance. - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you rely on WyW cache internals, note that WyW 1.x can promote fully-statically-evaluatable modules to `only: ['*']` and may re-evaluate modules when cached exports are incomplete. - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users on WyW 1.0.6: WyW serializes `transform()` by default; if you hit Rollup "Unexpected early exit" (unresolved plugin promises), try `serializeTransform: false` in the WyW Rollup plugin config. # 6.x from 5.x, 4.x, 3.x ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | --- | --- |@linaria/babel-preset | @wyw-in-js/babel-preset |@linaria/cli | @wyw-in-js/cli |@linaria/esbuild | @wyw-in-js/esbuild |@linaria/rollup | @wyw-in-js/rollup |@linaria/shaker | discontinued |@linaria/vite | @wyw-in-js/vite |@linaria/webpack4-loader | discontinued |@linaria/webpack5-loader | @wyw-in-js/webpack-loader There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). # 4.x, 3.x from 2.x This release was mostly a refactor to [split into more packages](https://github.com/callstack/linaria/pull/687/). ## Breaking changes All these package imports in code need to be updated: | Old | New | --- | --- |linaria | @linaria/core |linaria/loader | @linaria/webpack4-loader, @linaria/webpack5-loader |linaria/react | @linaria/react |linaria/rollup | @linaria/rollup |linaria/server | @linaria/server |linaria/stylelint-config | @linaria/stylelint The `shaker` evaluator has moved from `linaria/evaluators` into its own package. You'll need to add `@linaria/shaker` to your package.json even if you never import it. The Babel preset moved from `linaria/babel` to `@linaria/babel-preset` but has to be referenced as `@linaria` in a Babel config. See https://github.com/callstack/linaria/issues/704 In package.json import all the new packages you use. # 2.x from 1.x ## Breaking changes ### `Core-js` dependency removal and _theoretical_ drop compatibility for `node` below `10` In [#569](https://github.com/callstack/linaria/pull/569) We removed `core-js` dependency. It should not effectively affect your users or build pipelines. But it was technically a breaking change. We set babel preset that makes all non-browser dependencies compatible with `node` from version `10`. But previous setup was using `browser` env so If you was able to build Linaria with previous versions of node, it should work also now. Support for browsers environment didn't change. After that you should be able to solve issues with `core-js` dependency in your project, because it will no longer collide with version used by Linaria. ### The default [evaluation strategy](./HOW_IT_WORKS.md#evaluators) has been changed to `shaker` It should not affect existed code since the new strategy is more powerful, but you can always switch to the old one by adding the next `rules` section to your Linaria-config: ```js [ { action: require('linaria/evaluators').extractor, }, { test: /\/node_modules\//, action: 'ignore', }, ] ``` ================================================ FILE: docs/THEMING.md ================================================ # Theming There are several approaches you can use for theming. Depending on the browser support and requirements, you can pick the approach that suits you the best. ## CSS custom properties CSS custom properties aka CSS variables are one of the best ways to apply a theme to your web app. The basic concept is that we add a class name to represent the theme to our root element, and use different values for our CSS variables based on the theme: ```js // Create class names for different themes const a = css` --color-primary: #6200ee; --color-accent: #03dac4; `; const b = css` --color-primary: #03a9f4; --color-accent: #e91e63; `; // Apply a theme to the root element ; ``` Now, we can use these variables in any of the child elements: ```js const Button = styled.button` background-color: var(--color-accent); `; ``` CSS custom properties are [not supported in some browsers such as IE](http://caniuse.com/#feat=css-variables), so if you need to support those browsers, this is not a viable approach. ## Class names Another approach is to add a class name representing the theme (e.g. - `theme-dark`) in the root element, and take advantage of CSS child selectors to theme the elements based on this parent class name. For example, let's add the theme to the root component: ```js ``` Now, we can conditionally style any child element according to the theme: ```js const Header = styled.h1` text-transform: uppercase; .theme-dark & { color: white; } .theme-light & { color: black; } `; ``` You could even make some helpers to make writing this easier: ```js // Put your colors in an object grouped by the theme names const colors = { light: { text: 'black', }, dark: { text: 'white', }, }; // Create a small helper function to loop over the themes and create CSS rule sets const theming = cb => Object.keys(colors).reduce((acc, name) => Object.assign(acc, { [`.theme-${name} &`]: cb(colors[name]), }), {}); // Use the helper in your styles const Header = styled.h1` text-transform: uppercase; ${theming(c => ({ color: c.text, }))}; `; ``` This approach works in all browsers, and is the best approach if you want to support older browsers without support for CSS custom properties. ## React Context Another approach is to use React Context to pass down colors, and then use function interpolations with the `styled` tag to use the colors in your component. You could use something like [`@callstack/react-theme-provider`](https://github.com/callstack/react-theme-provider) or write your own HOC. Then use it like: ```js const Button = withTheme(styled.button` background-color: ${props => props.theme.accent}; `); ``` Note that this approach also uses CSS custom properties under the hood since function interpolations compile down to CSS custom properties. So the browser support is limited. ================================================ FILE: examples/astro-solid/astro.config.js ================================================ import { defineConfig } from 'astro/config'; import astro_solid from '@astrojs/solid-js'; import vite_wyw from '@wyw-in-js/vite'; import vite_inspect from 'vite-plugin-inspect'; export default defineConfig({ output: 'static', srcDir: '.', root: '.', integrations: [astro_solid()], server: { host: '0.0.0.0', port: 3000, }, build: { format: 'file', }, vite: { plugins: [ vite_wyw({ displayName: true, classNameSlug: (hash, title, args) => `${args.dir}_${title}_${hash}`, babelOptions: { presets: ['solid'], }, }), vite_inspect(), ], css: { modules: false, }, }, }); ================================================ FILE: examples/astro-solid/package.json ================================================ { "name": "astro-solid-example", "version": "0.0.1", "license": "MIT", "main": "index.js", "type": "module", "devDependencies": { "@astrojs/solid-js": "^1.2.3", "@babel/core": "^7.23.5", "@linaria/core": "workspace:^", "@wyw-in-js/vite": "^1.0.6", "astro": "^1.6.10", "solid-js": "^1.6.2", "vite": "^3", "vite-plugin-inspect": "^0.7.33" }, "scripts": { "dev": "astro dev --force", "build": "astro build" }, "author": "Dmitriy Nikiforov" } ================================================ FILE: examples/astro-solid/pages/csr.tsx ================================================ import { css } from '@linaria/core'; import { CSRChild, cssVariableFromModule } from './csr_child'; import { astroTextColor } from './external'; // Try to change some variables white in dev mode const GLOBAL_VARS = { color_header: 'red', } as const; export default function CSRComponent() { const LOCAL_VARS = { description_font_style: 'bold', } as const; return (

Hello! This is{' '} Solid {' '} app built with{' '} Linaria {' '} powered by
Astro

This component was rendered on client.
); } ================================================ FILE: examples/astro-solid/pages/csr_child.tsx ================================================ import { css } from '@linaria/core'; import { astroTextColor } from './external'; export function CSRChild() { return (
I am child module!
); } // Try to change some variables white in dev mode export const cssVariableFromModule = '64px'; ================================================ FILE: examples/astro-solid/pages/external.ts ================================================ export const astroTextColor = 'orange'; ================================================ FILE: examples/astro-solid/pages/index.astro ================================================ --- import CSRComponent from './csr'; --- Linaria – zero-runtime CSS in JS library ================================================ FILE: examples/astro-solid/tsconfig.json ================================================ { "compilerOptions": { "baseUrl": ".", "module": "ESNext", "target": "ESNext", "jsx": "preserve", "jsxImportSource": "solid-js", "moduleResolution": "Node" }, "exclude": ["node_modules"] } ================================================ FILE: examples/esbuild/.gitignore ================================================ /build ================================================ FILE: examples/esbuild/app.js ================================================ import 'linaria-website'; ================================================ FILE: examples/esbuild/build.js ================================================ const wyw = require('@wyw-in-js/esbuild').default; const prod = process.env.NODE_ENV === 'production'; require('esbuild') .build({ bundle: true, entryPoints: ['app.js'], loader: { '.svg': 'file', '.png': 'file', }, minify: prod, outfile: 'build/out.js', plugins: [ wyw({ sourceMap: prod, }), ], }) .catch(() => process.exit(1)); ================================================ FILE: examples/esbuild/package.json ================================================ { "private": true, "name": "esbuild-example", "version": "0.0.0", "license": "MIT", "dependencies": { "linaria-website": "workspace:^" }, "devDependencies": { "@wyw-in-js/esbuild": "^1.0.6", "esbuild": "^0.15.16" }, "scripts": { "build": "node build.js" }, "author": "Anton Evzhakov" } ================================================ FILE: examples/rollup/.gitignore ================================================ /build ================================================ FILE: examples/rollup/app.js ================================================ import 'linaria-website'; ================================================ FILE: examples/rollup/babel.config.js ================================================ module.exports = { presets: ['@babel/preset-react'], }; ================================================ FILE: examples/rollup/package.json ================================================ { "private": true, "name": "rollup-example", "version": "0.0.0", "license": "MIT", "dependencies": { "linaria-website": "workspace:^" }, "devDependencies": { "@babel/core": "^7.23.5", "@babel/preset-react": "^7.23.3", "@rollup/plugin-babel": "^6.0.3", "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-image": "^3.0.2", "@rollup/plugin-node-resolve": "^15.2.1", "@wyw-in-js/rollup": "^1.0.6", "rollup": "^4.0.0", "rollup-plugin-css-only": "^4.3.0" }, "scripts": { "build": "rollup -c" }, "author": "Anton Evzhakov" } ================================================ FILE: examples/rollup/rollup.config.mjs ================================================ import wyw from '@wyw-in-js/rollup'; import { babel } from '@rollup/plugin-babel'; import commonjs from '@rollup/plugin-commonjs'; import image from '@rollup/plugin-image'; import { nodeResolve } from '@rollup/plugin-node-resolve'; import css from 'rollup-plugin-css-only'; export default { input: 'app.js', output: { dir: 'build', format: 'cjs', }, plugins: [ image(), wyw({ sourceMap: process.env.NODE_ENV !== 'production', // Rollup can deadlock when WyW resolves imports during transform. serializeTransform: false, }), css({ output: 'styles.css', }), nodeResolve({ extensions: ['.jsx', '.js'], }), commonjs(), babel({ babelHelpers: 'bundled' }), ], }; ================================================ FILE: examples/vite/.linariarc.mjs ================================================ module.exports = { rules: [ { action: require.resolve('@linaria/shaker'), }, { test: /\/node_modules\//, action: 'ignore', }, { test: (filename, code) => { if (!/\/node_modules\//.test(filename)) { return false; } return /(?:^|\*\/|;|})\s*(?:export|import)\s/m.test(code); }, action: require.resolve('@linaria/shaker'), }, ], }; ================================================ FILE: examples/vite/app.js ================================================ import 'linaria-website'; ================================================ FILE: examples/vite/index.html ================================================ Linaria – zero-runtime CSS in JS library
================================================ FILE: examples/vite/package.json ================================================ { "private": true, "name": "vite-example", "version": "0.0.0", "license": "MIT", "main": "index.js", "type": "module", "dependencies": { "linaria-website": "workspace:^" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", "@vitejs/plugin-react": "^2.1.0", "@wyw-in-js/vite": "^1.0.6", "vite": "^3.2.10" }, "scripts": { "build": "vite build" }, "author": "Anton Evzhakov" } ================================================ FILE: examples/vite/vite.config.js ================================================ import wyw from '@wyw-in-js/vite'; import { nodeResolve } from '@rollup/plugin-node-resolve'; import react from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; // https://vitejs.dev/config/ export default defineConfig(({ command }) => ({ plugins: [ nodeResolve({ extensions: ['.jsx', '.js'], }), wyw({ include: ['**/*.{js,jsx}'], babelOptions: { presets: ['@babel/preset-react'], }, }), react({ jsxRuntime: 'classic', }), ], build: { target: command === 'serve' ? 'modules' : 'es2015', }, })); ================================================ FILE: examples/vpssr-linaria-solid/package.json ================================================ { "name": "vpssr-linaria-solid-example", "version": "1.0.0", "private": true, "scripts": { "dev": "node ./server", "build": "vite build", "preview": "vite build && NODE_ENV=production node ./server" }, "author": "mrfoxpro", "license": "ISC", "dependencies": { "@linaria/core": "workspace:^", "@wyw-in-js/vite": "^1.0.6", "babel-preset-solid": "^1.6.2", "compression": "^1.7.4", "express": "^4.20.0", "sirv": "^2.0.2", "solid-js": "^1.6.2", "vite": "^3.2.10", "vite-plugin-solid": "^2.4.0", "vite-plugin-ssr": "^0.4.54" } } ================================================ FILE: examples/vpssr-linaria-solid/pages/html-js/_default.page.client.js ================================================ // We could also define `handleCounter()` in `index.page.client.js` instead of `_default.page.client.js`. // We define `_default.page.client.js` to showcase how to define the browser-side JavaScript for multiple pages. handleCounter() function handleCounter() { const counterEl = document.querySelector('button') let countState = 0 const txt = () => `Counter ${countState} (Vanilla JS)` counterEl.textContent = txt() counterEl.onclick = () => { countState++ counterEl.textContent = txt() } } ================================================ FILE: examples/vpssr-linaria-solid/pages/html-js/index.page.server.tsx ================================================ import { css } from '@linaria/core' export function Page() { return ( <>

HTML + JS

This page is rendered to HTML and has only few lines of browser-side JavaScript.

HMR works for CSS: modify pages/html-js/index.css to change the color of this{' '} red text .

) } ================================================ FILE: examples/vpssr-linaria-solid/pages/html-only/index.page.server.tsx ================================================ import { css } from '@linaria/core' export function Page() { return ( <>

HTML-only

The React component Page of this page is rendererd to HTML only.

This page has zero browser-side JavaScript. (In development, Vite's HMR client is loaded.)

As shown by this{' '} orange text , CSS can be loaded in .page.server.js files.

If needed, we can add a little bit of browser-side JavaScipt to implement bits of interactivity, see HTML + JS.

) } ================================================ FILE: examples/vpssr-linaria-solid/pages/index.page.server.tsx ================================================ export function Page() { return ( <>

Render Modes

  • HTML only. Rendered to HTML, zero browser-side JavaScript.
  • SPA. Rendered to the browser's DOM (not rendered to HTML).
  • HTML + JS. Rendered to HTML, some browser-side JavaScript.
  • SSR. Rendered to HTML and hydrated in the browser.
) } ================================================ FILE: examples/vpssr-linaria-solid/pages/spa/index.page.client.tsx ================================================ import { Counter } from '../ssr/Counter' import { css } from '@linaria/core' export function Page() { return ( <>

SPA

This page is:

  • Rendered only to the browser's DOM. (Not rendered to HTML.)
  • Interactive.

Green text.

) } ================================================ FILE: examples/vpssr-linaria-solid/pages/ssr/Counter.tsx ================================================ import { createSignal } from 'solid-js' export function Counter() { const [count, setCount] = createSignal(0) return ( ) } ================================================ FILE: examples/vpssr-linaria-solid/pages/ssr/index.page.tsx ================================================ import { Counter } from './Counter' import { css } from '@linaria/core' export function Page() { return ( <>

SSR

This page is:

  • Rendered to HTML and hydrated in the browser.
  • Interactive.

Blue text.

) } export const hydrate = true ================================================ FILE: examples/vpssr-linaria-solid/renderer/_default.page.client.tsx ================================================ import { render as solidRender, hydrate as solidHydrate } from 'solid-js/web' import type { PageContextBuiltInClient } from 'vite-plugin-ssr/client' // When using Client Routing export async function render(pageContext: PageContextBuiltInClient) { const { Page, exports, isHydration } = pageContext if ('hydrate' in exports && isHydration) { console.log('hydrating') solidHydrate(() => , document.body) return } solidRender(() => , document.body) } export const clientRouting = true ================================================ FILE: examples/vpssr-linaria-solid/renderer/_default.page.server.tsx ================================================ import { generateHydrationScript, renderToStream } from 'solid-js/web' import { escapeInject, stampPipe, dangerouslySkipEscape } from 'vite-plugin-ssr' import type { PageContextBuiltInClient } from 'vite-plugin-ssr/client' // When using Client Routing export function render(pageContext: PageContextBuiltInClient) { if (pageContext.Page) { const { Page } = pageContext const { pipe } = renderToStream(() => ) stampPipe(pipe, 'node-stream') return escapeInject` ${dangerouslySkipEscape(generateHydrationScript())} ${pipe} ` } return escapeInject` ` } ================================================ FILE: examples/vpssr-linaria-solid/server.js ================================================ const express = require("express"); const compression = require("compression"); const { renderPage } = require("vite-plugin-ssr"); const isProduction = process.env.NODE_ENV === "production"; const app = express(); app.use(compression()); async function main () { if (isProduction) { const sirv = require("sirv") app.use(sirv(`${__dirname}/dist/client`)); } else { const vite = require("vite"); const server = await vite.createServer({ root: __dirname, configFile: './vite.config.js', server: { middlewareMode: true }, }) app.use(server.middlewares); } app.get("*", async (req, res, next) => { const pageContextInit = { urlOriginal: req.originalUrl, }; const pageContext = await renderPage(pageContextInit); const { httpResponse } = pageContext; if (!httpResponse) return next(); const { statusCode, contentType, earlyHints } = httpResponse; if (res.writeEarlyHints) res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) }); res.status(statusCode).type(contentType); httpResponse.pipe(res); }); const port = process.env.PORT || 3000; app.listen(port); console.log(`Server running at http://localhost:${port}`); } main() ================================================ FILE: examples/vpssr-linaria-solid/tsconfig.json ================================================ { "compilerOptions": { "baseUrl": ".", "target": "ESNext", "module": "ESNext", "jsx": "preserve", "noEmit": true, "allowSyntheticDefaultImports": true, "moduleResolution": "node", // Misc "esModuleInterop": true, "types": [ "vite/client" ], "skipDefaultLibCheck": true, "skipLibCheck": true, }, "exclude": ["node_modules"] } ================================================ FILE: examples/vpssr-linaria-solid/vite.config.js ================================================ import vite_ssr from 'vite-plugin-ssr/plugin'; import vite_wyw from '@wyw-in-js/vite'; import vite_solid from 'vite-plugin-solid'; export default (/** @type import('vite').ConfigEnv */ { mode }) => { const dev = mode === 'development'; /** @type import('vite').UserConfig */ const config = { plugins: [ { ...vite_wyw({ babelOptions: { presets: [ 'solid', [ '@babel/preset-typescript', { isTSX: true, allExtensions: true, }, ], ], }, }), enforce: 'pre', }, vite_solid({ dev: dev, hot: dev, ssr: true, }), vite_ssr({ includeAssetsImportedByServer: true, prerender: { partial: true, noExtraDir: true, }, }), ], }; return config; }; ================================================ FILE: examples/webpack5/app.js ================================================ import 'linaria-website'; ================================================ FILE: examples/webpack5/babel.config.js ================================================ module.exports = { presets: ['@babel/preset-react'], }; ================================================ FILE: examples/webpack5/package.json ================================================ { "private": true, "name": "webpack5-example", "version": "0.0.0", "license": "MIT", "main": "index.js", "dependencies": { "linaria-website": "workspace:^" }, "devDependencies": { "@babel/core": "^7.23.5", "@wyw-in-js/webpack-loader": "^1.0.6", "babel-loader": "^9.1.0", "cross-env": "^7.0.3", "css-hot-loader": "^1.4.4", "css-loader": "^6.7.2", "file-loader": "^6.2.0", "mini-css-extract-plugin": "^2.7.0", "webpack": "^5.94.0", "webpack-cli": "^5.0.0" }, "scripts": { "build": "cross-env NODE_ENV=production webpack", "preview": "pnpm build && pnpm dlx http-server ." }, "author": "Anton Evzhakov" } ================================================ FILE: examples/webpack5/webpack.config.js ================================================ const path = require('path'); const webpack = require('webpack'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const dev = process.env.NODE_ENV !== 'production'; module.exports = { mode: dev ? 'development' : 'production', devtool: 'source-map', entry: { app: './app', }, output: { path: path.resolve('./dist'), filename: 'app.bundle.js', }, optimization: { noEmitOnErrors: true, }, plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV) }, }), new MiniCssExtractPlugin({ filename: 'styles.css' }), ], resolve: { extensions: ['.js', '.jsx', '.mjs'], }, module: { rules: [ { test: /\.mjs$/, type: 'javascript/auto', }, { test: /\.jsx?$/, exclude: /node_modules/, use: [ { loader: 'babel-loader' }, { loader: '@wyw-in-js/webpack-loader', options: { sourceMap: dev }, }, ], }, { test: /\.css$/, use: [ 'css-hot-loader', MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { sourceMap: dev }, }, ], }, { test: /\.(png|jpg|gif|svg)$/, use: [ { loader: 'file-loader', options: { esModule: false, }, }, ], }, ], }, }; ================================================ FILE: greenkeeper.json ================================================ { "groups": { "default": { "packages": [ "package.json", "website/package.json" ] } } } ================================================ FILE: jest.config.js ================================================ module.exports = { testEnvironment: 'node', collectCoverageFrom: ['src/*.ts'], transformIgnorePatterns: ['node_modules/(?!@linaria)'], testPathIgnorePatterns: ['/__utils__/'], }; ================================================ FILE: link-wyw.sh ================================================ #!/bin/bash # Find package.json files in the current folder (excluding node_modules) package_json_files=$(find . -name "package.json" ! -path "*/node_modules/*") # Loop through each package.json file found for package_json_file in $package_json_files; do # Get the directory path of the package.json file package_dir=$(dirname "$package_json_file") # Get all @linaria/* dependencies linaria_dependencies=$(cat "$package_json_file" | jq -r '(.dependencies + .devDependencies) | with_entries(select(.key | startswith("@wyw-in-js"))) | keys[]' 2>/dev/null) # Link @linaria dependencies if [[ $linaria_dependencies != "null" ]]; then for dep in $linaria_dependencies; do echo "Running pnpm link --global $dep in $package_dir" (cd "$package_dir" && pnpm link --global $dep) done fi done ================================================ FILE: package.json ================================================ { "name": "umbrella", "version": "3.0.0-beta.19", "private": true, "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "workspaces": [ "./packages/*", "./website" ], "scripts": { "add-contributor": "all-contributors add", "bootstrap": "pnpm install", "check:all": "turbo run check:all --output-logs=new-only && pnpm lint && pnpm sp:check", "clean": "del 'packages/*/{coverage,dist,esm,lib,types,tsconfig.tsbuildinfo}'", "lint": "eslint --ext .js,.ts,.tsx .", "prepare": "turbo run build --output-logs=new-only", "release": "pnpm run prepare && pnpm changeset publish", "sp:check": "syncpack", "sp:fix": "syncpack format && syncpack fix-mismatches", "sp:format": "syncpack format", "sp:list": "syncpack list-mismatches", "test": "turbo run test", "test:coverage": "turbo run test -- -- --coverage", "test:dts": "turbo run test:dts", "typecheck": "turbo run typecheck", "website": "pnpm --filter=linaria-website" }, "husky": { "hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", "pre-commit": "pnpm check:all" } }, "resolutions": { "@typescript-eslint/experimental-utils": "^4.28.0", "git-raw-commits": "^2.0.3" }, "dependencies": {}, "devDependencies": { "@babel/cli": "^7.23.4", "@babel/core": "^7.23.5", "@babel/eslint-parser": "^7.23.3", "@babel/plugin-proposal-explicit-resource-management": "^7.23.3", "@babel/plugin-syntax-jsx": "^7.23.3", "@babel/preset-env": "^7.23.5", "@babel/preset-react": "^7.23.3", "@babel/preset-typescript": "^7.23.3", "@changesets/cli": "^2.22.0", "@commitlint/config-conventional": "^8.3.4", "@definitelytyped/dtslint": "^0.0.176", "@types/jest": "^28.1.0", "@types/node": "^17.0.39", "@types/resolve": "^1.20.6", "@typescript-eslint/eslint-plugin": "^6.6.0", "@typescript-eslint/parser": "^6.6.0", "all-contributors-cli": "^6.20.0", "babel-jest": "^29.6.2", "codecov": "^3.2.0", "commitlint": "^8.3.5", "cross-env": "^7.0.3", "del-cli": "^1.1.0", "eslint": "^8.48.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-import": "^2.28.1", "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "git-raw-commits": "^2.0.3", "husky": "^1.3.1", "jest": "^29.6.2", "prettier": "^3.0.3", "react": "^16.14.0", "syncpack": "^11.2.1", "tsup": "^7.2.0", "turbo": "^1.10.13", "typescript": "^5.2.2" }, "engines": { "node": ">=20.0.0", "pnpm": "^9.0.0" }, "packageManager": "pnpm@9.15.9+sha256.cf86a7ad764406395d4286a6d09d730711720acc6d93e9dce9ac7ac4dc4a28a7" } ================================================ FILE: packages/atomic/CHANGELOG.md ================================================ # Change Log ## 7.0.1 ### Patch Changes - Updated dependencies [b3331e45] - @linaria/react@7.0.1 ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ### Patch Changes - Updated dependencies [ab11ebb7] - Updated dependencies [654d8590] - @linaria/core@7.0.0 - @linaria/react@7.0.0 ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ### Patch Changes - Updated dependencies [bd8d45fd] - Updated dependencies [281ca4f5] - @linaria/react@6.3.0 - @linaria/core@6.3.0 ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ### Patch Changes - Updated dependencies [a3dcee2e] - @linaria/core@6.2.0 - @linaria/react@6.2.1 ## 6.1.1 ### Patch Changes - Updated dependencies [fd60b5de] - @linaria/react@6.2.0 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ### Patch Changes - 8d4ebd33: chore: bump @wyw-in-js/\* packages - Updated dependencies [8d4ebd33] - Updated dependencies [8ba655d3] - @linaria/core@6.1.0 - @linaria/react@6.1.0 ## 6.0.0 ### Major Changes - 60e6b7e2: Stylis has been upgraded from v3 to v4. - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ### Patch Changes - Updated dependencies [2ac94b99] - @linaria/core@6.0.0 - @linaria/react@6.0.0 ## 5.0.3 ### Patch Changes - Updated dependencies [4b083b7c] - @linaria/react@5.0.3 ## 5.0.2 ### Patch Changes - Updated dependencies [1e889937] - Updated dependencies [4992c14d] - Updated dependencies [70000ec8] - Updated dependencies [1e889937] - Updated dependencies [5a32f4fd] - Updated dependencies [727dc2bd] - Updated dependencies [25ba1344] - Updated dependencies [5a32f4fd] - @linaria/react@5.0.2 - @linaria/utils@5.0.2 - @linaria/tags@5.0.2 - @linaria/core@5.0.2 ## 5.0.1 ### Patch Changes - Updated dependencies [6fb6eb69] - @linaria/utils@5.0.1 - @linaria/core@5.0.1 - @linaria/react@5.0.1 - @linaria/tags@5.0.1 ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 - Updated dependencies [9cb4143d] - Updated dependencies [ae162f46] - Updated dependencies [88e07613] - Updated dependencies [b3ef8c1f] - Updated dependencies [f8b9bff5] - Updated dependencies [63902332] - Updated dependencies [aa100453] - Updated dependencies [9bb782d0] - Updated dependencies [2a1e24a0] - Updated dependencies [16320d71] - Updated dependencies [cb853e14] - @linaria/core@5.0.0 - @linaria/logger@5.0.0 - @linaria/react@5.0.0 - @linaria/tags@5.0.0 - @linaria/utils@5.0.0 ## 4.5.4 ### Patch Changes - Updated dependencies [10bcd241] - @linaria/utils@4.5.3 - @linaria/core@4.5.4 - @linaria/react@4.5.4 - @linaria/tags@4.5.4 ## 4.5.3 ### Patch Changes - 79557248: Nothing has changed. Just moved some utils and types from babel to utils package. - e59bf809: Shaker mistakenly counts references in types as valuable and keeps referenced variables alive. - Updated dependencies [79557248] - Updated dependencies [b191f543] - Updated dependencies [e59bf809] - Updated dependencies [520ba8da] - Updated dependencies [ae3727f9] - Updated dependencies [dca076ef] - @linaria/core@4.5.3 - @linaria/react@4.5.3 - @linaria/tags@4.5.3 - @linaria/utils@4.5.2 ## 4.5.2 ### Patch Changes - Updated dependencies [85e74df6] - Updated dependencies [1bf5c5b8] - @linaria/utils@4.5.1 - @linaria/core@4.5.2 - @linaria/react@4.5.2 - @linaria/tags@4.5.2 ## 4.5.1 ### Patch Changes - Updated dependencies [ceca1611] - Updated dependencies [13258306] - @linaria/react@4.5.1 - @linaria/tags@4.5.1 - @linaria/core@4.5.1 ## 4.5.0 ### Minor Changes - 16c057df: Breaking Change: Performance Optimization for `styled` When a component is wrapped in `styled`, Linaria needs to determine if that component is already a styled component. To accomplish this, the wrapped component is included in the list of variables for evaluation, along with the interpolated values used in styles. The issue arises when a wrapped component, even if it is not styled, brings along a substantial dependency tree. This situation is particularly evident when using `styled` to style components from third-party UI libraries. To address this problem, Linaria will now examine the import location of the component and check if there is an annotation in the `package.json` file of the package containing the components. This annotation indicates whether the package includes other Linaria components. If there is no such annotation, Linaria will refrain from evaluating the component. Please note that this Breaking Change solely affects developers of component libraries. In order for users to style components from your library, you must include the `linaria.components` property in the library's `package.json` file. This property should have a mask that covers all imported files with components. Here's an example of how to specify it: ```json "linaria": { "components": "**/*" } ``` ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. - Updated dependencies [890b4aca] - Updated dependencies [05ad266c] - Updated dependencies [16c057df] - Updated dependencies [af5bb92d] - Updated dependencies [10859924] - @linaria/utils@4.5.0 - @linaria/react@4.5.0 - @linaria/tags@4.5.0 - @linaria/core@4.5.0 - @linaria/logger@4.5.0 ## 4.2.10 ### Patch Changes - Updated dependencies [54ab61b2] - @linaria/react@4.3.8 - @linaria/tags@4.3.5 - @linaria/utils@4.3.4 - @linaria/core@4.2.10 ## 4.2.9 ### Patch Changes - 34029088: Usages of `styled` and `css` in Jest no longer trigger the "Using the … tag in runtime is not supported" exception. - Updated dependencies [2e966f23] - Updated dependencies [1c3f309d] - Updated dependencies [dbe250b5] - Updated dependencies [34029088] - @linaria/tags@4.3.4 - @linaria/react@4.3.7 - @linaria/utils@4.3.3 - @linaria/core@4.2.9 ## 4.2.8 ### Patch Changes - Updated dependencies [a3ad617f] - @linaria/react@4.3.6 - @linaria/tags@4.3.3 - @linaria/core@4.2.8 ## 4.2.7 ### Patch Changes - a2b618bc: add react as an optional peerDependency due to dependency on @atomic/react - Updated dependencies [f9df4ed8] - @linaria/utils@4.3.2 - @linaria/core@4.2.7 - @linaria/react@4.3.5 - @linaria/tags@4.3.2 ## 4.2.6 ### Patch Changes - Updated dependencies [28f3f93d] - Updated dependencies [71a5b351] - Updated dependencies [61d49a39] - @linaria/tags@4.3.1 - @linaria/utils@4.3.1 - @linaria/core@4.2.6 - @linaria/react@4.3.4 ## 4.2.5 ### Patch Changes - 61fe2560: Do not crash when no styles are extracted. - Updated dependencies [3ce985e0] - Updated dependencies [d11174d0] - @linaria/tags@4.3.0 - @linaria/utils@4.3.0 - @linaria/core@4.2.5 - @linaria/react@4.3.3 ## 4.2.4 ### Patch Changes - Updated dependencies [315f0366] - @linaria/utils@4.2.6 - @linaria/core@4.2.4 - @linaria/react@4.3.2 - @linaria/tags@4.2.2 ## 4.2.3 ### Patch Changes - 5edde648: Upgrade Babel to support TypeScript 4.9. Fixes #1133. - Updated dependencies [922f20d6] - Updated dependencies [5edde648] - Updated dependencies [b9e49b74] - @linaria/react@4.3.1 - @linaria/core@4.2.3 - @linaria/tags@4.2.1 - @linaria/utils@4.2.5 ## 4.2.2 ### Patch Changes - Updated dependencies [63f56d47] - Updated dependencies [963508a2] - Updated dependencies [c26d4667] - @linaria/react@4.3.0 - @linaria/tags@4.2.0 - @linaria/utils@4.2.4 - @linaria/core@4.2.2 ## 4.2.1 ### Patch Changes - Updated dependencies [cc2f87a8] - Updated dependencies [6de22792] - @linaria/utils@4.2.3 - @linaria/react@4.2.1 - @linaria/core@4.2.1 - @linaria/tags@4.1.5 ## 4.2.0 ### Minor Changes - 1e88e95d: Support for ECMAScript modules. Fixes #904 and #1043. ### Patch Changes - Updated dependencies [1e88e95d] - @linaria/core@4.2.0 - @linaria/react@4.2.0 ## 4.1.5 ### Patch Changes - 87ffe61c: The new `variableNameSlug` option that allows to customize css variable names (closes #1053). - Updated dependencies [8a8be242] - Updated dependencies [8a8be242] - Updated dependencies [08304e09] - Updated dependencies [87ffe61c] - @linaria/utils@4.2.2 - @linaria/core@4.1.4 - @linaria/react@4.1.5 - @linaria/tags@4.1.4 ## 4.1.4 ### Patch Changes - Updated dependencies [24b4a4bd] - @linaria/utils@4.2.1 - @linaria/core@4.1.3 - @linaria/tags@4.1.3 - @linaria/react@4.1.4 ## 4.1.3 ### Patch Changes - Updated dependencies [8590e134] - Updated dependencies [f7351b09] - Updated dependencies [c0bd271a] - Updated dependencies [8f90fa75] - Updated dependencies [ac0991a6] - @linaria/utils@4.2.0 - @linaria/react@4.1.3 - @linaria/tags@4.1.2 - @linaria/core@4.1.2 ## 4.1.2 ### Patch Changes - Updated dependencies [50bc0c79] - @linaria/utils@4.1.1 - @linaria/core@4.1.1 - @linaria/tags@4.1.1 - @linaria/react@4.1.2 ## 4.1.1 ### Patch Changes - Updated dependencies [2abc55b3] - @linaria/react@4.1.1 ## 4.1.0 ### Patch Changes - Updated dependencies [92f6d871] - @linaria/utils@4.1.0 - @linaria/core@4.1.0 - @linaria/tags@4.1.0 - @linaria/react@4.1.0 ## 4.0.0 ### Major Changes - bc0cbeea: A completely new async mode with native support for Vite, Rollup, esbuild and Webpack resolvers. BREAKING CHANGES: Despite the fact, that it should be fully compatible with 3.0 and 2.0 branches, the new version of styles evaluator can have some serious bugs which can make your project unbuildable (however, since there is no runtime, if the build is finished successfully, everything will continue work as it was on 2.0 and 3.0). If you face some problems please let us know and we will fix it as soon as possible. ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - ea41d440: New package @linaria/tags that contains all abstract logic for tags processors. - 9a50c1c1: Linaria now removes all unused css-related code from the runtime. - 12d35cb9: `processors` aliases have been lost during publishing. (fixes #984) - 17c83e34: Aliases for environments without the support of `exports` in package.json. - Updated dependencies [f0cddda4] - @linaria/core@4.0.0 - @linaria/logger@4.0.0 - @linaria/react@4.0.0 - @linaria/utils@4.0.0 - @linaria/tags@4.0.0 ## 3.0.0-beta.21 ### Patch Changes - 17c83e34: Aliases for environments without the support of `exports` in package.json. - Updated dependencies [17c83e34] - @linaria/react@3.0.0-beta.21 - @linaria/core@3.0.0-beta.21 ## 3.0.0-beta.20 ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - Updated dependencies - @linaria/core@3.0.0-beta.20 - @linaria/logger@3.0.0-beta.20 - @linaria/react@3.0.0-beta.20 - @linaria/utils@3.0.0-beta.20 # [3.0.0-beta.19](https://github.com/callstack/linaria/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2022-06-03) ### Features - **atomic:** add support for atomic using styled API ([#966](https://github.com/callstack/linaria/issues/966)) ([f59860b](https://github.com/callstack/linaria/commit/f59860b09c5f91b0423dbf188e5f8aaaef38a6b5)) - **babel:** api for custom tags ([#976](https://github.com/callstack/linaria/issues/976)) ([3285ccc](https://github.com/callstack/linaria/commit/3285ccc1d00449b78b3fc74087528cd38cbdd116)) - **babel:** new way for detecting tag imports ([#974](https://github.com/callstack/linaria/issues/974)) ([3305cfb](https://github.com/callstack/linaria/commit/3305cfb0c0f65abdacceeb7e6bad118c59f7d551)) # [3.0.0-beta.18](https://github.com/callstack/linaria/compare/v3.0.0-beta.17...v3.0.0-beta.18) (2022-04-01) ### Features - **atomic:** add property priorities ([#950](https://github.com/callstack/linaria/issues/950)) ([c44becb](https://github.com/callstack/linaria/commit/c44becb11b2eec795b68c2b3d0715672ba4b3888)) - **atomic:** add support for at-rules, keyframes and pseudo classes ([#913](https://github.com/callstack/linaria/issues/913)) ([dee7fa1](https://github.com/callstack/linaria/commit/dee7fa14ea912224cac9f0673be7464e93571a73)) - **atomic:** string serialization of atoms ([#934](https://github.com/callstack/linaria/issues/934)) ([ef19ccb](https://github.com/callstack/linaria/commit/ef19ccb384cb7dbee561e789f637b0289d4d224c)) # [3.0.0-beta.15](https://github.com/callstack/linaria/compare/v3.0.0-beta.14...v3.0.0-beta.15) (2021-11-29) ### Features - **atomic:** create an atomic package for the css API ([#867](https://github.com/callstack/linaria/issues/867)) ([4773bcf](https://github.com/callstack/linaria/commit/4773bcf4b14f08cdc4d2b612654b962cdfc97eaa)) ================================================ FILE: packages/atomic/README.md ================================================

Linaria

Zero-runtime CSS in JS library.

--- ### 📖 Please refer to the [GitHub](https://github.com/callstack/linaria#readme) for full documentation. ## Features - Write CSS in JS, but with **zero runtime**, CSS is extracted to CSS files during build - Familiar **CSS syntax** with Sass like nesting - Use **dynamic prop based styles** with the React bindings, uses CSS variables behind the scenes - Easily find where the style was defined with **CSS sourcemaps** - **Lint your CSS** in JS with [stylelint](https://github.com/stylelint/stylelint) - Use **JavaScript for logic**, no CSS preprocessor needed - Optionally use any **CSS preprocessor** such as Sass or PostCSS **[Why use Linaria](../../docs/BENEFITS.md)** ## Installation ```sh npm install @linaria/core @linaria/react @linaria/babel-preset ``` or ```sh yarn add @linaria/core @linaria/react @linaria/babel-preset ``` ================================================ FILE: packages/atomic/babel.config.js ================================================ const config = require('../../babel.config'); module.exports = config; ================================================ FILE: packages/atomic/package.json ================================================ { "name": "@linaria/atomic", "version": "7.0.1", "description": "Blazing fast zero-runtime CSS in JS library", "keywords": [ "css", "css-in-js", "linaria", "react", "styled-components" ], "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "sideEffects": false, "exports": { "./package.json": "./package.json", ".": { "types": "./types/index.d.ts", "import": "./dist/index.mjs", "default": "./dist/index.js" }, "./*": { "types": "./types/*.d.ts", "import": "./dist/*.mjs", "default": "./dist/*.js" } }, "main": "dist/index.js", "module": "dist/index.mjs", "types": "types/index.d.ts", "files": [ "dist/", "processors/", "types/" ], "wyw-in-js": { "tags": { "css": "./dist/processors/css.js", "styled": "./dist/processors/styled.js" } }, "scripts": { "build": "pnpm build:dist && pnpm build:declarations", "build:declarations": "tsc --emitDeclarationOnly --outDir types", "build:dist": "tsup --format cjs,esm", "typecheck": "tsc --noEmit --composite false", "watch": "pnpm build:dist --watch & pnpm build:declarations --watch" }, "dependencies": { "@linaria/core": "workspace:^", "@linaria/react": "workspace:^", "@wyw-in-js/processor-utils": "^1.0.4", "@wyw-in-js/shared": "^1.0.4", "known-css-properties": "^0.24.0", "postcss": "^8.4.31", "stylis": "^4.3.0", "ts-invariant": "^0.10.3" }, "devDependencies": { "@babel/types": "^7.23.5", "@types/node": "^17.0.39", "@types/stylis": "^4.2.1" }, "peerDependencies": { "react": ">=16" }, "peerDependenciesMeta": { "react": { "optional": true } }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" }, "tsup": { "entry": [ "src/index.ts", "src/processors/css.ts", "src/processors/styled.ts" ], "splitting": false, "sourcemap": true, "clean": true } } ================================================ FILE: packages/atomic/processors/css.js ================================================ Object.defineProperty(exports, '__esModule', { value: true, }); exports.default = require('../dist/processors/css').default; ================================================ FILE: packages/atomic/processors/styled.js ================================================ Object.defineProperty(exports, '__esModule', { value: true, }); exports.default = require('../dist/processors/styled').default; ================================================ FILE: packages/atomic/src/CSSProperties.ts ================================================ export type CSSProperties = { [key: string]: string | number | CSSProperties; }; ================================================ FILE: packages/atomic/src/css.ts ================================================ import type { LinariaClassName } from '@linaria/core'; import type { CSSProperties } from './CSSProperties'; type CSS = ( strings: TemplateStringsArray, ...exprs: Array ) => LinariaClassName; let idx = 0; export const css: CSS = () => { if (process.env.NODE_ENV === 'test') { // eslint-disable-next-line no-plusplus return `mocked-atomic-css-${idx++}` as LinariaClassName; } throw new Error( 'Using the "css" tag in runtime is not supported. Make sure you have set up the Babel plugin correctly.' ); }; export default css; ================================================ FILE: packages/atomic/src/index.ts ================================================ export { default as css } from './css'; export { styled } from '@linaria/react'; export { cx } from '@linaria/core'; export type { CSSProperties } from './CSSProperties'; ================================================ FILE: packages/atomic/src/processors/css.ts ================================================ import type { SourceLocation } from '@babel/types'; import type { Rules, ValueCache } from '@wyw-in-js/processor-utils'; import { logger } from '@wyw-in-js/shared'; import CssProcessor from '@linaria/core/processors/css'; import atomize from './helpers/atomize'; const debug = logger.extend('AtomicCssProcessor'); export default class AtomicCssProcessor extends CssProcessor { #classes: string | undefined; private get classes(): string { if (typeof this.#classes !== 'undefined') { return this.#classes; } throw new Error('Styles are not extracted yet. Please call `build` first.'); } public override doRuntimeReplacement(): void { this.replacer(this.astService.stringLiteral(this.classes), false); } public override extractRules( valueCache: ValueCache, cssText: string, loc?: SourceLocation | null ): Rules { const rules: Rules = {}; const atomicRules = atomize(cssText, false); atomicRules.forEach((rule) => { // eslint-disable-next-line no-param-reassign rules[rule.cssText] = { cssText: rule.cssText, start: loc?.start ?? null, className: this.className!, displayName: this.displayName!, atom: true, }; debug('extracted-atomic-rule:\n%s', rule.cssText); }); this.#classes = atomicRules // Some atomic rules produced (eg. keyframes) don't have class names, and they also don't need to appear in the object .filter((rule) => !!rule.className) .map((rule) => rule.className!) .join(' '); return rules; } } ================================================ FILE: packages/atomic/src/processors/helpers/atomize.ts ================================================ import { slugify } from '@wyw-in-js/shared'; import { all as knownProperties } from 'known-css-properties'; import type { Document, AtRule, Container, Rule } from 'postcss'; import postcss from 'postcss'; import { compile, serialize, stringify } from 'stylis'; import { getPropertyPriority } from './propertyPriority'; const knownPropertiesMap = knownProperties.reduce( (acc: { [property: string]: number }, property, i) => { acc[property] = i; return acc; }, {} ); function hashProperty(property: string) { const index = knownPropertiesMap[property]; // If it's a known property, let's use the index to cut down the length of the hash. // otherwise, slugify if (index !== undefined) { return index.toString(36); // base 36 so that we get a-z,0-9 } return slugify(property); } const parseCss = (cssText: string) => { try { return postcss.parse(cssText); } catch (e) { if (e instanceof Error) { throw new Error(`Error parsing CSS: ${e.message}\nCSS:\n${cssText}`); } throw new Error(`Unknown error parsing CSS.\nCSS:\n${cssText}`); } }; export default function atomize(cssText: string, hasPriority = false) { const atomicRules: { className?: string; cssText: string; property: string; }[] = []; const stylesheet = parseCss(cssText); // We want to extract all keyframes and leave them as-is. // This isn't scoped locally yet stylesheet.walkAtRules('keyframes', (atRule) => { atRule.remove(); atomicRules.push({ property: atRule.name, cssText: atRule.toString(), }); }); stylesheet.walkDecls((decl) => { let thisParent: Document | Container | undefined = decl.parent; const parents: (Document | Container)[] = []; const atomicProperty = [decl.prop]; let hasAtRule = false; // Traverse the declarations parents, and collect them all. while (thisParent && thisParent !== stylesheet) { parents.unshift(thisParent); if (thisParent.type === 'atrule') { hasAtRule = true; // @media queries, @supports etc. atomicProperty.push( (thisParent as AtRule).name, (thisParent as AtRule).params ); } else if (thisParent.type === 'rule') { // pseudo classes etc. atomicProperty.push((thisParent as Rule).selector); } thisParent = thisParent.parent; } // Create a new stylesheet that contains *just* the extracted atomic rule and wrapping selectors, eg. // `@media (max-width: 400px) { background: red; }`, or // `&:hover { background: red; }`, or // `background: red;` // We do this so we can run it through stylis, to produce a full atom, eg. // `@media (max-width: 400px) { .atm_foo { background: red; } }` const root = postcss.root(); let container: Document | Container = root; parents.forEach((parent) => { const newNode = parent.clone(); newNode.removeAll(); container.append(newNode); container = newNode; }); container.append(decl.clone()); const css = root.toString(); const propertySlug = hashProperty([...atomicProperty].join(';')); const valueSlug = slugify(decl.value); const className = `atm_${propertySlug}_${valueSlug}`; const propertyPriority = getPropertyPriority(decl.prop) + (hasAtRule ? 1 : 0) + (hasPriority ? 1 : 0); const selector = `.${className}`.repeat(propertyPriority); const processedCss = serialize(compile(`${selector} {${css}}`), stringify); atomicRules.push({ property: atomicProperty.join(' '), className, cssText: processedCss, }); }); return atomicRules; } ================================================ FILE: packages/atomic/src/processors/helpers/propertyPriority.ts ================================================ const shorthandProperties = { // The `all` property resets everything, and should effectively have priority zero. // In practice, this can be achieved by using: div { all: ... } to have even less specificity, but to avoid duplicating all selectors, we just let it be // 'all': [] animation: [ 'animation-name', 'animation-duration', 'animation-timing-function', 'animation-delay', 'animation-iteration-count', 'animation-direction', 'animation-fill-mode', 'animation-play-state', ], background: [ 'background-attachment', 'background-clip', 'background-color', 'background-image', 'background-origin', 'background-position', 'background-repeat', 'background-size', ], border: ['border-color', 'border-style', 'border-width'], 'border-block-end': [ 'border-block-end-color', 'border-block-end-style', 'border-block-end-width', ], 'border-block-start': [ 'border-block-start-color', 'border-block-start-style', 'border-block-start-width', ], 'border-bottom': [ 'border-bottom-color', 'border-bottom-style', 'border-bottom-width', ], 'border-color': [ 'border-bottom-color', 'border-left-color', 'border-right-color', 'border-top-color', ], 'border-image': [ 'border-image-outset', 'border-image-repeat', 'border-image-slice', 'border-image-source', 'border-image-width', ], 'border-inline-end': [ 'border-inline-end-color', 'border-inline-end-style', 'border-inline-end-width', ], 'border-inline-start': [ 'border-inline-start-color', 'border-inline-start-style', 'border-inline-start-width', ], 'border-left': [ 'border-left-color', 'border-left-style', 'border-left-width', ], 'border-radius': [ 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius', ], 'border-right': [ 'border-right-color', 'border-right-style', 'border-right-width', ], 'border-style': [ 'border-bottom-style', 'border-left-style', 'border-right-style', 'border-top-style', ], 'border-top': ['border-top-color', 'border-top-style', 'border-top-width'], 'border-width': [ 'border-bottom-width', 'border-left-width', 'border-right-width', 'border-top-width', ], 'column-rule': [ 'column-rule-width', 'column-rule-style', 'column-rule-color', ], columns: ['column-count', 'column-width'], flex: ['flex-grow', 'flex-shrink', 'flex-basis'], 'flex-flow': ['flex-direction', 'flex-wrap'], font: [ 'font-family', 'font-size', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'line-height', ], gap: ['row-gap', 'column-gap'], grid: [ 'grid-auto-columns', 'grid-auto-flow', 'grid-auto-rows', 'grid-template-areas', 'grid-template-columns', 'grid-template-rows', ], 'grid-area': [ 'grid-row-start', 'grid-column-start', 'grid-row-end', 'grid-column-end', ], 'grid-column': ['grid-column-end', 'grid-column-start'], 'grid-row': ['grid-row-end', 'grid-row-start'], 'grid-template': [ 'grid-template-areas', 'grid-template-columns', 'grid-template-rows', ], 'list-style': ['list-style-image', 'list-style-position', 'list-style-type'], margin: ['margin-bottom', 'margin-left', 'margin-right', 'margin-top'], mask: [ 'mask-clip', 'mask-composite', 'mask-image', 'mask-mode', 'mask-origin', 'mask-position', 'mask-repeat', 'mask-size', ], offset: [ 'offset-anchor', 'offset-distance', 'offset-path', 'offset-position', 'offset-rotate', ], outline: ['outline-color', 'outline-style', 'outline-width'], overflow: ['overflow-x', 'overflow-y'], padding: ['padding-bottom', 'padding-left', 'padding-right', 'padding-top'], 'place-content': ['align-content', 'justify-content'], 'place-items': ['align-items', 'justify-items'], 'place-self': ['align-self', 'justify-self'], 'scroll-margin': [ 'scroll-margin-bottom', 'scroll-margin-left', 'scroll-margin-right', 'scroll-margin-top', ], 'scroll-padding': [ 'scroll-padding-bottom', 'scroll-padding-left', 'scroll-padding-right', 'scroll-padding-top', ], 'text-decoration': [ 'text-decoration-color', 'text-decoration-line', 'text-decoration-style', 'text-decoration-thickness', ], 'text-emphasis': ['text-emphasis-color', 'text-emphasis-style'], transition: [ 'transition-delay', 'transition-duration', 'transition-property', 'transition-timing-function', ], }; // Get the property priority: the higher the priority, the higher the resulting // specificity of the atom. For example, if we had: // // import { css } from '@linaria/atomic'; // css` // background-color: blue; // background: red; // `; // // we would produce: // // .atm_a.atm_a { background-color: blue } // .atm_b { background: red } // // and so the more specific selector (.atm_a.atm_a) would win export function getPropertyPriority(property: string) { const longhands = Object.values(shorthandProperties).reduce( (a, b) => [...a, ...b], [] ); return longhands.includes(property) ? 2 : 1; } ================================================ FILE: packages/atomic/src/processors/styled.ts ================================================ import type { SourceLocation } from '@babel/types'; import type { Rules, ValueCache } from '@wyw-in-js/processor-utils'; import { logger, hasEvalMeta } from '@wyw-in-js/shared'; import type { IProps } from '@linaria/react/processors/styled'; import StyledProcessor from '@linaria/react/processors/styled'; import atomize from './helpers/atomize'; const debug = logger.extend('AtomicStyledProcessor'); export default class AtomicStyledProcessor extends StyledProcessor { #classes: string | undefined; private get classes(): string { if (this.#classes) { return this.#classes; } throw new Error( 'Styles are not extracted yet. Please call `extractRules` first.' ); } public override extractRules( valueCache: ValueCache, cssText: string, loc?: SourceLocation | null ): Rules { const rules: Rules = {}; const wrappedValue = typeof this.component === 'string' ? null : valueCache.get(this.component.node.name); const atomicRules = atomize(cssText, hasEvalMeta(wrappedValue)); atomicRules.forEach((rule) => { // eslint-disable-next-line no-param-reassign rules[rule.cssText] = { cssText: rule.cssText, start: loc?.start ?? null, className: this.className, displayName: this.displayName, atom: true, }; debug('extracted-atomic-rule:\n%s', rule.cssText); }); this.#classes = atomicRules // Some atomic rules produced (eg. keyframes) don't have class names, and they also don't need to appear in the object .filter((rule) => !!rule.className) .map((rule) => rule.className!) .join(' '); return rules; } protected override getProps(): IProps { const props = super.getProps(); props.class = [this.classes, this.className].filter(Boolean).join(' '); props.atomic = true; return props; } protected override getVariableId( source: string, unit: string, precedingCss: string ): string { const id = this.getCustomVariableId(source, unit, precedingCss); if (id) { return id; } const context = this.getVariableContext(source, unit, precedingCss); // id is based on the slugified value return context.valueSlug; } } ================================================ FILE: packages/atomic/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "paths": {}, "rootDir": "src/", "types": ["node"] }, "references": [{ "path": "../core" }, { "path": "../react" }] } ================================================ FILE: packages/core/CHANGELOG.md ================================================ # Change Log ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ### Patch Changes - 8d4ebd33: chore: bump @wyw-in-js/\* packages ## 6.0.0 ### Major Changes - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ## 5.0.2 ### Patch Changes - Updated dependencies [4992c14d] - Updated dependencies [70000ec8] - Updated dependencies [1e889937] - Updated dependencies [5a32f4fd] - Updated dependencies [727dc2bd] - Updated dependencies [25ba1344] - Updated dependencies [5a32f4fd] - @linaria/utils@5.0.2 - @linaria/tags@5.0.2 ## 5.0.1 ### Patch Changes - Updated dependencies [6fb6eb69] - @linaria/utils@5.0.1 - @linaria/tags@5.0.1 ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 - Updated dependencies [9cb4143d] - Updated dependencies [ae162f46] - Updated dependencies [88e07613] - Updated dependencies [b3ef8c1f] - Updated dependencies [f8b9bff5] - Updated dependencies [63902332] - Updated dependencies [aa100453] - Updated dependencies [9bb782d0] - Updated dependencies [2a1e24a0] - Updated dependencies [16320d71] - Updated dependencies [cb853e14] - @linaria/logger@5.0.0 - @linaria/tags@5.0.0 - @linaria/utils@5.0.0 ## 4.5.4 ### Patch Changes - Updated dependencies [10bcd241] - @linaria/utils@4.5.3 - @linaria/tags@4.5.4 ## 4.5.3 ### Patch Changes - 79557248: Nothing has changed. Just moved some utils and types from babel to utils package. - e59bf809: Shaker mistakenly counts references in types as valuable and keeps referenced variables alive. - Updated dependencies [79557248] - Updated dependencies [b191f543] - Updated dependencies [e59bf809] - Updated dependencies [520ba8da] - Updated dependencies [ae3727f9] - Updated dependencies [dca076ef] - @linaria/tags@4.5.3 - @linaria/utils@4.5.2 ## 4.5.2 ### Patch Changes - Updated dependencies [85e74df6] - Updated dependencies [1bf5c5b8] - @linaria/utils@4.5.1 - @linaria/tags@4.5.2 ## 4.5.1 ### Patch Changes - Updated dependencies [ceca1611] - Updated dependencies [13258306] - @linaria/tags@4.5.1 ## 4.5.0 ### Minor Changes - 16c057df: Breaking Change: Performance Optimization for `styled` When a component is wrapped in `styled`, Linaria needs to determine if that component is already a styled component. To accomplish this, the wrapped component is included in the list of variables for evaluation, along with the interpolated values used in styles. The issue arises when a wrapped component, even if it is not styled, brings along a substantial dependency tree. This situation is particularly evident when using `styled` to style components from third-party UI libraries. To address this problem, Linaria will now examine the import location of the component and check if there is an annotation in the `package.json` file of the package containing the components. This annotation indicates whether the package includes other Linaria components. If there is no such annotation, Linaria will refrain from evaluating the component. Please note that this Breaking Change solely affects developers of component libraries. In order for users to style components from your library, you must include the `linaria.components` property in the library's `package.json` file. This property should have a mask that covers all imported files with components. Here's an example of how to specify it: ```json "linaria": { "components": "**/*" } ``` ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. - Updated dependencies [890b4aca] - Updated dependencies [05ad266c] - Updated dependencies [16c057df] - Updated dependencies [af5bb92d] - @linaria/utils@4.5.0 - @linaria/tags@4.5.0 - @linaria/logger@4.5.0 ## 4.2.10 ### Patch Changes - Updated dependencies [54ab61b2] - @linaria/tags@4.3.5 - @linaria/utils@4.3.4 ## 4.2.9 ### Patch Changes - 34029088: Usages of `styled` and `css` in Jest no longer trigger the "Using the … tag in runtime is not supported" exception. - Updated dependencies [2e966f23] - Updated dependencies [1c3f309d] - Updated dependencies [dbe250b5] - @linaria/tags@4.3.4 - @linaria/utils@4.3.3 ## 4.2.8 ### Patch Changes - Updated dependencies [a3ad617f] - @linaria/tags@4.3.3 ## 4.2.7 ### Patch Changes - Updated dependencies [f9df4ed8] - @linaria/utils@4.3.2 - @linaria/tags@4.3.2 ## 4.2.6 ### Patch Changes - Updated dependencies [28f3f93d] - Updated dependencies [71a5b351] - Updated dependencies [61d49a39] - @linaria/tags@4.3.1 - @linaria/utils@4.3.1 ## 4.2.5 ### Patch Changes - Updated dependencies [3ce985e0] - Updated dependencies [d11174d0] - @linaria/tags@4.3.0 - @linaria/utils@4.3.0 ## 4.2.4 ### Patch Changes - Updated dependencies [315f0366] - @linaria/utils@4.2.6 - @linaria/tags@4.2.2 ## 4.2.3 ### Patch Changes - 5edde648: Upgrade Babel to support TypeScript 4.9. Fixes #1133. - Updated dependencies [5edde648] - Updated dependencies [b9e49b74] - @linaria/tags@4.2.1 - @linaria/utils@4.2.5 ## 4.2.2 ### Patch Changes - Updated dependencies [63f56d47] - Updated dependencies [963508a2] - @linaria/tags@4.2.0 - @linaria/utils@4.2.4 ## 4.2.1 ### Patch Changes - Updated dependencies [cc2f87a8] - @linaria/utils@4.2.3 - @linaria/tags@4.1.5 ## 4.2.0 ### Minor Changes - 1e88e95d: Support for ECMAScript modules. Fixes #904 and #1043. ## 4.1.4 ### Patch Changes - 87ffe61c: The new `variableNameSlug` option that allows to customize css variable names (closes #1053). - Updated dependencies [8a8be242] - Updated dependencies [8a8be242] - Updated dependencies [08304e09] - Updated dependencies [87ffe61c] - @linaria/utils@4.2.2 - @linaria/tags@4.1.4 ## 4.1.3 ### Patch Changes - Updated dependencies [24b4a4bd] - @linaria/utils@4.2.1 - @linaria/tags@4.1.3 ## 4.1.2 ### Patch Changes - Updated dependencies [8590e134] - Updated dependencies [f7351b09] - Updated dependencies [c0bd271a] - Updated dependencies [8f90fa75] - Updated dependencies [ac0991a6] - @linaria/utils@4.2.0 - @linaria/tags@4.1.2 ## 4.1.1 ### Patch Changes - Updated dependencies [50bc0c79] - @linaria/utils@4.1.1 - @linaria/tags@4.1.1 ## 4.1.0 ### Patch Changes - Updated dependencies [92f6d871] - @linaria/utils@4.1.0 - @linaria/tags@4.1.0 ## 4.0.0 ### Major Changes - bc0cbeea: A completely new async mode with native support for Vite, Rollup, esbuild and Webpack resolvers. BREAKING CHANGES: Despite the fact, that it should be fully compatible with 3.0 and 2.0 branches, the new version of styles evaluator can have some serious bugs which can make your project unbuildable (however, since there is no runtime, if the build is finished successfully, everything will continue work as it was on 2.0 and 3.0). If you face some problems please let us know and we will fix it as soon as possible. ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - ea41d440: New package @linaria/tags that contains all abstract logic for tags processors. - 9a50c1c1: Linaria now removes all unused css-related code from the runtime. - 4cdf0315: Tagged template-specific logic has been moved from `BaseProcessor` to `TaggedTemplateProcessor`. `BaseProcessor` now can be used to define any type of expressions for zero-runtime transformations, such as `makeStyles` from `@griffel/react`. - 12d35cb9: `processors` aliases have been lost during publishing. (fixes #984) - f726eb3b: `cx` should return `LinariaClassName` if all arguments are `LinariaClassName` - 17c83e34: Aliases for environments without the support of `exports` in package.json. - f0cddda4: Extends `BaseProcessor` to support tags other than tagged templates, such as `makeStyles` from `@griffel/react`. - Updated dependencies [f0cddda4] - @linaria/logger@4.0.0 - @linaria/utils@4.0.0 - @linaria/tags@4.0.0 ## 3.0.0-beta.21 ### Patch Changes - f726eb3b: `cx` should return `LinariaClassName` if all arguments are `LinariaClassName` - 17c83e34: Aliases for environments without the support of `exports` in package.json. ## 3.0.0-beta.20 ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - Updated dependencies [8be5650d] - @linaria/logger@3.0.0-beta.20 - @linaria/utils@3.0.0-beta.20 # [3.0.0-beta.19](https://github.com/callstack/linaria/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2022-06-03) ### Features - **babel:** api for custom tags ([#976](https://github.com/callstack/linaria/issues/976)) ([3285ccc](https://github.com/callstack/linaria/commit/3285ccc1d00449b78b3fc74087528cd38cbdd116)) - **babel:** new way for detecting tag imports ([#974](https://github.com/callstack/linaria/issues/974)) ([3305cfb](https://github.com/callstack/linaria/commit/3305cfb0c0f65abdacceeb7e6bad118c59f7d551)) # [3.0.0-beta.18](https://github.com/callstack/linaria/compare/v3.0.0-beta.17...v3.0.0-beta.18) (2022-04-01) **Note:** Version bump only for package @linaria/core # [3.0.0-beta.15](https://github.com/callstack/linaria/compare/v3.0.0-beta.14...v3.0.0-beta.15) (2021-11-29) ### Features - **atomic:** create an atomic package for the css API ([#867](https://github.com/callstack/linaria/issues/867)) ([4773bcf](https://github.com/callstack/linaria/commit/4773bcf4b14f08cdc4d2b612654b962cdfc97eaa)) # [3.0.0-beta.13](https://github.com/callstack/linaria/compare/v3.0.0-beta.12...v3.0.0-beta.13) (2021-09-13) ### Bug Fixes - **core:** return type alias instead of string from `css` and `cx` ([#835](https://github.com/callstack/linaria/issues/835)) ([7eb9d94](https://github.com/callstack/linaria/commit/7eb9d94dc2d9d79f7be0159c43fa5d71c96d7182)) # [3.0.0-beta.4](https://github.com/callstack/linaria/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2021-05-07) **Note:** Version bump only for package @linaria/core # [3.0.0-beta.3](https://github.com/callstack/linaria/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2021-04-20) **Note:** Version bump only for package @linaria/core # [3.0.0-beta.2](https://github.com/callstack/linaria/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2021-04-11) ### Bug Fixes - **core:** remove unnecessary spread operators from css and cx ([#746](https://github.com/callstack/linaria/issues/746)) ([#749](https://github.com/callstack/linaria/issues/749)) ([de23a09](https://github.com/callstack/linaria/commit/de23a0926c2583db01e7df5ea9a134f5910f96a1)) ================================================ FILE: packages/core/README.md ================================================

Linaria

Zero-runtime CSS in JS library.

--- ### 📖 Please refer to the [GitHub](https://github.com/callstack/linaria#readme) for full documentation. ## Features - Write CSS in JS, but with **zero runtime**, CSS is extracted to CSS files during build - Familiar **CSS syntax** with Sass like nesting - Use **dynamic prop based styles** with the React bindings, uses CSS variables behind the scenes - Easily find where the style was defined with **CSS sourcemaps** - **Lint your CSS** in JS with [stylelint](https://github.com/stylelint/stylelint) - Use **JavaScript for logic**, no CSS preprocessor needed - Optionally use any **CSS preprocessor** such as Sass or PostCSS **[Why use Linaria](../../docs/BENEFITS.md)** ## Installation ```sh npm install @linaria/core @linaria/react @linaria/babel-preset ``` or ```sh yarn add @linaria/core @linaria/react @linaria/babel-preset ``` ================================================ FILE: packages/core/__dtslint__/core.ts ================================================ /* eslint-disable @typescript-eslint/no-unused-vars */ import { css, cx } from '../src'; // $ExpectType LinariaClassName const class1 = css``; const activeClass = css``; // $ExpectType string const combined1 = cx(class1, 'active'); // $ExpectType LinariaClassName const combined2 = cx(class1, activeClass); ================================================ FILE: packages/core/__dtslint__/index.d.ts ================================================ // dtslint wants to see index.d.ts. Well, here it is. declare const linaria: unknown; ================================================ FILE: packages/core/__dtslint__/tsconfig.eslint.json ================================================ { "extends": "./tsconfig.json" } ================================================ FILE: packages/core/__dtslint__/tsconfig.json ================================================ { "compilerOptions": { "module": "commonjs", "lib": ["es6"], "target": "ES2015", "esModuleInterop": true, "noImplicitAny": true, "noImplicitThis": true, "strictNullChecks": true, "strictFunctionTypes": true, "noEmit": true, "baseUrl": "./" } } ================================================ FILE: packages/core/__tests__/cx.test.ts ================================================ import cx from '../src/cx'; it('should filter falsy values', () => { expect(cx('1', 'test', false, '2', 0, '', null, undefined, '3')).toBe( '1 test 2 3' ); }); it('should join atoms together, de-duplicating by property and joining the values', () => { expect(cx('atm_a_class1 atm_b_class2', 'atm_a_class3')).toBe( 'atm_a_class3 atm_b_class2' ); }); it('should join atoms and non atoms together at the same time', () => { expect( cx('atm_a_1', 'atm_b_2', false, '2', 0, '', null, undefined, '3', 'atm_b_3') ).toBe('atm_a_1 atm_b_3 2 3'); }); ================================================ FILE: packages/core/__tests__/detect-core-js.test.ts ================================================ import cp from 'child_process'; const waitForProcess = async (process: cp.ChildProcess) => { return new Promise((resolve) => { let output = ''; process.stdout?.on('data', (chunk) => { output += chunk.toString(); }); process.on('close', () => { resolve(output); }); }); }; it('Ensures that package do not include core-js dependency after build', async () => { // eslint-disable-next-line import/no-extraneous-dependencies const packageJSON = require('@linaria/core/package.json'); const buildScript = packageJSON.scripts['build:corejs-test']; const proc = cp.exec(buildScript, { env: { ...process.env, DEBUG_CORE_JS: 'true', }, }); const result = await waitForProcess(proc); // run `DEBUG_CORE_JS=true yarn build:lib` to debug issues with introduced core-js dependency expect(result).not.toContain( 'The corejs3 polyfill added the following polyfills' ); expect(result).toContain( 'Based on your code and targets, the corejs3 polyfill did not add any polyfill' ); }, 30000); ================================================ FILE: packages/core/babel.config.js ================================================ const config = require('../../babel.config'); module.exports = config; ================================================ FILE: packages/core/package.json ================================================ { "name": "@linaria/core", "version": "7.0.0", "description": "Blazing fast zero-runtime CSS in JS library", "keywords": [ "css", "css-in-js", "linaria", "react", "styled-components" ], "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "sideEffects": false, "exports": { "./package.json": "./package.json", ".": { "types": "./types/index.d.ts", "import": "./dist/index.mjs", "default": "./dist/index.js" }, "./*": { "types": "./types/*.d.ts", "import": "./dist/*.mjs", "default": "./dist/*.js" } }, "main": "dist/index.js", "module": "dist/index.mjs", "types": "types/index.d.ts", "typesVersions": { "*": { "processors/*": [ "./types/processors/*.d.ts" ] } }, "files": [ "dist/", "processors/", "types/" ], "wyw-in-js": { "tags": { "css": "./dist/processors/css.js" } }, "scripts": { "build": "pnpm build:dist && pnpm build:declarations", "build:corejs-test": "cross-env NODE_ENV=legacy babel src --out-dir lib --extensions '.js,.jsx,.ts,.tsx' --ignore \"src/processors/**/*\"", "build:declarations": "tsc --emitDeclarationOnly --outDir types", "build:dist": "tsup --format cjs,esm", "test": "jest --config ../../jest.config.js --rootDir .", "test:dts": "dtslint --localTs ../../node_modules/typescript/lib __dtslint__", "typecheck": "tsc --noEmit --composite false", "watch": "pnpm build:dist --watch & pnpm build:declarations --watch" }, "dependencies": { "@wyw-in-js/processor-utils": "^1.0.4" }, "devDependencies": { "@babel/traverse": "^7.23.5", "@babel/types": "^7.23.5", "@types/babel__core": "^7.20.5", "@types/babel__traverse": "^7.20.4", "@types/node": "^17.0.39" }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" }, "tsup": { "entry": [ "src/index.ts", "src/processors/css.ts" ], "splitting": false, "sourcemap": true, "clean": true } } ================================================ FILE: packages/core/processors/css.js ================================================ Object.defineProperty(exports, '__esModule', { value: true, }); exports.default = require('../dist/processors/css').default; ================================================ FILE: packages/core/src/CSSProperties.ts ================================================ export type CSSProperties = { [key: string]: string | number | CSSProperties; }; ================================================ FILE: packages/core/src/css.ts ================================================ import type { CSSProperties } from './CSSProperties'; import type { LinariaClassName } from './cx'; type WYWEvalMeta = { __wyw_meta: unknown }; // simplified version of WYWEvalMeta from @wyw-in-js/shared type CSS = ( strings: TemplateStringsArray, ...exprs: Array ) => LinariaClassName; let idx = 0; const css: CSS = () => { if (process.env.NODE_ENV === 'test') { // eslint-disable-next-line no-plusplus return `mocked-css-${idx++}` as LinariaClassName; } throw new Error( 'Using the "css" tag in runtime is not supported. Make sure you have set up the Babel plugin correctly.' ); }; export default css; ================================================ FILE: packages/core/src/cx.ts ================================================ export type LinariaClassName = string & { __linariaClassName: true }; export type ClassName = T | false | void | null | 0 | ''; interface ICX { (...classNames: ClassName[]): LinariaClassName; (...classNames: ClassName[]): string; } /** * Takes a list of class names and filters for truthy ones, joining them into a single class name for convenience. * eg. * ```js * cx('red', isBig && 'big') // returns 'red big' if `isBig` is true, otherwise returns 'red' * ``` * If space separated atomic styles are provided, they are deduplicated according to the first hashed valued: * * ```js * cx('atm_a_class1 atm_b_class2', 'atm_a_class3') // returns `atm_a_class3 atm_b_class2` * ``` * * @returns the combined, space separated class names that can be applied directly to the class attribute */ const cx: ICX = function cx() { const presentClassNames: (ClassName | ClassName)[] = Array.prototype.slice // eslint-disable-next-line prefer-rest-params .call(arguments) .filter(Boolean); const atomicClasses: { [k: string]: string } = {}; const nonAtomicClasses: string[] = []; presentClassNames.forEach((arg) => { // className could be the output of a previous cx call, so split by ' ' first const individualClassNames = arg ? arg.split(' ') : []; individualClassNames.forEach((className) => { if (className.startsWith('atm_')) { const [, keyHash] = className.split('_'); atomicClasses[keyHash] = className; } else { nonAtomicClasses.push(className); } }); }); const result: string[] = []; // eslint-disable-next-line no-restricted-syntax for (const keyHash in atomicClasses) { if (Object.prototype.hasOwnProperty.call(atomicClasses, keyHash)) { result.push(atomicClasses[keyHash]); } } result.push(...nonAtomicClasses); return result.join(' ') as LinariaClassName; }; export default cx; ================================================ FILE: packages/core/src/index.ts ================================================ export { default as css } from './css'; export { default as cx } from './cx'; export type { CSSProperties } from './CSSProperties'; export type { LinariaClassName } from './cx'; ================================================ FILE: packages/core/src/processors/css.ts ================================================ import type { SourceLocation, StringLiteral } from '@babel/types'; import type { Rules, ValueCache } from '@wyw-in-js/processor-utils'; import { TaggedTemplateProcessor } from '@wyw-in-js/processor-utils'; export default class CssProcessor extends TaggedTemplateProcessor { public override get asSelector(): string { return this.className; } public override get value(): StringLiteral { return this.astService.stringLiteral(this.className); } // eslint-disable-next-line class-methods-use-this public override addInterpolation( node: unknown, precedingCss: string, source: string ): string { throw new Error( `css tag cannot handle '${source}' as an interpolated value` ); } public override doEvaltimeReplacement(): void { this.replacer(this.value, false); } public override doRuntimeReplacement(): void { this.replacer(this.astService.stringLiteral(this.className), false); } public override extractRules( valueCache: ValueCache, cssText: string, loc?: SourceLocation | null ): Rules { const rules: Rules = {}; const selector = `.${this.className}`; rules[selector] = { cssText, className: this.className, displayName: this.displayName, start: loc?.start ?? null, }; return rules; } } ================================================ FILE: packages/core/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "paths": {}, "rootDir": "src/", "types": ["node"] }, "references": [] } ================================================ FILE: packages/interop/CHANGELOG.md ================================================ # Change Log ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ## 6.0.0 ### Major Changes - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 ## 4.5.1 ### Patch Changes - e59bf809: Shaker mistakenly counts references in types as valuable and keeps referenced variables alive. ## 4.5.0 ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. ## 4.0.1 ### Patch Changes - 5edde648: Upgrade Babel to support TypeScript 4.9. Fixes #1133. ## 4.0.0 ### Major Changes - bc0cbeea: A completely new async mode with native support for Vite, Rollup, esbuild and Webpack resolvers. BREAKING CHANGES: Despite the fact, that it should be fully compatible with 3.0 and 2.0 branches, the new version of styles evaluator can have some serious bugs which can make your project unbuildable (however, since there is no runtime, if the build is finished successfully, everything will continue work as it was on 2.0 and 3.0). If you face some problems please let us know and we will fix it as soon as possible. ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - ea41d440: New package @linaria/tags that contains all abstract logic for tags processors. ## 3.0.0-beta.20 ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo # [3.0.0-beta.19](https://github.com/callstack/linaria/tree/master/packages/interop/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2022-06-03) ### Features - **babel:** api for custom tags ([#976](https://github.com/callstack/linaria/tree/master/packages/interop/issues/976)) ([3285ccc](https://github.com/callstack/linaria/tree/master/packages/interop/commit/3285ccc1d00449b78b3fc74087528cd38cbdd116)) - **babel:** new way for detecting tag imports ([#974](https://github.com/callstack/linaria/tree/master/packages/interop/issues/974)) ([3305cfb](https://github.com/callstack/linaria/tree/master/packages/interop/commit/3305cfb0c0f65abdacceeb7e6bad118c59f7d551)) # [3.0.0-beta.7](https://github.com/callstack/linaria/tree/master/packages/interop/compare/v3.0.0-beta.6...v3.0.0-beta.7) (2021-06-24) **Note:** Version bump only for package @linaria/babel-plugin-interop # [3.0.0-beta.6](https://github.com/callstack/linaria/tree/master/packages/interop/compare/v3.0.0-beta.5...v3.0.0-beta.6) (2021-06-06) ### Features - **interop:** interop between Linaria and traditional CSS-in-JS libraries ([#776](https://github.com/callstack/linaria/tree/master/packages/interop/issues/776)) ([0a5f5b4](https://github.com/callstack/linaria/tree/master/packages/interop/commit/0a5f5b440506bfa24724d4a91e519c48d6f6c69b)) ================================================ FILE: packages/interop/README.md ================================================

Linaria

Zero-runtime CSS in JS library.

--- # `@linaria/babel-plugin-interop` This plugin allows to interpolate Linaria components inside styled-components and Emotion: ```javascript import styled from 'styled-components'; import { Title } from './Title.styled'; // Linaria component const Article = () => { /* … */ }; export default styled(Article)` & > ${Title} { color: green; } `; ``` ## Quick start Install the plugin first: ``` npm install --save-dev @linaria/babel-plugin-interop ``` Then add `@linaria/interop` to your babel configuration *before* `styled-components`: ```JSON { "plugins": [ ["@linaria/interop", { "library": "styled-components" }], "styled-components" ] } ``` ================================================ FILE: packages/interop/__tests__/__snapshots__/index.test.ts.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`styled-components css 1`] = ` ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _styledComponents = require("styled-components"); var _Title = _interopRequireDefault(require("./Title")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _default = exports.default = (0, _styledComponents.css)\` & > \${(i => i && i.__wyw_meta ? '.' + i.__wyw_meta.className : i)(_Title.default)} { color: red; } \`;" `; exports[`styled-components keeps linaria 1`] = ` ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireDefault(require("linaria/react")); var _Title = _interopRequireDefault(require("./Title")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _default = exports.default = _react.default.h1\` & > \${_Title.default} { color: red; } \`;" `; exports[`styled-components member expression as selector 1`] = ` ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _styledComponents = _interopRequireDefault(require("styled-components")); var _Title = _interopRequireDefault(require("./Title")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _default = exports.default = _styledComponents.default.h1\` & > \${(i => i && i.__wyw_meta ? '.' + i.__wyw_meta.className : i)(_Title.default.Small)} { color: red; } \`;" `; exports[`styled-components styled(Cmp) 1`] = ` ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _styledComponents = _interopRequireDefault(require("styled-components")); var _Cmp = _interopRequireDefault(require("./Cmp")); var _Title = _interopRequireDefault(require("./Title")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _default = exports.default = (0, _styledComponents.default)(_Cmp.default)\` & > \${(i => i && i.__wyw_meta ? '.' + i.__wyw_meta.className : i)(_Title.default)} { color: red; } \`;" `; exports[`styled-components styled(Cmp).attrs({}) 1`] = ` ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _styledComponents = _interopRequireDefault(require("styled-components")); var _Cmp = _interopRequireDefault(require("./Cmp")); var _Title = _interopRequireDefault(require("./Title")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _default = exports.default = (0, _styledComponents.default)(_Cmp.default).attrs(() => ({}))\` & > \${(i => i && i.__wyw_meta ? '.' + i.__wyw_meta.className : i)(_Title.default)} { color: red; } \`;" `; exports[`styled-components styled.h1 1`] = ` ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _styledComponents = _interopRequireDefault(require("styled-components")); var _Title = _interopRequireDefault(require("./Title")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _default = exports.default = _styledComponents.default.h1\` & > \${(i => i && i.__wyw_meta ? '.' + i.__wyw_meta.className : i)(_Title.default)} { color: red; } \`;" `; exports[`styled-components styled.h1.attrs({}) 1`] = ` ""use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _styledComponents = _interopRequireDefault(require("styled-components")); var _Title = _interopRequireDefault(require("./Title")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _default = exports.default = _styledComponents.default.h1.attrs(() => ({}))\` & > \${(i => i && i.__wyw_meta ? '.' + i.__wyw_meta.className : i)(_Title.default)} { color: red; } \`;" `; ================================================ FILE: packages/interop/__tests__/index.test.ts ================================================ const babel = require('@babel/core'); const dedent = require('dedent'); const plugin = require('../src'); const getCode = (src: string) => { const { code } = babel.transform(dedent(src), { filename: 'test.js', babelrc: false, plugins: [plugin], }); return code; }; describe('styled-components', () => { it('keeps linaria', () => { const code = getCode(` import styled from "linaria/react"; import Title from "./Title"; export default styled.h1\` & > ${'${Title}'} { color: red; } \`; `); expect(code).toMatchSnapshot(); }); it('css', () => { const code = getCode(` import { css } from "styled-components"; import Title from "./Title"; export default css\` & > ${'${Title}'} { color: red; } \`; `); expect(code).toMatchSnapshot(); }); it('styled.h1', () => { const code = getCode(` import styled from "styled-components"; import Title from "./Title"; export default styled.h1\` & > ${'${Title}'} { color: red; } \`; `); expect(code).toMatchSnapshot(); }); it('member expression as selector', () => { const code = getCode(` import styled from "styled-components"; import Title from "./Title"; export default styled.h1\` & > ${'${Title.Small}'} { color: red; } \`; `); expect(code).toMatchSnapshot(); }); it('styled(Cmp)', () => { const code = getCode(` import styled from "styled-components"; import Cmp from "./Cmp"; import Title from "./Title"; export default styled(Cmp)\` & > ${'${Title}'} { color: red; } \`; `); expect(code).toMatchSnapshot(); }); it('styled(Cmp).attrs({})', () => { const code = getCode(` import styled from "styled-components"; import Cmp from "./Cmp"; import Title from "./Title"; export default styled(Cmp).attrs(() => ({}))\` & > ${'${Title}'} { color: red; } \`; `); expect(code).toMatchSnapshot(); }); it('styled.h1.attrs({})', () => { const code = getCode(` import styled from "styled-components"; import Title from "./Title"; export default styled.h1.attrs(() => ({}))\` & > ${'${Title}'} { color: red; } \`; `); expect(code).toMatchSnapshot(); }); }); ================================================ FILE: packages/interop/babel.config.js ================================================ const config = require('../../babel.config'); module.exports = config; ================================================ FILE: packages/interop/package.json ================================================ { "name": "@linaria/babel-plugin-interop", "version": "7.0.0", "homepage": "https://github.com/callstack/linaria/tree/master/packages/interop#readme", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "author": { "name": "Anton Evzhakov", "email": "anton@evz.name" }, "main": "lib/index.js", "module": "esm/index.js", "types": "types", "files": [ "types/", "lib/", "esm/" ], "scripts": { "build": "pnpm build:lib && pnpm build:esm && pnpm build:declarations", "build:declarations": "tsc --emitDeclarationOnly --outDir types", "build:esm": "babel src --out-dir esm --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "build:lib": "cross-env NODE_ENV=legacy babel src --out-dir lib --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "test": "jest --config ../../jest.config.js --rootDir .", "typecheck": "tsc --noEmit --composite false", "watch": "pnpm build:lib --watch & pnpm build:esm --watch & pnpm build:declarations --watch" }, "devDependencies": { "@babel/core": "^7.23.5", "@babel/traverse": "^7.23.5", "@babel/types": "^7.23.5", "@types/babel__core": "^7.20.5", "@types/babel__traverse": "^7.20.4", "dedent": "^1.5.1" }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" } } ================================================ FILE: packages/interop/src/index.ts ================================================ import type core from '@babel/core'; import type { NodePath } from '@babel/traverse'; import type { Expression, Identifier, MemberExpression, TaggedTemplateExpression, V8IntrinsicIdentifier, } from '@babel/types'; export declare type Core = typeof core; export default ( { types: t }: Core, config: { library?: string | RegExp } = {} ) => { const library = config.library || 'styled-components'; const isLibrary: (s: string) => boolean = library instanceof RegExp ? (s) => library.test(s) : (s) => s === library; const fixer = (path: NodePath | NodePath) => { if (!t.isTemplateLiteral(path.parent) || path.listKey !== 'expressions') { return; } const original = path.node; path.replaceWithSourceString( "(i => i && i.__wyw_meta ? '.' + i.__wyw_meta.className : i)('placeholder')" ); const args = path.get('arguments'); if (Array.isArray(args)) { args[0]?.replaceWith(original); } }; const visitors = { MemberExpression: fixer, Identifier: fixer, }; return { visitor: { TaggedTemplateExpression(path: NodePath) { const tag = path.get('tag'); let identifier: NodePath | null = null; if (tag.isIdentifier()) { identifier = tag; } else if (tag.isMemberExpression()) { identifier = tag.get('object'); } else if (tag.isCallExpression()) { identifier = tag.get('callee'); } else { return; } if (identifier.isMemberExpression()) { const obj = identifier.get('object'); // it's something like styled().attrs() if (obj.isCallExpression()) { identifier = obj.get('callee'); } else if (obj.isMemberExpression()) { identifier = obj.get('object'); } } if (!identifier.isIdentifier()) { return; } const { scope } = identifier; const binding = scope.getBinding(identifier.node.name); const parent = binding?.path.parentPath ?? null; if (!parent?.isImportDeclaration()) { return; } const importSource = parent.node.source.value; if (isLibrary(importSource)) { path.get('quasi').traverse(visitors); } }, }, }; }; ================================================ FILE: packages/interop/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "paths": {}, "rootDir": "src/" }, "references": [] } ================================================ FILE: packages/linaria/CHANGELOG.md ================================================ # Change Log ## 7.0.1 ### Patch Changes - Updated dependencies [b3331e45] - @linaria/react@7.0.1 ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ### Patch Changes - ebefe2e4: Require Node.js `>=20` (aligned with WyW 1.x). - Updated dependencies [ab11ebb7] - Updated dependencies [654d8590] - @linaria/core@7.0.0 - @linaria/react@7.0.0 - @linaria/server@7.0.0 ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ### Patch Changes - Updated dependencies [bd8d45fd] - Updated dependencies [281ca4f5] - @linaria/react@6.3.0 - @linaria/core@6.3.0 - @linaria/server@6.3.0 ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ### Patch Changes - Updated dependencies [a3dcee2e] - @linaria/core@6.2.0 - @linaria/server@6.2.0 - @linaria/react@6.2.1 ## 6.1.1 ### Patch Changes - Updated dependencies [fd60b5de] - @linaria/react@6.2.0 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ### Patch Changes - Updated dependencies [8d4ebd33] - Updated dependencies [8ba655d3] - @linaria/core@6.1.0 - @linaria/react@6.1.0 - @linaria/server@6.1.0 ## 6.0.0 ### Major Changes - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ### Patch Changes - Updated dependencies [2ac94b99] - @linaria/core@6.0.0 - @linaria/react@6.0.0 - @linaria/server@6.0.0 ## 5.0.5 ### Patch Changes - Updated dependencies [e25e91ff] - @linaria/babel-preset@5.0.4 - @linaria/shaker@5.0.3 - @linaria/rollup@5.0.4 - @linaria/stylelint@5.0.4 - @linaria/webpack4-loader@5.0.4 ## 5.0.4 ### Patch Changes - Updated dependencies [4b083b7c] - @linaria/react@5.0.3 ## 5.0.3 ### Patch Changes - Updated dependencies [5f216d3b] - Updated dependencies [1e889937] - Updated dependencies [4992c14d] - Updated dependencies [15fa87a5] - Updated dependencies [25ba1344] - Updated dependencies [5f216d3b] - @linaria/babel-preset@5.0.3 - @linaria/react@5.0.2 - @linaria/shaker@5.0.2 - @linaria/rollup@5.0.3 - @linaria/stylelint@5.0.3 - @linaria/webpack4-loader@5.0.3 - @linaria/core@5.0.2 ## 5.0.2 ### Patch Changes - Updated dependencies [38796a57] - @linaria/babel-preset@5.0.2 - @linaria/rollup@5.0.2 - @linaria/stylelint@5.0.2 - @linaria/webpack4-loader@5.0.2 ## 5.0.1 ### Patch Changes - Updated dependencies [6fb6eb69] - Updated dependencies [6fb6eb69] - @linaria/babel-preset@5.0.1 - @linaria/shaker@5.0.1 - @linaria/rollup@5.0.1 - @linaria/stylelint@5.0.1 - @linaria/webpack4-loader@5.0.1 - @linaria/core@5.0.1 - @linaria/react@5.0.1 ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 - Updated dependencies [9cb4143d] - Updated dependencies [ae162f46] - Updated dependencies [88e07613] - Updated dependencies [715dc93c] - Updated dependencies [b3ef8c1f] - Updated dependencies [144995f0] - Updated dependencies [f8b9bff5] - Updated dependencies [8a5d734b] - Updated dependencies [aa100453] - Updated dependencies [ea1444f6] - Updated dependencies [9bb782d0] - Updated dependencies [2a1e24a0] - Updated dependencies [cb853e14] - Updated dependencies [e042f96d] - @linaria/babel-preset@5.0.0 - @linaria/core@5.0.0 - @linaria/extractor@5.0.0 - @linaria/react@5.0.0 - @linaria/rollup@5.0.0 - @linaria/server@5.0.0 - @linaria/shaker@5.0.0 - @linaria/stylelint@5.0.0 - @linaria/webpack4-loader@5.0.0 ## 4.5.4 ### Patch Changes - Updated dependencies [10bcd241] - @linaria/babel-preset@4.5.4 - @linaria/rollup@4.5.4 - @linaria/stylelint@4.5.4 - @linaria/webpack4-loader@4.5.4 - @linaria/core@4.5.4 - @linaria/react@4.5.4 - @linaria/shaker@4.5.3 ## 4.5.3 ### Patch Changes - Updated dependencies [79557248] - Updated dependencies [b191f543] - Updated dependencies [e59bf809] - Updated dependencies [520ba8da] - Updated dependencies [ae3727f9] - @linaria/babel-preset@4.5.3 - @linaria/core@4.5.3 - @linaria/react@4.5.3 - @linaria/stylelint@4.5.3 - @linaria/shaker@4.5.2 - @linaria/rollup@4.5.3 - @linaria/webpack4-loader@4.5.3 ## 4.5.2 ### Patch Changes - Updated dependencies [85e74df6] - Updated dependencies [1bf5c5b8] - @linaria/shaker@4.5.1 - @linaria/babel-preset@4.5.2 - @linaria/rollup@4.5.2 - @linaria/webpack4-loader@4.5.2 - @linaria/core@4.5.2 - @linaria/react@4.5.2 - @linaria/stylelint@4.5.2 ## 4.5.1 ### Patch Changes - Updated dependencies [ceca1611] - Updated dependencies [13258306] - @linaria/babel-preset@4.5.1 - @linaria/react@4.5.1 - @linaria/rollup@4.5.1 - @linaria/stylelint@4.5.1 - @linaria/webpack4-loader@4.5.1 - @linaria/core@4.5.1 ## 4.5.0 ### Minor Changes - 16c057df: Breaking Change: Performance Optimization for `styled` When a component is wrapped in `styled`, Linaria needs to determine if that component is already a styled component. To accomplish this, the wrapped component is included in the list of variables for evaluation, along with the interpolated values used in styles. The issue arises when a wrapped component, even if it is not styled, brings along a substantial dependency tree. This situation is particularly evident when using `styled` to style components from third-party UI libraries. To address this problem, Linaria will now examine the import location of the component and check if there is an annotation in the `package.json` file of the package containing the components. This annotation indicates whether the package includes other Linaria components. If there is no such annotation, Linaria will refrain from evaluating the component. Please note that this Breaking Change solely affects developers of component libraries. In order for users to style components from your library, you must include the `linaria.components` property in the library's `package.json` file. This property should have a mask that covers all imported files with components. Here's an example of how to specify it: ```json "linaria": { "components": "**/*" } ``` ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. - Updated dependencies [418e40af] - Updated dependencies [05ad266c] - Updated dependencies [16c057df] - Updated dependencies [af5bb92d] - Updated dependencies [10859924] - @linaria/babel-preset@4.5.0 - @linaria/shaker@4.5.0 - @linaria/react@4.5.0 - @linaria/core@4.5.0 - @linaria/extractor@4.5.0 - @linaria/rollup@4.5.0 - @linaria/server@4.5.0 - @linaria/stylelint@4.5.0 - @linaria/webpack4-loader@4.5.0 ## 4.1.17 ### Patch Changes - Updated dependencies [821a6819] - Updated dependencies [54ab61b2] - @linaria/babel-preset@4.4.5 - @linaria/react@4.3.8 - @linaria/shaker@4.2.11 - @linaria/rollup@4.3.8 - @linaria/stylelint@4.1.17 - @linaria/webpack4-loader@4.1.17 - @linaria/core@4.2.10 ## 4.1.16 ### Patch Changes - Updated dependencies [1c3f309d] - Updated dependencies [dbe250b5] - Updated dependencies [34029088] - Updated dependencies [a62e7ba6] - @linaria/babel-preset@4.4.4 - @linaria/react@4.3.7 - @linaria/shaker@4.2.10 - @linaria/core@4.2.9 - @linaria/rollup@4.3.7 - @linaria/stylelint@4.1.16 - @linaria/webpack4-loader@4.1.16 ## 4.1.15 ### Patch Changes - Updated dependencies [a3ad617f] - @linaria/react@4.3.6 - @linaria/babel-preset@4.4.3 - @linaria/core@4.2.8 - @linaria/rollup@4.3.6 - @linaria/stylelint@4.1.15 - @linaria/webpack4-loader@4.1.15 ## 4.1.14 ### Patch Changes - Updated dependencies [13f0b416] - Updated dependencies [f9df4ed8] - @linaria/rollup@4.3.5 - @linaria/babel-preset@4.4.2 - @linaria/stylelint@4.1.14 - @linaria/webpack4-loader@4.1.14 - @linaria/core@4.2.7 - @linaria/react@4.3.5 - @linaria/shaker@4.2.9 ## 4.1.13 ### Patch Changes - Updated dependencies [917db446] - Updated dependencies [57c0dc4f] - @linaria/babel-preset@4.4.1 - @linaria/rollup@4.3.4 - @linaria/stylelint@4.1.13 - @linaria/webpack4-loader@4.1.13 ## 4.1.12 ### Patch Changes - Updated dependencies [b27f328f] - Updated dependencies [9cf41fae] - Updated dependencies [860b8d21] - Updated dependencies [af783273] - Updated dependencies [28f3f93d] - Updated dependencies [1d4d6833] - Updated dependencies [71a5b351] - Updated dependencies [cf1d6611] - Updated dependencies [2d3a741f] - Updated dependencies [61d49a39] - @linaria/shaker@4.2.8 - @linaria/babel-preset@4.4.0 - @linaria/rollup@4.3.3 - @linaria/stylelint@4.1.12 - @linaria/webpack4-loader@4.1.12 - @linaria/core@4.2.6 - @linaria/react@4.3.4 ## 4.1.11 ### Patch Changes - Updated dependencies [3ce985e0] - Updated dependencies [77bcf2e7] - @linaria/babel-preset@4.3.3 - @linaria/server@4.1.0 - @linaria/rollup@4.3.2 - @linaria/stylelint@4.1.11 - @linaria/webpack4-loader@4.1.11 - @linaria/core@4.2.5 - @linaria/react@4.3.3 - @linaria/shaker@4.2.7 ## 4.1.10 ### Patch Changes - Updated dependencies [edbf3cf1] - Updated dependencies [315f0366] - @linaria/rollup@4.3.1 - @linaria/babel-preset@4.3.2 - @linaria/core@4.2.4 - @linaria/react@4.3.2 - @linaria/shaker@4.2.6 - @linaria/stylelint@4.1.10 - @linaria/webpack4-loader@4.1.10 ## 4.1.9 ### Patch Changes - Updated dependencies [e2224348] - Updated dependencies [655c4f2c] - Updated dependencies [922f20d6] - Updated dependencies [5edde648] - Updated dependencies [e6420897] - Updated dependencies [b9e49b74] - @linaria/shaker@4.2.5 - @linaria/rollup@4.3.0 - @linaria/react@4.3.1 - @linaria/babel-preset@4.3.1 - @linaria/core@4.2.3 - @linaria/stylelint@4.1.9 - @linaria/webpack4-loader@4.1.9 ## 4.1.8 ### Patch Changes - Updated dependencies [63f56d47] - Updated dependencies [963508a2] - Updated dependencies [c26d4667] - @linaria/babel-preset@4.3.0 - @linaria/react@4.3.0 - @linaria/shaker@4.2.4 - @linaria/rollup@4.2.2 - @linaria/stylelint@4.1.8 - @linaria/webpack4-loader@4.1.8 - @linaria/core@4.2.2 ## 4.1.7 ### Patch Changes - Updated dependencies [cc2f87a8] - Updated dependencies [6de22792] - @linaria/babel-preset@4.2.4 - @linaria/shaker@4.2.3 - @linaria/react@4.2.1 - @linaria/rollup@4.2.1 - @linaria/stylelint@4.1.7 - @linaria/webpack4-loader@4.1.7 - @linaria/core@4.2.1 ## 4.1.6 ### Patch Changes - Updated dependencies [1e88e95d] - Updated dependencies [9111b4ea] - @linaria/core@4.2.0 - @linaria/react@4.2.0 - @linaria/rollup@4.2.0 - @linaria/babel-preset@4.2.3 - @linaria/stylelint@4.1.6 - @linaria/webpack4-loader@4.1.6 ## 4.1.5 ### Patch Changes - Updated dependencies [8a8be242] - Updated dependencies [2906ec1c] - Updated dependencies [8a8be242] - Updated dependencies [c2092f61] - Updated dependencies [08304e09] - Updated dependencies [87ffe61c] - @linaria/shaker@4.2.2 - @linaria/webpack4-loader@4.1.5 - @linaria/babel-preset@4.2.2 - @linaria/rollup@4.1.5 - @linaria/core@4.1.4 - @linaria/react@4.1.5 - @linaria/stylelint@4.1.5 ## 4.1.4 ### Patch Changes - Updated dependencies [24b4a4bd] - @linaria/babel-preset@4.2.1 - @linaria/shaker@4.2.1 - @linaria/rollup@4.1.4 - @linaria/stylelint@4.1.4 - @linaria/webpack4-loader@4.1.4 - @linaria/core@4.1.3 - @linaria/react@4.1.4 ## 4.1.3 ### Patch Changes - Updated dependencies [8590e134] - Updated dependencies [f7351b09] - Updated dependencies [c0bd271a] - Updated dependencies [8f90fa75] - Updated dependencies [a5169f16] - Updated dependencies [ac0991a6] - @linaria/babel-preset@4.2.0 - @linaria/shaker@4.2.0 - @linaria/react@4.1.3 - @linaria/webpack4-loader@4.1.3 - @linaria/rollup@4.1.3 - @linaria/stylelint@4.1.3 - @linaria/core@4.1.2 ## 4.1.2 ### Patch Changes - Updated dependencies [008a5d13] - Updated dependencies [3c593aa8] - @linaria/webpack4-loader@4.1.2 - @linaria/babel-preset@4.1.2 - @linaria/rollup@4.1.2 - @linaria/stylelint@4.1.2 - @linaria/core@4.1.1 - @linaria/shaker@4.1.2 - @linaria/react@4.1.2 ## 4.1.1 ### Patch Changes - Updated dependencies [21ba7a44] - Updated dependencies [21ba7a44] - Updated dependencies [21ba7a44] - Updated dependencies [2abc55b3] - Updated dependencies [21ba7a44] - @linaria/babel-preset@4.1.1 - @linaria/react@4.1.1 - @linaria/shaker@4.1.1 - @linaria/rollup@4.1.1 - @linaria/stylelint@4.1.1 - @linaria/webpack4-loader@4.1.1 ## 4.1.0 ### Patch Changes - Updated dependencies [92f6d871] - @linaria/babel-preset@4.1.0 - @linaria/rollup@4.1.0 - @linaria/stylelint@4.1.0 - @linaria/webpack4-loader@4.1.0 - @linaria/core@4.1.0 - @linaria/shaker@4.1.0 - @linaria/react@4.1.0 ## 4.0.0 ### Major Changes - bc0cbeea: A completely new async mode with native support for Vite, Rollup, esbuild and Webpack resolvers. BREAKING CHANGES: Despite the fact, that it should be fully compatible with 3.0 and 2.0 branches, the new version of styles evaluator can have some serious bugs which can make your project unbuildable (however, since there is no runtime, if the build is finished successfully, everything will continue work as it was on 2.0 and 3.0). If you face some problems please let us know and we will fix it as soon as possible. ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - ea41d440: New package @linaria/tags that contains all abstract logic for tags processors. - Updated dependencies [f0cddda4] - @linaria/babel-preset@4.0.0 - @linaria/core@4.0.0 - @linaria/extractor@4.0.0 - @linaria/react@4.0.0 - @linaria/rollup@4.0.0 - @linaria/server@4.0.0 - @linaria/shaker@4.0.0 - @linaria/stylelint@4.0.0 - @linaria/webpack4-loader@4.0.0 ## 3.0.0-beta.21 ### Patch Changes - Updated dependencies [17c83e34] - @linaria/react@3.0.0-beta.21 - @linaria/babel-preset@3.0.0-beta.21 - @linaria/core@3.0.0-beta.21 - @linaria/extractor@3.0.0-beta.21 - @linaria/rollup@3.0.0-beta.21 - @linaria/shaker@3.0.0-beta.21 - @linaria/stylelint@3.0.0-beta.21 - @linaria/webpack4-loader@3.0.0-beta.21 ## 3.0.0-beta.20 ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - Updated dependencies - @linaria/babel-preset@3.0.0-beta.20 - @linaria/core@3.0.0-beta.20 - @linaria/extractor@3.0.0-beta.20 - @linaria/react@3.0.0-beta.20 - @linaria/rollup@3.0.0-beta.20 - @linaria/server@3.0.0-beta.20 - @linaria/shaker@3.0.0-beta.20 - @linaria/stylelint@3.0.0-beta.20 - @linaria/webpack4-loader@3.0.0-beta.20 # [3.0.0-beta.19](https://github.com/callstack/linaria/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2022-06-03) ### Features - **babel:** api for custom tags ([#976](https://github.com/callstack/linaria/issues/976)) ([3285ccc](https://github.com/callstack/linaria/commit/3285ccc1d00449b78b3fc74087528cd38cbdd116)) - **babel:** new way for detecting tag imports ([#974](https://github.com/callstack/linaria/issues/974)) ([3305cfb](https://github.com/callstack/linaria/commit/3305cfb0c0f65abdacceeb7e6bad118c59f7d551)) # [3.0.0-beta.18](https://github.com/callstack/linaria/compare/v3.0.0-beta.17...v3.0.0-beta.18) (2022-04-01) **Note:** Version bump only for package linaria # [3.0.0-beta.17](https://github.com/callstack/linaria/compare/v3.0.0-beta.16...v3.0.0-beta.17) (2021-12-27) **Note:** Version bump only for package linaria # [3.0.0-beta.16](https://github.com/callstack/linaria/compare/v3.0.0-beta.15...v3.0.0-beta.16) (2021-12-01) **Note:** Version bump only for package linaria # [3.0.0-beta.15](https://github.com/callstack/linaria/compare/v3.0.0-beta.14...v3.0.0-beta.15) (2021-11-29) **Note:** Version bump only for package linaria # [3.0.0-beta.14](https://github.com/callstack/linaria/compare/v3.0.0-beta.13...v3.0.0-beta.14) (2021-11-05) **Note:** Version bump only for package linaria # [3.0.0-beta.13](https://github.com/callstack/linaria/compare/v3.0.0-beta.12...v3.0.0-beta.13) (2021-09-13) **Note:** Version bump only for package linaria # [3.0.0-beta.12](https://github.com/callstack/linaria/compare/v3.0.0-beta.11...v3.0.0-beta.12) (2021-08-31) **Note:** Version bump only for package linaria # [3.0.0-beta.11](https://github.com/callstack/linaria/compare/v3.0.0-beta.10...v3.0.0-beta.11) (2021-08-08) **Note:** Version bump only for package linaria # [3.0.0-beta.10](https://github.com/callstack/linaria/compare/v3.0.0-beta.9...v3.0.0-beta.10) (2021-07-24) **Note:** Version bump only for package linaria # [3.0.0-beta.9](https://github.com/callstack/linaria/compare/v3.0.0-beta.8...v3.0.0-beta.9) (2021-07-23) **Note:** Version bump only for package linaria # [3.0.0-beta.8](https://github.com/callstack/linaria/compare/v3.0.0-beta.7...v3.0.0-beta.8) (2021-07-18) **Note:** Version bump only for package linaria # [3.0.0-beta.7](https://github.com/callstack/linaria/compare/v3.0.0-beta.6...v3.0.0-beta.7) (2021-06-24) **Note:** Version bump only for package linaria # [3.0.0-beta.6](https://github.com/callstack/linaria/compare/v3.0.0-beta.5...v3.0.0-beta.6) (2021-06-06) **Note:** Version bump only for package linaria # [3.0.0-beta.5](https://github.com/callstack/linaria/compare/v3.0.0-beta.4...v3.0.0-beta.5) (2021-05-31) **Note:** Version bump only for package linaria # [3.0.0-beta.4](https://github.com/callstack/linaria/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2021-05-07) **Note:** Version bump only for package linaria # [3.0.0-beta.3](https://github.com/callstack/linaria/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2021-04-20) **Note:** Version bump only for package linaria # [3.0.0-beta.2](https://github.com/callstack/linaria/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2021-04-11) **Note:** Version bump only for package linaria ================================================ FILE: packages/linaria/README.md ================================================

Linaria

Zero-runtime CSS in JS library.

--- ### 📖 Please refer to the [GitHub](https://github.com/callstack/linaria#readme) for full documentation. ## Features - Write CSS in JS, but with **zero runtime**, CSS is extracted to CSS files during build - Familiar **CSS syntax** with Sass like nesting - Use **dynamic prop based styles** with the React bindings, uses CSS variables behind the scenes - Easily find where the style was defined with **CSS sourcemaps** - **Lint your CSS** in JS with [stylelint](https://github.com/stylelint/stylelint) - Use **JavaScript for logic**, no CSS preprocessor needed - Optionally use any **CSS preprocessor** such as Sass or PostCSS **[Why use Linaria](../../docs/BENEFITS.md)** ## Installation ```sh npm install @linaria/core @linaria/react @linaria/babel-preset ``` or ```sh yarn add @linaria/core @linaria/react @linaria/babel-preset ``` ================================================ FILE: packages/linaria/babel/package.json ================================================ { "main": "../lib/babel.js", "module": "../esm/babel.js", "types": "../types/babel.d.ts" } ================================================ FILE: packages/linaria/babel.config.js ================================================ const config = require('../../babel.config'); module.exports = config; ================================================ FILE: packages/linaria/evaluators/package.json ================================================ { "main": "../lib/evaluators.js", "module": "../esm/evaluators.js", "types": "../types/evaluators.d.ts" } ================================================ FILE: packages/linaria/loader/package.json ================================================ { "main": "../lib/webpack4-loader.js", "module": "../esm/webpack4-loader.js", "types": "../types/webpack4-loader.d.ts" } ================================================ FILE: packages/linaria/package.json ================================================ { "name": "linaria", "version": "7.0.1", "description": "Blazing fast zero-runtime CSS in JS library", "keywords": [ "babel", "babel-plugin", "css", "css-in-js", "linaria", "react", "styled-components" ], "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "main": "lib/core.js", "module": "esm/core.js", "types": "types/core.d.ts", "files": [ "babel", "evaluators", "loader", "react", "rollup", "server", "stylelint-config", "types/", "lib/", "esm/" ], "wyw-in-js": { "tags": { "css": "@linaria/core/processors/css", "styled": "@linaria/react/processors/styled" } }, "scripts": { "build": "pnpm build:lib && pnpm build:esm && pnpm build:declarations", "build:declarations": "tsc --emitDeclarationOnly --outDir types", "build:esm": "babel src --out-dir esm --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "build:lib": "cross-env NODE_ENV=legacy babel src --out-dir lib --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "typecheck": "tsc --noEmit --composite false", "watch": "pnpm build:lib --watch & pnpm build:esm --watch & pnpm build:declarations --watch" }, "dependencies": { "@linaria/core": "workspace:^", "@linaria/react": "workspace:^", "@linaria/server": "workspace:^" }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" } } ================================================ FILE: packages/linaria/react/package.json ================================================ { "main": "../lib/react.js", "module": "../esm/react.js", "types": "../types/react.d.ts" } ================================================ FILE: packages/linaria/rollup/package.json ================================================ { "main": "../lib/rollup.js", "module": "../esm/rollup.js", "types": "../types/rollup.d.ts" } ================================================ FILE: packages/linaria/server/package.json ================================================ { "main": "../lib/server.js", "module": "../esm/server.js", "types": "../types/server.d.ts" } ================================================ FILE: packages/linaria/src/core.ts ================================================ export * from '@linaria/core'; ================================================ FILE: packages/linaria/src/react.ts ================================================ export * from '@linaria/react'; ================================================ FILE: packages/linaria/src/server.ts ================================================ export * from '@linaria/server'; ================================================ FILE: packages/linaria/stylelint-config/package.json ================================================ { "main": "../lib/stylelint.js", "module": "../esm/stylelint.js", "types": "../types/stylelint.d.ts" } ================================================ FILE: packages/linaria/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "paths": {}, "rootDir": "src/" }, "references": [ { "path": "../core" }, { "path": "../react" }, { "path": "../server" } ] } ================================================ FILE: packages/postcss-linaria/CHANGELOG.md ================================================ # Change Log ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ### Patch Changes - b04f025e: Fix `@linaria/postcss-linaria` placeholder naming and source location correction, and ensure stylelint integration resolves configs correctly. ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ## 6.0.0 ### Major Changes - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ### Patch Changes - 63392f9a: Fix the expressions in at-rule parameters and rules with functions. Fixes #1074 ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 ## 4.5.1 ### Patch Changes - e59bf809: Shaker mistakenly counts references in types as valuable and keeps referenced variables alive. ## 4.5.0 ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. ## 4.1.5 ### Patch Changes - 5edde648: Upgrade Babel to support TypeScript 4.9. Fixes #1133. - e6420897: Update patch version so npm will pick up readme change ## 4.1.4 ### Patch Changes - 4c2efaa9: Only lint when file can be parsed by babel, reduce noisey errors during dev ## 4.1.3 ### Patch Changes - ce36da42: Add stylelint v14 custom syntax support ================================================ FILE: packages/postcss-linaria/README.md ================================================

Linaria

Zero-runtime CSS in JS library.

--- ## Setup Please check the Linaria [linting documentation](https://github.com/callstack/linaria/blob/master/docs/LINTING.md) for setup instructions. ## Acknowledgements This project wouldn't have been possible without the following libraries or the people behind them. - [postcss-lit](https://github.com/43081j/postcss-lit) (One of the first CSS-in-JS custom syntaxes) - [stylelint](https://stylelint.io/) - [postcss](https://postcss.org/) ### 📖 Please refer to [GitHub](https://github.com/callstack/linaria#readme) for full documentation. ================================================ FILE: packages/postcss-linaria/__tests__/__utils__/index.ts ================================================ import type { Document, Node } from 'postcss'; import { parse } from '../../src/parse'; export function createTestAst(source: string): { ast: Document; source: string; } { const ast = parse(source) as Document; return { ast, source }; } export function getSourceForNodeByLoc(source: string, node: Node): string { const loc = node.source; if (!loc || !loc.start || !loc.end) { return ''; } const lines = source.split(/\r\n|\n/); const result: string[] = []; const startLineIndex = loc.start.line - 1; const endLineIndex = loc.end.line - 1; for (let i = startLineIndex; i < loc.end.line; i++) { const line = lines[i]; if (line) { let offsetStart = 0; let offsetEnd = line.length; if (i === startLineIndex) { offsetStart = loc.start.column - 1; } if (i === endLineIndex) { offsetEnd = loc.end.column; } result.push(line.substring(offsetStart, offsetEnd)); } } return result.join('\n'); } export function getSourceForNodeByRange(source: string, node: Node): string { if (!node.source || !node.source.start || !node.source.end) { return ''; } return source.substring(node.source.start.offset, node.source.end.offset + 1); } export const sourceWithExpression = { ruleset: ` const expr = 'color: black'; css\` $\{expr} \`; `, singleLineRuleset: ` css\` \${expr0} { \${expr1}: \${expr2} } \` `, selectorOrAtRule: ` const expr = '@media (min-width: 100px)'; css\` $\{expr} { color: black; } \`; `, selectorBeforeExpression: ` const expr = '.classname'; css\` .example $\{expr} { color: black; } \`; `, selectorAfterExpression: ` const expr = '.classname'; css\` $\{expr} .example { color: black; } \`; `, declarationProperty: ` const expr = 'color'; css\` \${expr}: black; \`; `, declarationValue: ` const expr = 'black'; css\` color: \${expr}; \`; `, declarationMultipleValues: ` const expr1 = '10px'; const expr2 = '5px'; css\` margin: \${expr1} \${expr2} \${expr1} \${expr2}; \`; `, declarationMixedValues: ` const expr1 = '10px'; const expr2 = '5px'; css\` margin: \${expr1} 7px \${expr2} 9px; \`; `, combo: ` css\` \${expr0} .foo { \${expr1}: \${expr2}; } \${expr3} { .bar { color: black; } } \${expr4} \`; `, }; ================================================ FILE: packages/postcss-linaria/__tests__/locationCorrection.test.ts ================================================ import type { Root, Rule, Declaration, Comment } from 'postcss'; import { createTestAst, getSourceForNodeByRange, getSourceForNodeByLoc, sourceWithExpression, } from './__utils__'; const { ruleset, selectorOrAtRule, selectorBeforeExpression, selectorAfterExpression, declarationProperty, declarationValue, declarationMultipleValues, declarationMixedValues, } = sourceWithExpression; describe('locationCorrection', () => { it('should translate basic CSS positions', () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; } \`; `); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; const color = rule.nodes[0] as Declaration; expect(color.type).toEqual('decl'); expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( '.foo { color: hotpink; }' ); expect(getSourceForNodeByLoc(source, color)).toEqual('color: hotpink;'); expect(getSourceForNodeByRange(source, rule)).toEqual( '.foo { color: hotpink; }' ); expect(getSourceForNodeByRange(source, color)).toEqual('color: hotpink;'); }); it('should handle multi-line CSS', () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; } \`; `); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; const color = rule.nodes[0] as Declaration; expect(color.type).toEqual('decl'); expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( `.foo { color: hotpink; }` ); expect(getSourceForNodeByLoc(source, color)).toEqual('color: hotpink;'); expect(getSourceForNodeByRange(source, rule)).toEqual( `.foo { color: hotpink; }` ); expect(getSourceForNodeByRange(source, color)).toEqual('color: hotpink;'); }); it('should handle multi-line CSS with expressions', () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; $\{expr} } \`; `); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; const color = rule.nodes[0] as Declaration; expect(color.type).toEqual('decl'); expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( `.foo { color: hotpink; $\{expr} }` ); expect(getSourceForNodeByLoc(source, color)).toEqual('color: hotpink;'); expect(getSourceForNodeByRange(source, rule)).toEqual( `.foo { color: hotpink; $\{expr} }` ); expect(getSourceForNodeByRange(source, color)).toEqual('color: hotpink;'); }); it('should handle single line expressions', () => { const { source, ast } = createTestAst(`css\`.foo { color: \${expr}; }\`;`); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; const color = rule.nodes[0] as Declaration; expect(color.type).toEqual('decl'); expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( '.foo { color: ${expr}; }' ); expect(getSourceForNodeByLoc(source, color)).toEqual('color: ${expr};'); expect(getSourceForNodeByRange(source, rule)).toEqual( '.foo { color: ${expr}; }' ); expect(getSourceForNodeByRange(source, color)).toEqual('color: ${expr};'); }); it('should handle multi-line CSS with value expression', () => { const { source, ast } = createTestAst(` css\` .foo { color: $\{expr1}; } \`; `); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; const color = rule.nodes[0] as Declaration; expect(color.type).toEqual('decl'); expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( `.foo { color: $\{expr1}; }` ); expect(getSourceForNodeByLoc(source, color)).toEqual('color: ${expr1};'); expect(getSourceForNodeByRange(source, rule)).toEqual( `.foo { color: $\{expr1}; }` ); expect(getSourceForNodeByRange(source, color)).toEqual( 'color: ${expr1};\n' ); }); it('should stringify a ruleset expression', () => { const { source, ast } = createTestAst(ruleset); const node = (ast.nodes[0] as Root).nodes[0] as Comment; expect(node.type).toEqual('comment'); expect(getSourceForNodeByLoc(source, node)).toEqual('${expr}'); expect(getSourceForNodeByRange(source, node)).toEqual('${expr}'); }); it('should stringify a selector or at-rule expression', () => { const { source, ast } = createTestAst(selectorOrAtRule); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( `$\{expr} { color: black; }` ); expect(getSourceForNodeByRange(source, rule)).toEqual( `$\{expr} { color: black; }` ); }); it('should stringify selector expression with a selector before the expression', () => { const { source, ast } = createTestAst(selectorBeforeExpression); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( `.example $\{expr} { color: black; }` ); expect(getSourceForNodeByRange(source, rule)).toEqual( `.example $\{expr} { color: black; }` ); }); it('should stringify selector expression with a selector after the expression', () => { const { source, ast } = createTestAst(selectorAfterExpression); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( `$\{expr} .example { color: black; }` ); expect(getSourceForNodeByRange(source, rule)).toEqual( `$\{expr} .example { color: black; }` ); }); it('should stringify a declaration property expression', () => { const { source, ast } = createTestAst(declarationProperty); const color = (ast.nodes[0] as Root).nodes[0] as Declaration; expect(color.type).toEqual('decl'); expect(getSourceForNodeByLoc(source, color)).toEqual('${expr}: black;'); expect(getSourceForNodeByRange(source, color)).toEqual('${expr}: black;'); }); it('should stringify a declaration value with a single expression', () => { const { source, ast } = createTestAst(declarationValue); const color = (ast.nodes[0] as Root).nodes[0] as Declaration; expect(color.type).toEqual('decl'); expect(getSourceForNodeByLoc(source, color)).toEqual('color: ${expr};'); expect(getSourceForNodeByRange(source, color)).toEqual('color: ${expr};'); }); it('should stringify a declaration value with multiple expressions', () => { const { source, ast } = createTestAst(declarationMultipleValues); const margin = (ast.nodes[0] as Root).nodes[0] as Declaration; expect(margin.type).toEqual('decl'); expect(getSourceForNodeByLoc(source, margin)).toEqual( 'margin: ${expr1} ${expr2} ${expr1} ${expr2};' ); expect(getSourceForNodeByRange(source, margin)).toEqual( 'margin: ${expr1} ${expr2} ${expr1} ${expr2};' ); }); it('should stringify a decl value with some but not all values as expressions', () => { const { source, ast } = createTestAst(declarationMixedValues); const margin = (ast.nodes[0] as Root).nodes[0] as Declaration; expect(margin.type).toEqual('decl'); expect(getSourceForNodeByLoc(source, margin)).toEqual( 'margin: ${expr1} 7px ${expr2} 9px;' ); expect(getSourceForNodeByRange(source, margin)).toEqual( 'margin: ${expr1} 7px ${expr2} 9px;' ); }); it('should account for code before', () => { const { source, ast } = createTestAst(` const foo = bar + baz; css\` .foo { color: hotpink; } \`; `); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; const color = rule.nodes[0] as Declaration; expect(color.type).toEqual('decl'); expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( '.foo { color: hotpink; }' ); expect(getSourceForNodeByLoc(source, color)).toEqual('color: hotpink;'); expect(getSourceForNodeByRange(source, rule)).toEqual( '.foo { color: hotpink; }' ); expect(getSourceForNodeByRange(source, color)).toEqual('color: hotpink;'); }); it('should account for mixed indentation', () => { const { source, ast } = createTestAst(` css\` .foo { $\{expr}: hotpink; } \`; `); const rule = (ast.nodes[0] as Root).nodes[0] as Rule; const color = rule.nodes[0] as Declaration; expect(color.type).toEqual('decl'); expect(rule.type).toEqual('rule'); expect(getSourceForNodeByLoc(source, rule)).toEqual( '.foo { ${expr}: hotpink; }' ); expect(getSourceForNodeByLoc(source, color)).toEqual('${expr}: hotpink;'); expect(getSourceForNodeByRange(source, rule)).toEqual( '.foo { ${expr}: hotpink; }' ); expect(getSourceForNodeByRange(source, color)).toEqual('${expr}: hotpink;'); }); }); ================================================ FILE: packages/postcss-linaria/__tests__/parse.test.ts ================================================ import type { Root, Rule, Declaration } from 'postcss'; import { placeholderText } from '../src/util'; import { createTestAst, sourceWithExpression } from './__utils__'; const { ruleset, singleLineRuleset, selectorOrAtRule, selectorBeforeExpression, selectorAfterExpression, declarationProperty, declarationValue, declarationMultipleValues, declarationMixedValues, combo, } = sourceWithExpression; describe('parse', () => { describe('expressions', () => { it('should parse a ruleset expression', () => { const { ast } = createTestAst(ruleset); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " /* ${placeholderText}:0 */ " `); }); it('should parse a single line ruleset expression', () => { const { ast } = createTestAst(singleLineRuleset); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " .${placeholderText}0 { --${placeholderText}1: ${placeholderText}2 } " `); }); it('should parse a selector or at-rule expression', () => { const { ast } = createTestAst(selectorOrAtRule); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " .${placeholderText}0 { color: black; } " `); }); it('should parse a selector expression with selectors before expression', () => { const { ast } = createTestAst(selectorBeforeExpression); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " .example .${placeholderText}0 { color: black; } " `); }); it('should parse a selector expression with selectors after expression', () => { const { ast } = createTestAst(selectorAfterExpression); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " .${placeholderText}0 .example { color: black; } " `); }); it('should parse a declaration property expression', () => { const { ast } = createTestAst(declarationProperty); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " --${placeholderText}0: black; " `); }); it('should parse a declaration value with a single expression', () => { const { ast } = createTestAst(declarationValue); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " color: ${placeholderText}0; " `); }); it('should parse a declaration value with multiple expressions', () => { const { ast } = createTestAst(declarationMultipleValues); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " margin: ${placeholderText}0 ${placeholderText}1 ${placeholderText}2 ${placeholderText}3; " `); }); it('should parse a decl value with some but not all values as expressions', () => { const { ast } = createTestAst(declarationMixedValues); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " margin: ${placeholderText}0 7px ${placeholderText}1 9px; " `); }); it('should parse a combinations of all expressions', () => { const { ast } = createTestAst(combo); const root = ast.nodes[0] as Root; expect(root.source?.input.css).toMatchInlineSnapshot(` " /* ${placeholderText}:0 */ .foo { --${placeholderText}1: ${placeholderText}2; } .${placeholderText}3 { .bar { color: black; } } /* ${placeholderText}:4 */ " `); }); }); describe('languages', () => { it('should parse css', () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; } \`; `); expect(ast.nodes.length).toEqual(1); const root = ast.nodes[0] as Root; const rule = root.nodes[0] as Rule; const colour = rule.nodes[0] as Declaration; expect(ast.type).toEqual('document'); expect(root.type).toEqual('root'); expect(rule.type).toEqual('rule'); expect(colour.type).toEqual('decl'); expect(root.raws.codeBefore).toEqual('\n css`\n'); expect(root.parent).toEqual(ast); expect(root.raws.codeAfter).toEqual('`;\n '); expect(ast.source!.start).toEqual({ line: 1, column: 1, offset: 0, }); expect(ast.source!.input.css).toEqual(source); }); it('should parse javascript', () => { const { ast } = createTestAst(` const someObj = {a: {b: 2}}; const someValue = someObj?.a?.b ?? 3; css\` .foo { color: hotpink; } \`; `); expect(ast.nodes.length).toEqual(1); const root = ast.nodes[0] as Root; const rule = root.nodes[0] as Rule; const color = rule.nodes[0] as Declaration; expect(ast.type).toEqual('document'); expect(root.type).toEqual('root'); expect(rule.type).toEqual('rule'); expect(color.type).toEqual('decl'); }); it('should parse javascript without any CSS', () => { const { source, ast } = createTestAst(` const foo = 'bar'; `); expect(ast.type).toEqual('document'); expect(ast.nodes.length).toEqual(0); expect(ast.source!.start).toEqual({ line: 1, column: 1, offset: 0, }); expect(ast.source!.input.css).toEqual(source); }); it('should parse typescript', () => { const { ast } = createTestAst(` function doStuff(x: number, y: number): void {} css\` .foo { color: hotpink; } \`; `); expect(ast.nodes.length).toEqual(1); const root = ast.nodes[0] as Root; const rule = root.nodes[0] as Rule; const color = rule.nodes[0] as Declaration; expect(ast.type).toEqual('document'); expect(root.type).toEqual('root'); expect(rule.type).toEqual('rule'); expect(color.type).toEqual('decl'); }); it('should parse jsx', () => { const { ast } = createTestAst(` import React from 'react'; import { css } from 'linaria'; const container = css\` color: hotpink; \` const HelloWorld = () => { const cx = useCx(); return (
Hello World
); } export default HelloWorld; `); expect(ast.type).toEqual('document'); const root = ast.nodes[0] as Root; expect(root.type).toEqual('root'); expect(root.source!.input.css).toEqual(' color: hotpink;\n'); }); it('should parse styled api', () => { const { source, ast } = createTestAst(` const StyledSpan = styled.span\` color: black; \`; `); expect(ast.nodes.length).toEqual(1); const root = ast.nodes[0] as Root; const color = root.nodes[0] as Declaration; expect(ast.type).toEqual('document'); expect(root.type).toEqual('root'); expect(color.type).toEqual('decl'); expect(root.raws.codeBefore).toEqual( '\n const StyledSpan = styled.span`\n' ); expect(root.parent).toEqual(ast); expect(root.raws.codeAfter).toEqual('`;\n '); expect(ast.source!.start).toEqual({ line: 1, column: 1, offset: 0, }); expect(ast.source!.input.css).toEqual(source); }); it('should parse styled api with props', () => { const { source, ast } = createTestAst(` const StyledSpan = styled.span\` color: \${(props) => props.color}; \`; `); expect(ast.nodes.length).toEqual(1); const root = ast.nodes[0] as Root; const color = root.nodes[0] as Declaration; expect(ast.type).toEqual('document'); expect(root.type).toEqual('root'); expect(color.type).toEqual('decl'); expect(root.raws.codeBefore).toEqual( '\n const StyledSpan = styled.span`\n' ); expect(root.parent).toEqual(ast); expect(root.raws.codeAfter).toEqual('`;\n '); expect(ast.source!.start).toEqual({ line: 1, column: 1, offset: 0, }); expect(ast.source!.input.css).toEqual(source); }); it('should ignore non-css templates', () => { const { source, ast } = createTestAst(` html\`
\`; `); expect(ast.type).toEqual('document'); expect(ast.nodes.length).toEqual(0); expect(ast.source!.start).toEqual({ line: 1, column: 1, offset: 0, }); expect(ast.source!.input.css).toEqual(source); }); }); describe('formats', () => { it('should parse multiple stylesheets', () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; } \`; css\`.bar: { background: lime; }\`; `); expect(ast.nodes.length).toEqual(2); const root1 = ast.nodes[0] as Root; const root2 = ast.nodes[1] as Root; expect(root1.type).toEqual('root'); expect(root1.raws.codeBefore).toEqual('\n css`\n'); expect(root1.raws.codeAfter).toEqual(undefined); expect(root1.parent).toEqual(ast); expect(root2.type).toEqual('root'); expect(root2.raws.codeBefore).toEqual('`;\n\n css`'); expect(root2.raws.codeAfter).toEqual('`;\n '); expect(root2.parent).toEqual(ast); expect(ast.source!.start).toEqual({ line: 1, column: 1, offset: 0, }); expect(ast.source!.input.css).toEqual(source); }); it('should parse multiple stylesheets indented differently', () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; } \`; const classNames = { container: css\` .bar: { background: lime; } \`, }; `); expect(ast.nodes.length).toEqual(2); const root1 = ast.nodes[0] as Root; const root2 = ast.nodes[1] as Root; expect(root1.type).toEqual('root'); expect(root1.raws.codeBefore).toEqual('\n css`\n'); expect(root1.raws.codeAfter).toEqual(undefined); expect(root1.parent).toEqual(ast); expect(root2.type).toEqual('root'); expect(root2.raws.codeBefore).toEqual( '`;\n const classNames = {\n container: css`\n' ); expect(root2.raws.codeAfter).toEqual('`,\n };\n '); expect(root2.parent).toEqual(ast); expect(ast.source!.start).toEqual({ line: 1, column: 1, offset: 0, }); expect(ast.source!.input.css).toEqual(source); }); it('should parse multi-line stylesheets', async () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; } \`; `); const root = ast.nodes[0] as Root; const rule = root.nodes[0] as Rule; const colour = rule.nodes[0] as Declaration; expect(ast.type).toEqual('document'); expect(root.type).toEqual('root'); expect(rule.type).toEqual('rule'); expect(colour.type).toEqual('decl'); expect(root.raws.codeBefore).toEqual('\n css`\n'); expect(root.parent).toEqual(ast); expect(root.raws.codeAfter).toEqual('`;\n '); expect(ast.source!.start).toEqual({ line: 1, column: 1, offset: 0, }); expect(ast.source!.input.css).toEqual(source); }); }); it('should return empty document if babel cannot parse file', () => { const { ast } = createTestAst(`this is not valid source code for a file`); expect(ast.type).toEqual('document'); expect(ast.raws).toEqual({}); expect(ast.nodes.length).toEqual(0); }); }); ================================================ FILE: packages/postcss-linaria/__tests__/stringify.test.ts ================================================ import type { Root, Rule, Declaration } from 'postcss'; import syntax from '../src/index'; import { placeholderText } from '../src/util'; import { createTestAst, sourceWithExpression } from './__utils__'; const { ruleset, singleLineRuleset, selectorOrAtRule, selectorBeforeExpression, selectorAfterExpression, declarationProperty, declarationValue, declarationMultipleValues, declarationMixedValues, combo, } = sourceWithExpression; describe('stringify', () => { describe('with expressions', () => { it('should stringify a ruleset expression', () => { const { source, ast } = createTestAst(ruleset); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify a single line ruleset expression', () => { const { source, ast } = createTestAst(singleLineRuleset); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify a selector or at-rule expression', () => { const { source, ast } = createTestAst(selectorOrAtRule); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify selector expression with a selector before the expression', () => { const { source, ast } = createTestAst(selectorBeforeExpression); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify selector expression with a selector after the expression', () => { const { source, ast } = createTestAst(selectorAfterExpression); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify a declaration property expression', () => { const { source, ast } = createTestAst(declarationProperty); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify a declaration value with a single expression', () => { const { source, ast } = createTestAst(declarationValue); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify a declaration value with multiple expressions', () => { const { source, ast } = createTestAst(declarationMultipleValues); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify a decl value with some but not all values as expressions', () => { const { source, ast } = createTestAst(declarationMixedValues); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify a combinations of all expressions', () => { const { source, ast } = createTestAst(combo); const output = ast.toString(syntax); expect(output).toEqual(source); }); }); it('should stringify basic CSS', () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify single-line expressions', () => { const { source, ast } = createTestAst(` css\` .foo { $\{expr}: hotpink; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify multiple expressions', () => { const { source, ast } = createTestAst(` css\` .foo { $\{expr}: hotpink; } .bar { $\{expr2}: lime; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify multiple same-named expressions', () => { const { source, ast } = createTestAst(` css\` .foo { $\{expr}: hotpink; } .bar { $\{expr}: lime; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify multiple stylesheets', () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; } \`; const somethingInTheMiddle = 808; css\`.foo { color: lime; }\`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should handle deleted (by another plugin) expression state', () => { const { ast } = createTestAst(` css\` .foo { $\{expr}: hotpink; } \`; `); const root = ast.nodes[0]!; root.raws.linariaTemplateExpressions = undefined; const output = ast.toString(syntax); expect(output).toEqual( ` css\` .foo { --${placeholderText}0: hotpink; } \`; ` ); }); it('should ignore non-placeholder comments', () => { const { source, ast } = createTestAst(` css\` /* random comment about this line */ .foo { color: hotpink; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should handle base indentations', () => { const { source, ast } = createTestAst(` css\` .foo { color: hotpink; } .bar { border: 808em solid cyan; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should deal with multi-line rules', () => { const { source, ast } = createTestAst(` css\` .foo, .bar { color: hotpink; } .x, .x > .y { font-size: 32em; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should deal with multi-line declarations', () => { const { source, ast } = createTestAst(` css\` .foo { margin: 1px 2px 3px 4px; } .bar { margin: 1px 2px 3px; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should deal with unusual between values', () => { const { source, ast } = createTestAst(` css\` .foo { margin : 10px; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should deal with unusual before values', () => { const { source, ast } = createTestAst(` css\` .foo { margin: 10px; ; margin: 20px; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should deal with unusual after values', () => { const { source, ast } = createTestAst(` css\` .foo { margin: 1px 2px; ; } \`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify non-css JS', () => { const { source, ast } = createTestAst(` const a = 5; const b = 303; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify empty CSS', () => { const { source, ast } = createTestAst(` css\`\`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should stringify single-line CSS', () => { const { source, ast } = createTestAst(` css\`.foo { color: hotpink; }\`; `); const output = ast.toString(syntax); expect(output).toEqual(source); }); it('should escape backticks', () => { const { ast } = createTestAst(` css\`.foo { color: hotpink; }\`; `); const root = ast.nodes[0] as Root; const rule = root.nodes[0] as Rule; const colour = rule.nodes[0] as Declaration; colour.raws.between = ': /*comment with `backticks`*/'; const output = ast.toString(syntax); expect(output).toEqual( ` css\`.foo { color: /*comment with \\\`backticks\\\`*/hotpink; }\`; ` ); }); it('should not escape unrelated backticks', () => { const { ast } = createTestAst(` html\`
\`; `); const output = ast.toString(syntax); expect(output).toEqual( ` html\`
\`; ` ); }); it('should not escape unrelated backslashes', () => { const { ast } = createTestAst(` const foo = 'abc\\def'; `); const output = ast.toString(syntax); expect(output).toEqual( ` const foo = 'abc\\def'; ` ); }); it('should escape backslashes', () => { const { ast } = createTestAst(` css\`.foo { color: hotpink; }\`; `); const root = ast.nodes[0] as Root; const rule = root.nodes[0] as Rule; rule.selector = '.foo\\:bar'; const output = ast.toString(syntax); expect(output).toEqual( ` css\`.foo\\\\:bar { color: hotpink; }\`; ` ); }); it('should stringify styled API', () => { const { source, ast } = createTestAst(` styled.h1\` .foo { width: \${p => p.size}px; } \` `); const output = ast.toString(syntax); expect(output).toEqual(source); }); }); ================================================ FILE: packages/postcss-linaria/__tests__/stylelint.test.ts ================================================ import { resolve } from 'path'; import stylelint, { type Config } from 'stylelint'; // importing from the package would create circular dependency // so just import the config directly here // eslint-disable-next-line import/no-relative-packages import config from '../../stylelint-config-standard-linaria/src'; // note: need to run pnpm install to pick up updates from any parse/stringify changes describe('stylelint', () => { const configBasedir = resolve( __dirname, '../../stylelint-config-standard-linaria' ); it('should not error with valid syntax', async () => { const source = ` css\` \${expr0} .foo { \${expr1}: \${expr2}; } \${expr3} { .bar { color: black; } } \${expr4} \`; `; const result = await stylelint.lint({ code: source, config: config as Config, configBasedir, }); expect(result.errored).toEqual(false); }); it('should be fixable by stylelint', async () => { const source = ` css\` .foo { \${expr1}: \${expr2};; } \`;`; const result = await stylelint.lint({ code: source, config: { ...config, rules: { ...config.rules, 'no-extra-semicolons': true, }, } as Config, fix: true, configBasedir, }); expect(result.errored).toEqual(false); expect(result.output).toMatchInlineSnapshot(` " css\` .foo { \${expr1}: \${expr2}; } \`;" `); }); it('should be fixable by stylelint with styled api', async () => { const source = ` styled.h1\` .foo { width: \${p => p.size}px;; } \`;`; const result = await stylelint.lint({ code: source, config: { ...config, rules: { ...config.rules, 'no-extra-semicolons': true, }, } as Config, fix: true, configBasedir, }); expect(result.errored).toEqual(false); expect(result.output).toMatchInlineSnapshot(` " styled.h1\` .foo { width: \${p => p.size}px; } \`;" `); }); it('should be fixable by stylelint with multi-line expressions', async () => { const source = ` css\` $\{expr1} .foo { \${expr2}: black;; } \`;`; const result = await stylelint.lint({ code: source, config: { ...config, rules: { ...config.rules, 'no-extra-semicolons': true, }, } as Config, fix: true, configBasedir, }); expect(result.output).toMatchInlineSnapshot(` " css\` $\{expr1} .foo { \${expr2}: black; } \`;" `); }); it('should be compatible with indentation rule', async () => { const source = ` css\` .foo { width: 100px; } \`; `; const result = await stylelint.lint({ code: source, config: { ...config, rules: { ...config.rules, indentation: 4, }, } as Config, configBasedir, }); expect(result.errored).toEqual(false); }); }); ================================================ FILE: packages/postcss-linaria/__tests__/utils.test.ts ================================================ import { createPlaceholder, placeholderText } from '../src/util'; describe('createPlaceholder', () => { it('should create a placeholder for a selector expression', () => { const expressionCounter = 0; const sourceAsString = ` const expr = '@media (min-width: 100px)'; css\` $\{expr} { color: black; } \`; `; const indexAfterExpression = sourceAsString.indexOf('}') + 1; const result = createPlaceholder( expressionCounter, sourceAsString, indexAfterExpression ); expect(result).toEqual(`.${placeholderText}${expressionCounter}`); }); it('should create a placeholder for a property expression', () => { const expressionCounter = 0; const sourceAsString = ` const expr = 'color'; css\` \${expr}: black; \`; `; const indexAfterExpression = sourceAsString.indexOf('}') + 1; const result = createPlaceholder( expressionCounter, sourceAsString, indexAfterExpression ); expect(result).toEqual(`--${placeholderText}${expressionCounter}`); }); it('should create a placeholder for a ruleset expression', () => { const expressionCounter = 0; const sourceAsString = ` const expr = 'color: black'; css\` $\{expr} \`; `; const indexAfterExpression = sourceAsString.indexOf('}') + 1; const result = createPlaceholder( expressionCounter, sourceAsString, indexAfterExpression ); expect(result).toEqual(`/* ${placeholderText}:${expressionCounter} */`); }); it('should create a placeholder for a value expression', () => { const expressionCounter = 0; const sourceAsString = ` const expr = 'black'; css\` color: \${expr}; \`; `; const indexAfterExpression = sourceAsString.indexOf('}') + 1; const result = createPlaceholder( expressionCounter, sourceAsString, indexAfterExpression ); expect(result).toEqual(`${placeholderText}${expressionCounter}`); }); }); ================================================ FILE: packages/postcss-linaria/babel.config.js ================================================ const config = require('../../babel.config'); module.exports = config; ================================================ FILE: packages/postcss-linaria/package.json ================================================ { "name": "@linaria/postcss-linaria", "version": "7.0.0", "description": "Blazing fast zero-runtime CSS in JS library", "keywords": [ "css", "css-in-js", "linaria", "react", "styled-components" ], "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "sideEffects": false, "main": "lib/index.js", "module": "esm/index.js", "types": "types/index.d.ts", "files": [ "esm/", "lib/", "processors/", "types/" ], "scripts": { "build": "pnpm build:lib && pnpm build:esm && pnpm build:declarations", "build:declarations": "tsc --emitDeclarationOnly --outDir types", "build:esm": "babel src --out-dir esm --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "build:lib": "cross-env NODE_ENV=legacy babel src --out-dir lib --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "typecheck": "tsc --noEmit --composite false", "test": "jest --config ../../jest.config.js --rootDir .", "watch": "pnpm build:lib --watch & pnpm build:esm --watch & pnpm build:declarations --watch" }, "dependencies": { "@babel/generator": "^7.23.5", "@babel/parser": "^7.23.5", "@babel/traverse": "^7.23.5", "stylelint": "^14.11.0" }, "devDependencies": { "@babel/types": "^7.23.5", "@types/babel__generator": "^7.6.7", "@types/babel__traverse": "^7.20.4", "postcss": "^8.4.31" }, "peerDependencies": { "postcss": "^8.4.31" }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" } } ================================================ FILE: packages/postcss-linaria/src/index.ts ================================================ import { parse } from './parse'; import { stringify } from './stringify'; export { parse, stringify }; export default { parse, stringify }; ================================================ FILE: packages/postcss-linaria/src/locationCorrection.ts ================================================ /* eslint-disable no-param-reassign */ import type { TaggedTemplateExpression } from '@babel/types'; import type { Root, Position, Document, ChildNode, AnyNode } from 'postcss'; import { createPlaceholder } from './util'; const correctLocation = ( node: TaggedTemplateExpression, loc: Position, baseIndentations: Map, sourceAsString: string, prefixOffsets?: { lines: number; offset: number }, kind: 'start' | 'end' = 'start' ): Position => { if (!node.quasi.loc || !node.quasi.range) { return loc; } const baseIndentation = baseIndentations?.get(loc.line) ?? 0; const nodeLoc = node.quasi.loc; const nodeOffset = node.quasi.range[0]; let lineOffset = nodeLoc.start.line - 1; let newOffset = loc.offset + nodeOffset + (kind === 'start' ? 1 : 0); let currentLine = 1; let columnOffset = nodeLoc.start.column + 1; if (prefixOffsets) { lineOffset += prefixOffsets.lines; newOffset += prefixOffsets.offset; } for (let i = 0; i < node.quasi.expressions.length; i++) { const expr = node.quasi.expressions[i]; const previousQuasi = node.quasi.quasis[i]; const nextQuasi = node.quasi.quasis[i + 1]; if ( expr && expr.loc && expr.range && nextQuasi && previousQuasi && previousQuasi.loc && nextQuasi.loc && previousQuasi.range && nextQuasi.range && previousQuasi.range[1] < newOffset ) { const placeholderSize = createPlaceholder( i, sourceAsString, nextQuasi.range[0] ).length; const exprSize = nextQuasi.range[0] - previousQuasi.range[1] - placeholderSize; const exprStartLine = previousQuasi.loc.end.line; const exprEndLine = nextQuasi.loc.start.line; newOffset += exprSize; lineOffset += exprEndLine - exprStartLine; if (currentLine !== exprEndLine) { currentLine = exprEndLine; if (exprStartLine === exprEndLine) { columnOffset = exprSize; } else { columnOffset = nextQuasi.loc.start.column - previousQuasi.loc.end.column - placeholderSize; } } else { columnOffset += exprSize; } } } let indentationOffset = 0; if (baseIndentations) { for (let i = 1; i <= loc.line; i++) { indentationOffset += baseIndentations.get(i) ?? 0; } } loc.line += lineOffset; if (loc.line === currentLine) { loc.column += columnOffset; } loc.column += baseIndentation; loc.offset = newOffset + indentationOffset; return loc; }; /** * Computes the re-indented string of a given string on a given line * @param {string} value Value to re-indent * @param {number} lineNumber Current line number of the value * @param {Map=} baseIndentations Indentation map * @return {string} */ function computeCorrectedString( value: string, lineNumber: number, baseIndentations?: Map ): string { if (!value.includes('\n')) { const baseIndentation = baseIndentations?.get(lineNumber); if (baseIndentation !== undefined) { return ' '.repeat(baseIndentation) + value; } return value; } const lines = value.split('\n'); const rawLines: string[] = []; if (lines[0] !== undefined) { rawLines.push(lines[0]); } for (let i = 1; i < lines.length; i++) { const line = lines[i]; if (line !== undefined) { const currentLineNumber = lineNumber + i; const baseIndentation = baseIndentations?.get(currentLineNumber); if (baseIndentation !== undefined) { rawLines.push(' '.repeat(baseIndentation) + line); } else { rawLines.push(line); } } } return rawLines.join('\n'); } /** * Computes the re-indented value of a given node's raw value * @param {T} node Node to re-indent raw value of * @param {string} key Raw value key to re-indent * @param {Map=} baseIndentations Indentation map * @return {string|null} */ function computeCorrectedRawValue( node: T, key: keyof T, baseIndentations?: Map ): string | null { const value = node[key]; if (typeof value !== 'string' || !node.source?.start) { return null; } return computeCorrectedString( value, node.source.start.line, baseIndentations ); } /** * Computes the before/after strings from the original source for * restoration later when stringifying. * @param {Document|Root|ChildNode} node Node to compute strings for * @param {Map} baseIndentations Map of base indentations by line * @return {void} */ function computeBeforeAfter( node: Document | Root | ChildNode, baseIndentations: Map ): void { if ( node.raws.before && (node.raws.before.includes('\n') || node.parent?.type === 'root') && node.source?.start ) { const numBeforeLines = node.raws.before.split('\n').length - 1; const corrected = computeCorrectedString( node.raws.before, node.source.start.line - numBeforeLines, baseIndentations ); node.raws.linariaBefore = corrected; } if ( node.raws.after && node.raws.after.includes('\n') && (node.type === 'root' || node.source?.end) ) { const numAfterLines = node.raws.after.split('\n').length - 1; const line = node.type === 'root' ? node.nodes[node.nodes.length - 1]?.source?.end?.line : node.source?.end?.line; if (line !== undefined) { const corrected = computeCorrectedString( node.raws.after, line - numAfterLines, baseIndentations ); node.raws.linariaAfter = corrected; } } if ( node.raws.between && node.raws.between.includes('\n') && node.source?.start ) { const corrected = computeCorrectedString( node.raws.between, node.source.start.line, baseIndentations ); node.raws.linariaBetween = corrected; } if (node.type === 'rule' && node.selector.includes('\n')) { const rawValue = computeCorrectedRawValue( node, 'selector', baseIndentations ); if (rawValue !== null) { (node.raws as unknown as Record).linariaSelector = rawValue; } } if (node.type === 'decl' && node.value.includes('\n')) { const rawValue = computeCorrectedRawValue(node, 'value', baseIndentations); if (rawValue !== null) { (node.raws as unknown as Record).linariaValue = rawValue; } } if (node.type === 'atrule' && node.params.includes('\n')) { const rawValue = computeCorrectedRawValue(node, 'params', baseIndentations); if (rawValue !== null) { (node.raws as unknown as Record).linariaParams = rawValue; } } } /** * Creates an AST walker/visitor for correcting PostCSS AST locations to * those in the original JavaScript document. * @param {TaggedTemplateExpression} expr Expression the original source came * from * @return {Function} */ export function locationCorrectionWalker( expr: TaggedTemplateExpression, sourceAsString: string ): (node: Document | Root | ChildNode) => void { return (node: Document | Root | ChildNode): void => { const root = node.root(); const baseIndentations = root.raws.linariaBaseIndentations; if (baseIndentations) { computeBeforeAfter(node, baseIndentations); } if (node.source?.start) { node.source.start = correctLocation( expr, node.source.start, baseIndentations, sourceAsString, root.raws.linariaPrefixOffsets, 'start' ); } if (node.source?.end) { node.source.end = correctLocation( expr, node.source.end, baseIndentations, sourceAsString, root.raws.linariaPrefixOffsets, 'end' ); } }; } ================================================ FILE: packages/postcss-linaria/src/parse.ts ================================================ import { parse as babelParse } from '@babel/parser'; import type { NodePath } from '@babel/traverse'; import traverse from '@babel/traverse'; import type { Identifier, TaggedTemplateExpression } from '@babel/types'; import type { Parser, Root, ProcessOptions } from 'postcss'; import { Document, Input } from 'postcss'; import postcssParse from 'postcss/lib/parse'; import { locationCorrectionWalker } from './locationCorrection'; import { createPlaceholder } from './util'; // This function returns // 1) styleText with placeholders for the expressions. // for example: // `${selector} { ${property} : ${value} }` // becomes // `.pcss-lin0 { --pcss-lin1: pcss-lin2 }` // 2) an array of the expressions: // ['${selector}', '${property}', '${value}'] const generateStyleTextWithExpressionPlaceholders = ( node: TaggedTemplateExpression, sourceAsString: string ): { expressionStrings: string[]; styleText: string } => { let styleText = ''; const expressionStrings: string[] = []; for (let i = 0; i < node.quasi.quasis.length; i++) { const template = node.quasi.quasis[i]; const expr = node.quasi.expressions[i]; const nextTemplate = node.quasi.quasis[i + 1]; if (template) { styleText += template.value.raw; if (expr && nextTemplate && nextTemplate.range && template.range) { const exprText = sourceAsString.slice( template.range[1], nextTemplate.range[0] ); styleText += createPlaceholder( i, sourceAsString, nextTemplate.range[0] ); expressionStrings.push(exprText); } } } return { styleText, expressionStrings }; }; const getDeindentedStyleTextAndOffsets = ( styleText: string, node: TaggedTemplateExpression ) => { const baseIndentation = (node.quasi.loc?.end.column ?? 1) - 1; const sourceLines = styleText.split('\n'); const baseIndentations = new Map(); const indentationPattern = new RegExp(`^[ \\t]{${baseIndentation}}`); const emptyLinePattern = /^[ \\t\r]*$/; const deindentedLines: string[] = []; const prefixOffsets = { lines: 0, offset: 0 }; // remove the first line if it's an empty string and update the prefix // offset to be the lines 1 instead of lines 0 if ( sourceLines.length > 1 && sourceLines[0] !== undefined && emptyLinePattern.test(sourceLines[0]) ) { prefixOffsets.lines = 1; prefixOffsets.offset = sourceLines[0].length + 1; sourceLines.shift(); } // go through each source line and deindent lines for (let i = 0; i < sourceLines.length; i++) { const sourceLine = sourceLines[i]; if (sourceLine !== undefined) { // if the sourceline has the indentation pattern if (indentationPattern.test(sourceLine)) { deindentedLines.push(sourceLine.replace(indentationPattern, '')); baseIndentations.set(i + 1, baseIndentation); // Roots don't have an end line, so we can't look this up so easily // later on. Having a special '-1' key helps here. if (i === sourceLines.length - 1) { baseIndentations.set(-1, baseIndentation); } } else { deindentedLines.push(sourceLine); } } } const deindentedStyleText = deindentedLines.join('\n'); return { deindentedStyleText, prefixOffsets, baseIndentations }; }; /** * Parses CSS from within tagged template literals in a JavaScript document * @param {string} source Source code to parse * @param {*=} opts Options to pass to PostCSS' parser when parsing * @return {Root|Document} */ export const parse: Parser = ( source: string | { toString(): string }, opts?: Pick ): Root | Document => { const doc = new Document(); const sourceAsString = source.toString(); // avoid error spam (and vscode error toasts) if babel can't parse doc // allows user to type new code without constant warnings let ast; try { ast = babelParse(sourceAsString, { sourceType: 'unambiguous', plugins: ['typescript', 'jsx'], ranges: true, }); } catch { return doc; } const extractedStyles = new Set(); traverse(ast, { TaggedTemplateExpression: ( path: NodePath ): void => { if ( path.node.tag.type === 'Identifier' && path.node.tag.name.includes('css') ) { extractedStyles.add(path.node); } if (path.node.tag.type === 'MemberExpression') { if ((path.node.tag.object as Identifier).name === 'styled') { extractedStyles.add(path.node); } } if ( path.node.tag.type === 'CallExpression' && path.node.tag.callee.type === 'Identifier' ) { if (path.node.tag.callee.name === 'styled') { extractedStyles.add(path.node); } } }, }); let currentOffset = 0; // eslint-disable-next-line no-restricted-syntax for (const node of extractedStyles) { if (!node.quasi.range) { // eslint-disable-next-line no-continue continue; } const startIndex = node.quasi.range[0] + 1; const { styleText, expressionStrings } = generateStyleTextWithExpressionPlaceholders(node, sourceAsString); const { deindentedStyleText, prefixOffsets, baseIndentations } = getDeindentedStyleTextAndOffsets(styleText, node); const root = postcssParse(deindentedStyleText, { ...opts, map: false, }) as Root; root.raws.linariaPrefixOffsets = prefixOffsets; root.raws.linariaTemplateExpressions = expressionStrings; root.raws.linariaBaseIndentations = baseIndentations; // TODO: remove this if stylelint/stylelint#5767 ever gets fixed, // or they drop the indentation rule. Their indentation rule depends on // `beforeStart` existing as they unsafely try to call `endsWith` on it. if (!root.raws.beforeStart) { root.raws.beforeStart = ''; } root.raws.codeBefore = sourceAsString.slice( currentOffset, startIndex + prefixOffsets.offset ); root.parent = doc; // TODO: stylelint relies on this existing, really unsure why. // it could just access root.parent to get the document... (root as Root & { document: Document }).document = doc; const walker = locationCorrectionWalker(node, sourceAsString); walker(root); root.walk(walker); doc.nodes.push(root); currentOffset = node.quasi.range[1] - 1; } if (doc.nodes.length > 0) { const last = doc.nodes[doc.nodes.length - 1]; if (last) { last.raws.codeAfter = sourceAsString.slice(currentOffset); } } doc.source = { input: new Input(sourceAsString, opts), start: { line: 1, column: 1, offset: 0, }, }; return doc; }; ================================================ FILE: packages/postcss-linaria/src/stringify.ts ================================================ import type { Stringifier as StringifierFn, Comment, Root, Document, AnyNode, Builder, Declaration, Rule, AtRule, } from 'postcss'; import Stringifier from 'postcss/lib/stringifier'; import { placeholderText } from './util'; const substitutePlaceholders = ( stringWithPlaceholders: string, expressions: string[] ) => { if (!stringWithPlaceholders.includes(placeholderText) || !expressions) { return stringWithPlaceholders; } const values = stringWithPlaceholders.split(' '); const temp: string[] = []; values.forEach((val) => { let [prefix, expressionIndexString] = val.split(placeholderText); prefix = prefix.replace(/(\.|--|\/\*)$/, ''); // if the val is 'pcss-lin10px', need to remove the px to get the placeholder number let suffix = ''; while ( Number.isNaN(Number(expressionIndexString)) && expressionIndexString && expressionIndexString.length > 0 ) { suffix = expressionIndexString[expressionIndexString.length - 1] + suffix; expressionIndexString = expressionIndexString.slice( 0, expressionIndexString.length - 1 ); } const expressionIndex = Number(expressionIndexString); const expression = expressions && !Number.isNaN(expressionIndex) && expressions[expressionIndex]; if (expression) { temp.push(prefix + expression + suffix); } else { temp.push(val); } }); return temp.join(' '); }; /** * Stringifies PostCSS nodes while taking interpolated expressions * into account. */ class LinariaStringifier extends Stringifier { /** @inheritdoc */ public constructor(builder: Builder) { const wrappedBuilder: Builder = ( str: string, node?: AnyNode, type?: 'start' | 'end' ): void => { // We purposely ignore the root node since the only thing we should // be stringifying here is already JS (before/after raws) so likely // already contains backticks on purpose. // // Similarly, if there is no node, we're probably stringifying // pure JS which never contained any CSS. Or something really weird // we don't want to touch anyway. // // For everything else, we want to escape backticks. if (!node || node?.type === 'root') { builder(str, node, type); } else { builder(str.replace(/\\/g, '\\\\').replace(/`/g, '\\`'), node, type); } }; super(wrappedBuilder); } public override atrule(node: AtRule, semicolon?: boolean) { const { params } = node; const expressionStrings = node.root().raws.linariaTemplateExpressions; if (params.includes(placeholderText)) { // eslint-disable-next-line no-param-reassign node.params = substitutePlaceholders(params, expressionStrings); } super.atrule(node, semicolon); } /** @inheritdoc */ public override comment(node: Comment): void { const placeholderPattern = new RegExp(`^${placeholderText}:\\d+$`); if (placeholderPattern.test(node.text)) { const [, expressionIndexString] = node.text.split(':'); const expressionIndex = Number(expressionIndexString); const root = node.root(); const expressionStrings = root.raws.linariaTemplateExpressions; if (expressionStrings && !Number.isNaN(expressionIndex)) { const expression = expressionStrings[expressionIndex]; if (expression) { this.builder(expression, node); return; } } } super.comment(node); } public override decl(node: Declaration, semicolon: boolean): void { const between = this.raw(node, 'between', 'colon'); let { prop } = node; const expressionStrings = node.root().raws.linariaTemplateExpressions; if (prop.includes(placeholderText)) { prop = substitutePlaceholders(prop, expressionStrings); } let value = this.rawValue(node, 'value'); if (value.includes(placeholderText)) { value = substitutePlaceholders(value, expressionStrings); } let string = prop + between + value; if (node.important) { string += node.raws.important || ' !important'; } if (semicolon) string += ';'; this.builder(string, node); } /** @inheritdoc */ public override document(node: Document): void { if (node.nodes.length === 0) { this.builder(node.source?.input.css ?? ''); } else { super.document(node); } } /** @inheritdoc */ public override raw( node: AnyNode, own: string, detect: string | undefined ): string { if (own === 'before' && node.raws.before && node.raws.linariaBefore) { return node.raws.linariaBefore; } if (own === 'after' && node.raws.after && node.raws.linariaAfter) { return node.raws.linariaAfter; } if (own === 'between' && node.raws.between && node.raws.linariaBetween) { return node.raws.linariaBetween; } return super.raw(node, own, detect); } /** @inheritdoc */ public override rawValue(node: AnyNode, prop: string): string { const linariaProp = `linaria${prop[0]?.toUpperCase()}${prop.slice(1)}`; if (Object.prototype.hasOwnProperty.call(node.raws, linariaProp)) { return `${node.raws[linariaProp]}`; } return super.rawValue(node, prop); } /** @inheritdoc */ public override root(node: Root): void { this.builder(node.raws.codeBefore ?? '', node, 'start'); this.body(node); // Here we want to recover any previously removed JS indentation // if possible. Otherwise, we use the `after` string as-is. const after = node.raws.linariaAfter ?? node.raws.after; if (after) { this.builder(after); } this.builder(node.raws.codeAfter ?? '', node, 'end'); } public override rule(node: Rule): void { let value = this.rawValue(node, 'selector'); if (value.includes(placeholderText)) { const expressionStrings = node.root().raws.linariaTemplateExpressions; value = substitutePlaceholders(value, expressionStrings); } this.block(node, value); if (node.raws.ownSemicolon) { this.builder(node.raws.ownSemicolon, node, 'end'); } } } export const stringify: StringifierFn = ( node: AnyNode, builder: Builder ): void => { const str = new LinariaStringifier(builder); str.stringify(node); }; ================================================ FILE: packages/postcss-linaria/src/util.ts ================================================ const getLine = (sourceAsString: string, indexAfterExpression: number) => { const begginningOfLineIndex = sourceAsString.lastIndexOf('\n', indexAfterExpression) || 0; const endOfLineIndex = sourceAsString.indexOf('\n', indexAfterExpression - 1) || Infinity; const indexAfterExpressionInLine = indexAfterExpression - begginningOfLineIndex; return { line: sourceAsString.substring(begginningOfLineIndex, endOfLineIndex + 1), indexAfterExpressionInLine, }; }; const isSelector = (sourceAsString: string, indexAfterExpression: number) => { const { line } = getLine(sourceAsString, indexAfterExpression); const isSingleLineRule = line.indexOf('{', indexAfterExpression) > 0 && line.indexOf('}', indexAfterExpression) > 0; return isSingleLineRule || line[line.length - 2] === '{'; }; const isProperty = (sourceAsString: string, indexAfterExpression: number) => { return sourceAsString[indexAfterExpression] === ':'; }; // no ':' or '{' on the line const isRuleSet = (sourceAsString: string, indexAfterExpression: number) => { const { line: possibleRuleset, indexAfterExpressionInLine } = getLine( sourceAsString, indexAfterExpression ); const hasCurlyBraceAfterExpression = possibleRuleset.indexOf('{', indexAfterExpressionInLine) > 0; const hasCommmaAfterExpression = possibleRuleset.indexOf(',', indexAfterExpressionInLine) > 0; // check if possible ruleset has ':' and outside of the func args if expression has a func // i.e. avoid false postivive for `${func({ key: value })} const indexOfOpenParenthesis = possibleRuleset.indexOf('('); const indexOfClosedParenthesis = possibleRuleset.indexOf(')'); const hasFuncInExpression = indexOfOpenParenthesis > 0 && indexOfClosedParenthesis > 0; let hasColonOutsideOfExpression = possibleRuleset.includes(':'); if (hasFuncInExpression) { hasColonOutsideOfExpression = possibleRuleset.lastIndexOf(':', indexOfOpenParenthesis) > 0 || possibleRuleset.indexOf(':', indexOfClosedParenthesis) > 0; } return !( hasColonOutsideOfExpression || hasCurlyBraceAfterExpression || hasCommmaAfterExpression ); }; export const placeholderText = 'pcss-lin'; export const createPlaceholder = ( i: number, sourceAsString: string, indexAfterExpression: number ): string => { if (isSelector(sourceAsString, indexAfterExpression)) { return `.${placeholderText}${i}`; } if (isProperty(sourceAsString, indexAfterExpression)) { return `--${placeholderText}${i}`; } if (isRuleSet(sourceAsString, indexAfterExpression)) { return `/* ${placeholderText}:${i} */`; } // assume it's a property value or part of another string; return `${placeholderText}${i}`; }; ================================================ FILE: packages/postcss-linaria/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "paths": {}, "rootDir": "src/" }, "references": [] } ================================================ FILE: packages/react/CHANGELOG.md ================================================ # Change Log ## 7.0.1 ### Patch Changes - b3331e45: Fix `styled.` typings in environments where only the React JSX runtime types are available (e.g. `jsx: react-jsx`). ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ### Patch Changes - 654d8590: Fix TypeScript typings for React 17 projects using the automatic JSX runtime (`jsx: react-jsx`), so `styled.*` intrinsic components don’t incorrectly require `children`. - Updated dependencies [ab11ebb7] - @linaria/core@7.0.0 ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ### Patch Changes - bd8d45fd: Support for React 19 - Updated dependencies [281ca4f5] - @linaria/core@6.3.0 ## 6.2.1 ### Patch Changes - Updated dependencies [a3dcee2e] - @linaria/core@6.2.0 ## 6.2.0 ### Minor Changes - fd60b5de: Fix for extending imported component #1378 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ### Patch Changes - 8d4ebd33: chore: bump @wyw-in-js/\* packages - Updated dependencies [8d4ebd33] - Updated dependencies [8ba655d3] - @linaria/core@6.1.0 ## 6.0.0 ### Major Changes - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ### Patch Changes - Updated dependencies [2ac94b99] - @linaria/core@6.0.0 ## 5.0.3 ### Patch Changes - 4b083b7c: Fix compatibility with Webpack 4. ## 5.0.2 ### Patch Changes - 1e889937: fix: make StyledProcessor work on Windows - Updated dependencies [4992c14d] - Updated dependencies [70000ec8] - Updated dependencies [1e889937] - Updated dependencies [5a32f4fd] - Updated dependencies [727dc2bd] - Updated dependencies [25ba1344] - Updated dependencies [5a32f4fd] - @linaria/utils@5.0.2 - @linaria/tags@5.0.2 - @linaria/core@5.0.2 ## 5.0.1 ### Patch Changes - Updated dependencies [6fb6eb69] - @linaria/utils@5.0.1 - @linaria/core@5.0.1 - @linaria/tags@5.0.1 ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 - Updated dependencies [9cb4143d] - Updated dependencies [ae162f46] - Updated dependencies [88e07613] - Updated dependencies [b3ef8c1f] - Updated dependencies [f8b9bff5] - Updated dependencies [63902332] - Updated dependencies [aa100453] - Updated dependencies [2a1e24a0] - Updated dependencies [16320d71] - Updated dependencies [cb853e14] - @linaria/core@5.0.0 - @linaria/tags@5.0.0 - @linaria/utils@5.0.0 ## 4.5.4 ### Patch Changes - Updated dependencies [10bcd241] - @linaria/utils@4.5.3 - @linaria/core@4.5.4 - @linaria/tags@4.5.4 ## 4.5.3 ### Patch Changes - 79557248: Nothing has changed. Just moved some utils and types from babel to utils package. - e59bf809: Shaker mistakenly counts references in types as valuable and keeps referenced variables alive. - Updated dependencies [79557248] - Updated dependencies [b191f543] - Updated dependencies [e59bf809] - Updated dependencies [520ba8da] - Updated dependencies [ae3727f9] - Updated dependencies [dca076ef] - @linaria/core@4.5.3 - @linaria/tags@4.5.3 - @linaria/utils@4.5.2 ## 4.5.2 ### Patch Changes - Updated dependencies [85e74df6] - Updated dependencies [1bf5c5b8] - @linaria/utils@4.5.1 - @linaria/core@4.5.2 - @linaria/tags@4.5.2 ## 4.5.1 ### Patch Changes - ceca1611: Enable optimisation from #1276 for complex expressions such as `styled(Component as unknow)` or `styled(connect(Component))`. - 13258306: Variables in props-based interpolation functions are no longer required for the evaluation stage. Here's an example: ``` import { getColor } from "very-big-library"; export const Box = styled.div\` color: ${props => getColor(props.kind)}; \`; ``` In versions prior to and including 4.5.0, the evaluator would attempt to import `getColor` from `very-big-library`, despite it having no relevance to style generation. However, in versions greater than 4.5.0, `very-big-library` will be ignored. - Updated dependencies [ceca1611] - Updated dependencies [13258306] - @linaria/tags@4.5.1 - @linaria/core@4.5.1 ## 4.5.0 ### Minor Changes - 16c057df: Breaking Change: Performance Optimization for `styled` When a component is wrapped in `styled`, Linaria needs to determine if that component is already a styled component. To accomplish this, the wrapped component is included in the list of variables for evaluation, along with the interpolated values used in styles. The issue arises when a wrapped component, even if it is not styled, brings along a substantial dependency tree. This situation is particularly evident when using `styled` to style components from third-party UI libraries. To address this problem, Linaria will now examine the import location of the component and check if there is an annotation in the `package.json` file of the package containing the components. This annotation indicates whether the package includes other Linaria components. If there is no such annotation, Linaria will refrain from evaluating the component. Please note that this Breaking Change solely affects developers of component libraries. In order for users to style components from your library, you must include the `linaria.components` property in the library's `package.json` file. This property should have a mask that covers all imported files with components. Here's an example of how to specify it: ```json "linaria": { "components": "**/*" } ``` ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. - 10859924: Don't add `mocked-styled` classnames outside test env - Updated dependencies [890b4aca] - Updated dependencies [05ad266c] - Updated dependencies [16c057df] - Updated dependencies [af5bb92d] - @linaria/utils@4.5.0 - @linaria/tags@4.5.0 - @linaria/core@4.5.0 ## 4.3.8 ### Patch Changes - 54ab61b2: Enhance @linaria/shaker strategy: better search in namespace imports, add support for side effect imports, fix file skipping. - Updated dependencies [54ab61b2] - @linaria/tags@4.3.5 - @linaria/utils@4.3.4 - @linaria/core@4.2.10 ## 4.3.7 ### Patch Changes - 1c3f309d: Fix tags usage validation (fixes #1224) - 34029088: Usages of `styled` and `css` in Jest no longer trigger the "Using the … tag in runtime is not supported" exception. - Updated dependencies [2e966f23] - Updated dependencies [1c3f309d] - Updated dependencies [dbe250b5] - Updated dependencies [34029088] - @linaria/tags@4.3.4 - @linaria/utils@4.3.3 - @linaria/core@4.2.9 ## 4.3.6 ### Patch Changes - a3ad617f: Fix "Invalid usage of `styled` tag" when it's not really invalid. Fixes #1214. - Updated dependencies [a3ad617f] - @linaria/tags@4.3.3 - @linaria/core@4.2.8 ## 4.3.5 ### Patch Changes - Updated dependencies [f9df4ed8] - @linaria/utils@4.3.2 - @linaria/core@4.2.7 - @linaria/tags@4.3.2 ## 4.3.4 ### Patch Changes - Updated dependencies [28f3f93d] - Updated dependencies [71a5b351] - Updated dependencies [61d49a39] - @linaria/tags@4.3.1 - @linaria/utils@4.3.1 - @linaria/core@4.2.6 ## 4.3.3 ### Patch Changes - Updated dependencies [3ce985e0] - Updated dependencies [d11174d0] - @linaria/tags@4.3.0 - @linaria/utils@4.3.0 - @linaria/core@4.2.5 ## 4.3.2 ### Patch Changes - Updated dependencies [315f0366] - @linaria/utils@4.2.6 - @linaria/core@4.2.4 - @linaria/tags@4.2.2 ## 4.3.1 ### Patch Changes - 922f20d6: Do not allow to wrap components without props. - 5edde648: Upgrade Babel to support TypeScript 4.9. Fixes #1133. - Updated dependencies [5edde648] - Updated dependencies [b9e49b74] - @linaria/core@4.2.3 - @linaria/tags@4.2.1 - @linaria/utils@4.2.5 ## 4.3.0 ### Minor Changes - 63f56d47: Do not filter properties if an unknown component is passed to `styled`. Fixes support of custom elements #968 ### Patch Changes - c26d4667: force interop check to fix @emotion/is-prop-valid esm import - Updated dependencies [63f56d47] - Updated dependencies [963508a2] - @linaria/tags@4.2.0 - @linaria/utils@4.2.4 - @linaria/core@4.2.2 ## 4.2.1 ### Patch Changes - 6de22792: Upgrade @emotion/is-prop-valid to support ES modules - Updated dependencies [cc2f87a8] - @linaria/utils@4.2.3 - @linaria/core@4.2.1 - @linaria/tags@4.1.5 ## 4.2.0 ### Minor Changes - 1e88e95d: Support for ECMAScript modules. Fixes #904 and #1043. ### Patch Changes - Updated dependencies [1e88e95d] - @linaria/core@4.2.0 ## 4.1.5 ### Patch Changes - 87ffe61c: The new `variableNameSlug` option that allows to customize css variable names (closes #1053). - Updated dependencies [8a8be242] - Updated dependencies [8a8be242] - Updated dependencies [08304e09] - Updated dependencies [87ffe61c] - @linaria/utils@4.2.2 - @linaria/core@4.1.4 - @linaria/tags@4.1.4 ## 4.1.4 ### Patch Changes - @linaria/core@4.1.3 - @linaria/tags@4.1.3 ## 4.1.3 ### Patch Changes - c0bd271a: Sometimes Linaria can meet already processed code. In such a case, it shall ignore runtime versions of `styled` tags. Fixes #1037. - Updated dependencies [c0bd271a] - @linaria/tags@4.1.2 - @linaria/core@4.1.2 ## 4.1.2 ### Patch Changes - @linaria/core@4.1.1 - @linaria/tags@4.1.1 ## 4.1.1 ### Patch Changes - 2abc55b3: Fix 'Using the tag in runtime is not supported' in some enviroments (fixes #1021) ## 4.1.0 ### Patch Changes - @linaria/core@4.1.0 - @linaria/tags@4.1.0 ## 4.0.0 ### Major Changes - bc0cbeea: A completely new async mode with native support for Vite, Rollup, esbuild and Webpack resolvers. BREAKING CHANGES: Despite the fact, that it should be fully compatible with 3.0 and 2.0 branches, the new version of styles evaluator can have some serious bugs which can make your project unbuildable (however, since there is no runtime, if the build is finished successfully, everything will continue work as it was on 2.0 and 3.0). If you face some problems please let us know and we will fix it as soon as possible. ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - 609d79ba: Generic parameters of wrapped components had been missed in some cases. - ea41d440: New package @linaria/tags that contains all abstract logic for tags processors. - 9a50c1c1: Linaria now removes all unused css-related code from the runtime. - 4cdf0315: Tagged template-specific logic has been moved from `BaseProcessor` to `TaggedTemplateProcessor`. `BaseProcessor` now can be used to define any type of expressions for zero-runtime transformations, such as `makeStyles` from `@griffel/react`. - 12d35cb9: `processors` aliases have been lost during publishing. (fixes #984) - 3111ca8d: beta.19 broke prop interploation in some enviroments. Fixed. (fix #981) - 17c83e34: Aliases for environments without the support of `exports` in package.json. - f0cddda4: Extends `BaseProcessor` to support tags other than tagged templates, such as `makeStyles` from `@griffel/react`. - Updated dependencies [f0cddda4] - @linaria/core@4.0.0 - @linaria/tags@4.0.0 ## 3.0.0-beta.21 ### Patch Changes - 609d79ba: Generic parameters of wrapped components had been missed in some cases. - 17c83e34: Aliases for environments without the support of `exports` in package.json. - Updated dependencies [17c83e34] - @linaria/core@3.0.0-beta.21 ## 3.0.0-beta.20 ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - beta.19 broke prop interploation in some enviroments. Fixed. (fix #981) - Updated dependencies [8be5650d] - @linaria/core@3.0.0-beta.20 # [3.0.0-beta.19](https://github.com/callstack/linaria/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2022-06-03) ### Bug Fixes - **react:** support UpperCamelCase custom elements [#968](https://github.com/callstack/linaria/issues/968) ([#970](https://github.com/callstack/linaria/issues/970)) ([59800db](https://github.com/callstack/linaria/commit/59800dba540e09c0c43b1f0ec1d4b2c46d8a4672)) ### Features - **atomic:** add support for atomic using styled API ([#966](https://github.com/callstack/linaria/issues/966)) ([f59860b](https://github.com/callstack/linaria/commit/f59860b09c5f91b0423dbf188e5f8aaaef38a6b5)) - **babel:** api for custom tags ([#976](https://github.com/callstack/linaria/issues/976)) ([3285ccc](https://github.com/callstack/linaria/commit/3285ccc1d00449b78b3fc74087528cd38cbdd116)) - **babel:** new way for detecting tag imports ([#974](https://github.com/callstack/linaria/issues/974)) ([3305cfb](https://github.com/callstack/linaria/commit/3305cfb0c0f65abdacceeb7e6bad118c59f7d551)) # [3.0.0-beta.18](https://github.com/callstack/linaria/compare/v3.0.0-beta.17...v3.0.0-beta.18) (2022-04-01) **Note:** Version bump only for package @linaria/react # [3.0.0-beta.17](https://github.com/callstack/linaria/compare/v3.0.0-beta.16...v3.0.0-beta.17) (2021-12-27) ### Bug Fixes - **react:** refactored types for styled function (fixes [#872](https://github.com/callstack/linaria/issues/872)) ([#887](https://github.com/callstack/linaria/issues/887)) ([7b8b129](https://github.com/callstack/linaria/commit/7b8b12937f9a0d1730d908e7cebad1684ccb03c3)) # [3.0.0-beta.15](https://github.com/callstack/linaria/compare/v3.0.0-beta.14...v3.0.0-beta.15) (2021-11-29) ### Bug Fixes - **react:** fixed types for supporting class components (fixes [#730](https://github.com/callstack/linaria/issues/730)) ([#877](https://github.com/callstack/linaria/issues/877)) ([e637ecb](https://github.com/callstack/linaria/commit/e637ecb8946a8119cfbd039bfb65d42206e09c4e)) # [3.0.0-beta.14](https://github.com/callstack/linaria/compare/v3.0.0-beta.13...v3.0.0-beta.14) (2021-11-05) ### Bug Fixes - **react:** refactor/rest op ([#860](https://github.com/callstack/linaria/issues/860)) ([da94704](https://github.com/callstack/linaria/commit/da94704df8ca74d94fe57682e2557274cf2d4cb0)) - **react:** unions in prop types are not resolved ([#844](https://github.com/callstack/linaria/issues/844)) ([62009e9](https://github.com/callstack/linaria/commit/62009e9184638fd8761f187c99e7ea434f364bee)) # [3.0.0-beta.13](https://github.com/callstack/linaria/compare/v3.0.0-beta.12...v3.0.0-beta.13) (2021-09-13) ### Bug Fixes - **react:** fixes for `--exactOptionalPropertyTypes` TS flag ([#827](https://github.com/callstack/linaria/issues/827)) ([eed92b1](https://github.com/callstack/linaria/commit/eed92b19e3b779b656fb780307bbab8a08d14ba2)) # [3.0.0-beta.11](https://github.com/callstack/linaria/compare/v3.0.0-beta.10...v3.0.0-beta.11) (2021-08-08) ### Bug Fixes - **styled:** remove unnecessary core-js polyfills (fixes [#799](https://github.com/callstack/linaria/issues/799)) ([#814](https://github.com/callstack/linaria/issues/814)) ([6c3070a](https://github.com/callstack/linaria/commit/6c3070a47715022eb761567b8795f6918784ae4c)) # [3.0.0-beta.7](https://github.com/callstack/linaria/compare/v3.0.0-beta.6...v3.0.0-beta.7) (2021-06-24) **Note:** Version bump only for package @linaria/react # [3.0.0-beta.4](https://github.com/callstack/linaria/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2021-05-07) **Note:** Version bump only for package @linaria/react # [3.0.0-beta.3](https://github.com/callstack/linaria/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2021-04-20) ### Bug Fixes - **core,react:** make IE 11 compatible (fixes [#746](https://github.com/callstack/linaria/issues/746)) ([#750](https://github.com/callstack/linaria/issues/750)) ([922df95](https://github.com/callstack/linaria/commit/922df9576a430cdfe9b27aed5dc45c4f75917607)) # [3.0.0-beta.2](https://github.com/callstack/linaria/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2021-04-11) **Note:** Version bump only for package @linaria/react ================================================ FILE: packages/react/README.md ================================================

Linaria

Zero-runtime CSS in JS library.

--- ### 📖 Please refer to the [GitHub](https://github.com/callstack/linaria#readme) for full documentation. ## Features - Write CSS in JS, but with **zero runtime**, CSS is extracted to CSS files during build - Familiar **CSS syntax** with Sass like nesting - Use **dynamic prop based styles** with the React bindings, uses CSS variables behind the scenes - Easily find where the style was defined with **CSS sourcemaps** - **Lint your CSS** in JS with [stylelint](https://github.com/stylelint/stylelint) - Use **JavaScript for logic**, no CSS preprocessor needed - Optionally use any **CSS preprocessor** such as Sass or PostCSS **[Why use Linaria](../../docs/BENEFITS.md)** ## Installation ```sh npm install @linaria/core @linaria/react @linaria/babel-preset ``` or ```sh yarn add @linaria/core @linaria/react @linaria/babel-preset ``` ================================================ FILE: packages/react/__dtslint-react17__/index.d.ts ================================================ // dtslint expects an `index.d.ts` in the test folder. ================================================ FILE: packages/react/__dtslint-react17__/react17.tsx ================================================ import { styled } from '..'; const Button = styled.button``; // Should not require `children` for intrinsic elements on React 17 projects. Button({}); ; ================================================ FILE: packages/react/__dtslint-react17__/stubs/jsx-runtime.d.ts ================================================ declare module 'react/jsx-runtime' { const Fragment: unknown; function jsx(type: unknown, props: unknown, key?: unknown): unknown; function jsxs(type: unknown, props: unknown, key?: unknown): unknown; } declare module 'react/jsx-dev-runtime' { const Fragment: unknown; function jsxDEV( type: unknown, props: unknown, key: unknown, isStaticChildren: boolean, source: unknown, self: unknown ): unknown; } ================================================ FILE: packages/react/__dtslint-react17__/stubs/react17.d.ts ================================================ // Minimal React 17-like type surface for dtslint. // It intentionally does NOT export a module-level `JSX` namespace. declare namespace React { type ElementType = unknown; interface CSSProperties { [key: string]: unknown; } interface FunctionComponent

> { (props: P & { children?: unknown }): unknown; } function createElement(...args: unknown[]): unknown; } export = React; export as namespace React; declare global { namespace JSX { interface IntrinsicElements { button: Record; } } } ================================================ FILE: packages/react/__dtslint-react17__/tsconfig.eslint.json ================================================ { "extends": "./tsconfig.json" } ================================================ FILE: packages/react/__dtslint-react17__/tsconfig.json ================================================ { "compilerOptions": { "module": "commonjs", "lib": ["es6"], "target": "ES2015", "jsx": "react-jsx", "noImplicitAny": true, "noImplicitThis": true, "strictNullChecks": true, "strictFunctionTypes": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "types": [], "noEmit": true, "baseUrl": "./", "paths": { "react": ["./stubs/react17.d.ts"], "react/jsx-runtime": ["./stubs/jsx-runtime.d.ts"], "react/jsx-dev-runtime": ["./stubs/jsx-runtime.d.ts"] } } } ================================================ FILE: packages/react/__dtslint__/index.d.ts ================================================ // dtslint wants to see index.d.ts. Well, here it is. declare const linaria: unknown; ================================================ FILE: packages/react/__dtslint__/styled.ts ================================================ /* tslint:disable:no-unnecessary-generics */ // eslint-disable-next-line import/no-extraneous-dependencies import * as React from 'react'; import { css } from '@linaria/core'; import { styled } from '..'; // eslint-disable-next-line @typescript-eslint/no-unused-vars function isExtends(arg1?: C, arg2?: T): C extends T ? 'extends' : never { // It will never be executed, so the result doesn't matter. return null as any; } const Fabric = >(): React.FC => (props) => React.createElement('div', props); const Header = (p: { children: string }) => React.createElement('h1', p); const Generic = ( p: T & { className?: string; style?: React.CSSProperties } ) => React.createElement('h1', p); const StyledDiv = styled.div``; // $ExpectType "extends" isExtends>>(); const A = (): React.ReactElement => React.createElement('div', null); // @ts-expect-error styled(A)``; // foo is not a valid property of div // @ts-expect-error React.createElement(StyledDiv, { foo: 'foo' }); const ReStyledDiv = styled(StyledDiv)<{ foo: string }>``; React.createElement(ReStyledDiv, { foo: 'foo' }); // component should have className property // @ts-expect-error styled(Fabric<{ a: string }>())``; // className property should be string // @ts-expect-error styled(Fabric<{ className: number }>())``; const SimplestComponent = styled(Fabric<{ className: string }>())``; // $ExpectType "extends" isExtends>(); styled(Fabric<{ className: string }>())` // component should have style property color: ${ // @ts-expect-error () => 'red' }; `; styled(Fabric<{ className: string }>())` // it looks like function, but it's a reference to another styled component & > ${SimplestComponent} { color: red; } `; styled(Fabric<{ className: string }>())` // it looks like the previous test, but it references a non-linaria component & > ${ // @ts-expect-error Header } { color: red; } `; styled(Fabric<{ className: string; style: {} }>())` color: ${() => 'red'}; `; styled(Fabric<{ className: string; style: {} }>())` // color should be defined in props color: ${ // @ts-expect-error (props) => props.color }; `; styled(Fabric<{ className: string; color: 'red' | 'blue'; style: {} }>())` & > ${SimplestComponent} { color: ${(props) => props.color}; } `; // $ExpectType number Generic({ children: 123 }).props.children; const StyledGeneric = styled(Generic)``; // $ExpectType number StyledGeneric({ children: 123 }).props.children; styled.a` & > ${SimplestComponent} { color: red; } `({ href: 'about:blank' }); ((/* Issue #536 */) => { const Title = styled.div<{ background: string }>` background: ${(props) => props.background}; `; // $ExpectType "extends" isExtends>(); css` ${Title} { color: green; } `; })(); ((/* Issue #622 */) => { const Wrapper = styled.div<{ prop1: boolean }>` width: 1em; background-color: ${(props) => (props.prop1 ? 'transparent' : 'green')}; `; const Custom: React.FC<{ className?: string; id: number }> = () => null; const tag = styled(Custom); const Card = tag` ${Wrapper} { color: green; } `; // $ExpectType Validator | undefined Card.propTypes!.id; const styledTag = styled(Wrapper); const NewWrapper = styledTag<{ prop2: string }>` width: 2em; background-color: ${(props) => (props.prop1 ? 'transparent' : 'red')}; color: ${(props) => props.prop2}; `; // $ExpectType Validator | undefined NewWrapper.propTypes!.prop1; // $ExpectType Validator | undefined NewWrapper.propTypes!.prop2; })(); ((/* Issue #844 */) => { type GridProps = { container?: false } | { container: true; spacing: number }; const Grid: React.FC = () => null; // Type 'false' is not assignable to type 'true' // @ts-expect-error React.createElement(Grid, { container: false, spacing: 8 }); React.createElement(Grid, { container: true, spacing: 8 }); styled(Grid)``; })(); ((/* Issue #872 */) => { interface BaseProps { className?: string; style?: React.CSSProperties; } interface ComponentProps extends BaseProps { title: string; } const Flow = (Cmp: React.FC) => styled(Cmp)` display: flow; `; const Component: React.FC = (props) => React.createElement('div', props); const Implementation = Flow(Component); (() => React.createElement(Implementation, { title: 'Title' }))(); })(); ================================================ FILE: packages/react/__dtslint__/tsconfig.eslint.json ================================================ { "extends": "./tsconfig.json" } ================================================ FILE: packages/react/__dtslint__/tsconfig.json ================================================ { "compilerOptions": { "module": "commonjs", "lib": ["es6"], "target": "ES2015", "esModuleInterop": true, "noImplicitAny": true, "noImplicitThis": true, "strictNullChecks": true, "strictFunctionTypes": true, "noUncheckedIndexedAccess": true, "noPropertyAccessFromIndexSignature": true, "noEmit": true, "baseUrl": "./" } } ================================================ FILE: packages/react/__tests__/__snapshots__/styled.test.tsx.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`applies CSS variables in style prop 1`] = `

This is a test
`; exports[`does not filter attributes for components 1`] = `
voila
`; exports[`does not filter attributes for kebab cased custom elements 1`] = ` This is a test `; exports[`does not filter attributes for unknown tag 1`] = ` This is a test `; exports[`does not filter attributes for upper camel cased custom elements 1`] = ` This is a test `; exports[`filters unknown html attributes for HTML tag 1`] = `
This is a test
`; exports[`forwards as prop when wrapping another styled component 1`] = ` This is a test `; exports[`handles wrapping another styled component 1`] = `
This is a test
`; exports[`merges CSS variables with custom style prop 1`] = `
This is a test
`; exports[`provides linaria component className for composition as last item in props.className 1`] = `
original classname used for composition
`; exports[`renders component with display name and class name 1`] = `
This is a test
`; exports[`renders tag with display name and class name 1`] = `

This is a test

`; exports[`replaces custom component with as prop for primitive 1`] = ` This is a test `; exports[`replaces primitive with as prop for custom component 1`] = `
This is a test
`; exports[`replaces simple component with as prop 1`] = ` This is a test `; exports[`supports extra class prop 1`] = `
This is a test
`; exports[`supports extra className prop 1`] = `
This is a test
`; ================================================ FILE: packages/react/__tests__/detect-core-js.test.ts ================================================ import cp from 'child_process'; const waitForProcess = async (process) => { return new Promise((resolve) => { let output = ''; process.stdout.on('data', (chunk) => { output += chunk.toString(); }); process.on('close', () => { resolve(output); }); }); }; it('Ensures that package do not include core-js dependency after build', async () => { // eslint-disable-next-line import/no-extraneous-dependencies const packageJSON = require('@linaria/react/package.json'); const buildScript = packageJSON.scripts['build:corejs-test']; const proc = cp.exec(buildScript, { stdio: 'ignore', env: { ...process.env, DEBUG_CORE_JS: 'true', }, }); const result = await waitForProcess(proc); // run `DEBUG_CORE_JS=true yarn build:lib` to debug issues with introduced core-js dependency expect(result).not.toContain( 'The corejs3 polyfill added the following polyfills' ); expect(result).toContain( 'Based on your code and targets, the corejs3 polyfill did not add any polyfill' ); }, 15000); ================================================ FILE: packages/react/__tests__/styled.test.tsx ================================================ import React from 'react'; import { omit } from '../src/styled'; const renderer = require('react-test-renderer'); const { styled } = require('../src'); it('renders tag with display name and class name', () => { const Test = styled('h1')({ name: 'TestComponent', class: 'abcdefg', }); expect(Test.displayName).toBe('TestComponent'); expect(Test.__wyw_meta.className).toBe('abcdefg'); expect(Test.__wyw_meta.extends).toBe('h1'); const tree = renderer.create(This is a test); expect(tree.toJSON()).toMatchSnapshot(); }); it('renders component with display name and class name', () => { const Custom: React.FC = (props) =>
; const Test = styled(Custom)({ name: 'TestComponent', class: 'abcdefg', }); expect(Test.displayName).toBe('TestComponent'); expect(Test.__wyw_meta.className).toBe('abcdefg'); expect(Test.__wyw_meta.extends).toBe(Custom); const tree = renderer.create(This is a test); expect(tree.toJSON()).toMatchSnapshot(); }); it('applies CSS variables in style prop', () => { const Test = styled('div')({ name: 'TestComponent', class: 'abcdefg', vars: { foo: ['tomato'], bar: [20, 'px'], baz: [(props: { size: number }) => props.size, 'px'], }, }); const tree = renderer.create(This is a test); expect(tree.toJSON()).toMatchSnapshot(); }); it('merges CSS variables with custom style prop', () => { const Test = styled('div')({ name: 'TestComponent', class: 'abcdefg', vars: { foo: ['tomato'], }, }); const tree = renderer.create( This is a test ); expect(tree.toJSON()).toMatchSnapshot(); }); it('supports extra className prop', () => { const Test = styled('div')({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create(This is a test); expect(tree.toJSON()).toMatchSnapshot(); }); it('supports extra class prop', () => { const Test = styled('div')({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create(This is a test); expect(tree.toJSON()).toMatchSnapshot(); }); it('replaces simple component with as prop', () => { const Test = styled('button')({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create( This is a test ); expect(tree.toJSON()).toMatchSnapshot(); }); it('replaces custom component with as prop for primitive', () => { const Custom: React.FC = (props) => (
); const Test = styled(Custom)({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create( This is a test ); expect(tree.toJSON()).toMatchSnapshot(); }); it('replaces primitive with as prop for custom component', () => { const Custom: React.FC = (props) => (
); const Test = styled('div')({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create( This is a test ); expect(tree.toJSON()).toMatchSnapshot(); }); it('handles wrapping another styled component', () => { const First = styled('div')({ name: 'FirstComponent', class: 'abcdefg', }); const Second = styled(First)({ name: 'SecondComponent', class: 'hijklmn', }); const tree = renderer.create(This is a test); expect(tree.toJSON()).toMatchSnapshot(); }); it('forwards as prop when wrapping another styled component', () => { const First = styled('div')({ name: 'FirstComponent', class: 'abcdefg', }); const Second = styled(First)({ name: 'SecondComponent', class: 'hijklmn', }); const tree = renderer.create(This is a test); expect(tree.toJSON()).toMatchSnapshot(); }); it('filters unknown html attributes for HTML tag', () => { const Test = styled('div')({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create( This is a test ); expect(tree.toJSON()).toMatchSnapshot(); }); it('does not filter attributes for kebab cased custom elements', () => { const Test = styled('my-element')({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create( This is a test ); expect(tree.toJSON()).toMatchSnapshot(); }); it('does not filter attributes for upper camel cased custom elements', () => { const Test = styled('View')({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create(This is a test); expect(tree.toJSON()).toMatchSnapshot(); }); it('does not filter attributes for unknown tag', () => { const Test = styled('definitelyunknowntag')({ name: 'TestComponent', class: 'abcdefg', propsAsIs: true, }); const tree = renderer.create(This is a test); expect(tree.toJSON()).toMatchSnapshot(); }); it('does not filter attributes for components', () => { const Custom: React.FC<{ unknownAttribute: string }> = (props) => (
{props.unknownAttribute}
); const Test = styled(Custom)({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create( This is a test ); expect(tree.toJSON()).toMatchSnapshot(); }); it('provides linaria component className for composition as last item in props.className', () => { const Custom: React.FC<{ className: string }> = (props) => { const classnames = props.className.split(' '); const linariaClassName = classnames[classnames.length - 1]; const newClassNames = [ props.className, `${linariaClassName}--primary`, `${linariaClassName}--accessibility`, ].join(' '); return (
original classname used for composition
); }; const Test = styled(Custom)({ name: 'TestComponent', class: 'abcdefg', }); const tree = renderer.create( This is a test ); expect(tree.toJSON()).toMatchSnapshot(); }); it('throws when using as tag for template literal', () => { // styled uses process.env.NODE_ENV to determine if it's running in a test environment const nodeEnv = process.env.NODE_ENV; delete process.env.NODE_ENV; expect( () => styled('div')` color: blue; ` ).toThrow('Using the "styled" tag in runtime is not supported'); expect( () => styled.div` color: blue; ` ).toThrow('Using the "styled" tag in runtime is not supported'); process.env.NODE_ENV = nodeEnv; }); it('can get rest keys from object', () => { const obj = { one: 1, two: 2, three: 3 }; const rest = omit(obj, ['two']); // eslint-disable-next-line no-unused-vars const { two, ...expectedRest } = obj; expect(rest).toEqual(expectedRest); }); it('can get rest keys from complex object', () => { const obj = { string: 'hello', bool: false, object: { hello: 'world' }, arr: [1, 2, 3], num: 47, }; const rest = omit(obj, ['bool', 'object', 'arr']); // eslint-disable-next-line no-unused-vars const { bool, object, arr, ...expectedRest } = obj; expect(rest).toEqual(expectedRest); }); ================================================ FILE: packages/react/babel.config.js ================================================ const config = require('../../babel.config'); module.exports = config; ================================================ FILE: packages/react/package.json ================================================ { "name": "@linaria/react", "version": "7.0.1", "description": "Blazing fast zero-runtime CSS in JS library", "keywords": [ "css", "css-in-js", "linaria", "react", "styled-components" ], "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "sideEffects": false, "exports": { "./package.json": "./package.json", ".": { "types": "./types/index.d.ts", "import": "./dist/index.mjs", "default": "./dist/index.js" }, "./*": { "types": "./types/*.d.ts", "import": "./dist/*.mjs", "default": "./dist/*.js" } }, "main": "dist/index.js", "module": "dist/index.mjs", "types": "types/index.d.ts", "typesVersions": { "*": { "processors/*": [ "./types/processors/*.d.ts" ] } }, "files": [ "dist/", "processors/", "types/" ], "wyw-in-js": { "tags": { "styled": "./dist/processors/styled.js" } }, "scripts": { "build": "pnpm build:dist && pnpm build:declarations", "build:corejs-test": "cross-env NODE_ENV=legacy babel src --out-dir lib --extensions '.js,.jsx,.ts,.tsx' --ignore \"src/processors/**/*\"", "build:declarations": "tsc --emitDeclarationOnly --outDir types", "build:dist": "tsup --format cjs,esm", "test": "jest --config ../../jest.config.js --rootDir .", "test:dts": "dtslint --localTs ../../node_modules/typescript/lib __dtslint__ && dtslint --localTs ../../node_modules/typescript/lib __dtslint-react17__", "typecheck": "tsc --noEmit --composite false", "watch": "pnpm build:dist --watch & pnpm build:declarations --watch" }, "dependencies": { "@emotion/is-prop-valid": "^1.2.0", "@linaria/core": "workspace:^", "@wyw-in-js/processor-utils": "^1.0.4", "@wyw-in-js/shared": "^1.0.4", "minimatch": "^9.0.3", "react-html-attributes": "^1.4.6", "resolve": "^1.22.8", "ts-invariant": "^0.10.3" }, "devDependencies": { "@babel/types": "^7.23.5", "@types/babel__core": "^7.20.5", "@types/node": "^17.0.39", "@types/react": ">=16", "react": "^16.14.0", "react-test-renderer": "^16.8.3" }, "peerDependencies": { "react": ">=16" }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" }, "tsup": { "entry": [ "src/index.ts", "src/processors/styled.ts" ], "splitting": false, "sourcemap": true, "clean": true } } ================================================ FILE: packages/react/processors/styled.js ================================================ Object.defineProperty(exports, '__esModule', { value: true, }); exports.default = require('../dist/processors/styled').default; ================================================ FILE: packages/react/src/index.ts ================================================ export { default as styled } from './styled'; export type { HtmlStyledTag, StyledComponent, StyledJSXIntrinsics, Styled, } from './styled'; export type { CSSProperties } from '@linaria/core'; export type { WYWEvalMeta } from '@wyw-in-js/shared'; ================================================ FILE: packages/react/src/processors/styled.ts ================================================ import { readFileSync } from 'fs'; import { dirname, join, posix } from 'path'; import type { CallExpression, Expression, ObjectExpression, SourceLocation, StringLiteral, Identifier, } from '@babel/types'; import { buildSlug, TaggedTemplateProcessor, validateParams, toValidCSSIdentifier, } from '@wyw-in-js/processor-utils'; import type { Params, Rules, TailProcessorParams, ValueCache, } from '@wyw-in-js/processor-utils'; import type { IVariableContext } from '@wyw-in-js/shared'; import { findPackageJSON, hasEvalMeta, slugify, ValueType, } from '@wyw-in-js/shared'; import { minimatch } from 'minimatch'; import html from 'react-html-attributes'; import { sync as resolveSync } from 'resolve'; const isNotNull = (x: T | null): x is T => x !== null; const allTagsSet = new Set([...html.elements.html, html.elements.svg]); export type WrappedNode = | string | { node: Identifier; nonLinaria?: true; source: string }; export interface IProps { atomic?: boolean; class?: string; name: string; propsAsIs: boolean; vars?: Record; } const singleQuotedStringLiteral = (value: string): StringLiteral => ({ type: 'StringLiteral', value, extra: { rawValue: value, raw: `'${value}'`, }, }); export default class StyledProcessor extends TaggedTemplateProcessor { public component: WrappedNode; #variableIdx = 0; #variablesCache = new Map(); constructor(params: Params, ...args: TailProcessorParams) { // Should have at least two params and the first one should be a callee. validateParams( params, ['callee', '*', '...'], TaggedTemplateProcessor.SKIP ); validateParams( params, ['callee', ['call', 'member'], ['template', 'call']], 'Invalid usage of `styled` tag' ); const [tag, tagOp, template] = params; if (template[0] === 'call') { // It is already transformed styled-literal. Skip it. // eslint-disable-next-line @typescript-eslint/no-throw-literal throw TaggedTemplateProcessor.SKIP; } super([tag, template], ...args); let component: WrappedNode | undefined; if (tagOp[0] === 'call' && tagOp.length === 2) { const value = tagOp[1]; if (value.kind === ValueType.FUNCTION) { component = 'FunctionalComponent'; } else if (value.kind === ValueType.CONST) { component = typeof value.value === 'string' ? value.value : undefined; } else { if (value.importedFrom?.length) { const selfPkg = findPackageJSON('.', this.context.filename); // Check if at least one used identifier is a Linaria component. const isSomeMatched = value.importedFrom.some((importedFrom) => { const importedPkg = // If package.json is not found, assume it's a local package findPackageJSON(importedFrom, this.context.filename) ?? selfPkg; if (importedPkg) { const packageJSON = JSON.parse(readFileSync(importedPkg, 'utf8')); const mask: string | undefined = packageJSON?.linaria?.components; if (importedPkg === selfPkg && mask === undefined) { // If mask is not specified for the local package, all components are treated as styled. return true; } if (mask) { const packageDir = dirname(importedPkg); // Masks for minimatch should always use POSIX slashes const fullMask = join(packageDir, mask).replace( /\\/g, posix.sep ); try { const fileWithComponent = resolveSync(importedFrom, { basedir: dirname(this.context.filename!), extensions: this.options.extensions, }); return minimatch(fileWithComponent, fullMask); } catch (e) { // It means that resolver can't find the file. // eslint-disable-next-line no-console console.warn( `Can't resolve ${importedFrom} from ${this.context.filename}. If ${value.source} is another styled component, it should be resolvable with default Node.js resolver. If it's not, please exclude it from the linaria.components mask in package.json.` ); return false; } } } return false; }); if (!isSomeMatched) { component = { node: value.ex, nonLinaria: true, source: value.source, }; } } if (component === undefined) { component = { node: value.ex, source: value.source, }; this.dependencies.push(value); } } } if (tagOp[0] === 'member') { [, component] = tagOp; } if (!component) { throw new Error('Invalid usage of `styled` tag'); } this.component = component; } public override get asSelector(): string { return `.${this.className}`; } public override get value(): ObjectExpression { const t = this.astService; const extendsNode = typeof this.component === 'string' || this.component.nonLinaria ? null : this.component.node.name; return t.objectExpression([ t.objectProperty( t.stringLiteral('displayName'), t.stringLiteral(this.displayName) ), t.objectProperty( t.stringLiteral('__wyw_meta'), t.objectExpression([ t.objectProperty( t.stringLiteral('className'), t.stringLiteral(this.className) ), t.objectProperty( t.stringLiteral('extends'), extendsNode ? t.callExpression(t.identifier(extendsNode), []) : t.nullLiteral() ), ]) ), ]); } protected get tagExpression(): CallExpression { const t = this.astService; return t.callExpression(this.callee, [this.tagExpressionArgument]); } protected get tagExpressionArgument(): Expression { const t = this.astService; if (typeof this.component === 'string') { if (this.component === 'FunctionalComponent') { return t.arrowFunctionExpression([], t.blockStatement([])); } return singleQuotedStringLiteral(this.component); } return t.callExpression(t.identifier(this.component.node.name), []); } public override addInterpolation( node: Expression, precedingCss: string, source: string, unit = '' ): string { const id = this.getVariableId(source, unit, precedingCss); this.interpolations.push({ id, node, source, unit, }); return id; } public override doEvaltimeReplacement(): void { this.replacer(this.value, false); } public override doRuntimeReplacement(): void { const t = this.astService; const props = this.getProps(); this.replacer( t.callExpression(this.tagExpression, [this.getTagComponentProps(props)]), true ); } public override extractRules( valueCache: ValueCache, cssText: string, loc?: SourceLocation | null ): Rules { const rules: Rules = {}; let selector = `.${this.className}`; // If `styled` wraps another component and not a primitive, // get its class name to create a more specific selector // it'll ensure that styles are overridden properly let value = typeof this.component === 'string' || this.component.nonLinaria ? null : valueCache.get(this.component.node.name); while (hasEvalMeta(value)) { selector += `.${value.__wyw_meta.className}`; value = value.__wyw_meta.extends; } rules[selector] = { cssText, className: this.className, displayName: this.displayName, start: loc?.start ?? null, }; return rules; } public override toString(): string { const res = (arg: string) => `${this.tagSourceCode()}(${arg})\`…\``; if (typeof this.component === 'string') { if (this.component === 'FunctionalComponent') { return res('() => {…}'); } return res(`'${this.component}'`); } return res(this.component.source); } protected getCustomVariableId( source: string, unit: string, precedingCss: string ) { const context = this.getVariableContext(source, unit, precedingCss); const customSlugFn = this.options.variableNameSlug; if (!customSlugFn) { return undefined; } return typeof customSlugFn === 'function' ? customSlugFn(context) : buildSlug(customSlugFn, { ...context }); } protected getProps(): IProps { const propsObj: IProps = { name: this.displayName, class: this.className, propsAsIs: typeof this.component !== 'string' || !allTagsSet.has(this.component), }; // If we found any interpolations, also pass them, so they can be applied if (this.interpolations.length) { propsObj.vars = {}; this.interpolations.forEach(({ id, unit, node }) => { const items: Expression[] = [this.astService.callExpression(node, [])]; if (unit) { items.push(this.astService.stringLiteral(unit)); } propsObj.vars![id] = items; }); } return propsObj; } protected getTagComponentProps(props: IProps): ObjectExpression { const t = this.astService; const propExpressions = Object.entries(props) .map(([key, value]: [key: string, value: IProps[keyof IProps]]) => { if (value === undefined) { return null; } const keyNode = t.identifier(key); if (value === null) { return t.objectProperty(keyNode, t.nullLiteral()); } if (typeof value === 'string') { return t.objectProperty(keyNode, t.stringLiteral(value)); } if (typeof value === 'boolean') { return t.objectProperty(keyNode, t.booleanLiteral(value)); } const vars = Object.entries(value).map(([propName, propValue]) => { return t.objectProperty( t.stringLiteral(propName), t.arrayExpression(propValue) ); }); return t.objectProperty(keyNode, t.objectExpression(vars)); }) .filter(isNotNull); return t.objectExpression(propExpressions); } protected getVariableContext( source: string, unit: string, precedingCss: string ): IVariableContext { const getIndex = () => { // eslint-disable-next-line no-plusplus return this.#variableIdx++; }; return { componentName: this.displayName, componentSlug: this.slug, get index() { return getIndex(); }, precedingCss, processor: this.constructor.name, source, unit, valueSlug: slugify(source + unit), }; } protected getVariableId( source: string, unit: string, precedingCss: string ): string { const value = source + unit; if (!this.#variablesCache.has(value)) { const id = this.getCustomVariableId(source, unit, precedingCss); if (id) { return toValidCSSIdentifier(id); } const context = this.getVariableContext(source, unit, precedingCss); // make the variable unique to this styled component this.#variablesCache.set(value, `${this.slug}-${context.index}`); } return this.#variablesCache.get(value)!; } } ================================================ FILE: packages/react/src/react-html-attributes.d.ts ================================================ declare module 'react-html-attributes' { interface IElements { html: string[]; svg: string[]; } interface IAttributes { [tag: string]: string[]; } const result: IAttributes & { elements: IElements; }; export = result; } ================================================ FILE: packages/react/src/styled.ts ================================================ /* eslint-disable @typescript-eslint/no-explicit-any */ /** * This file contains a runtime version of `styled` component. Responsibilities of the component are: * - returns ReactElement based on HTML tag used with `styled` or custom React Component * - injects classNames for the returned component * - injects CSS variables used to define dynamic styles based on props */ import validAttr from '@emotion/is-prop-valid'; import { createElement, forwardRef } from 'react'; import type React from 'react'; import { cx } from '@linaria/core'; import type { CSSProperties } from '@linaria/core'; type WYWEvalMeta = { __wyw_meta: unknown }; // simplified version of WYWEvalMeta from @wyw-in-js/shared export type NoInfer = [A][A extends any ? 0 : never]; type Component = | ((props: TProps) => unknown) | { new (props: TProps): unknown }; type Has = [T] extends [TObj] ? T : T & TObj; type Options = { atomic?: boolean; class: string; name: string; propsAsIs: boolean; vars?: { [key: string]: [ string | number | ((props: unknown) => string | number), string | void, ]; }; }; const isCapital = (ch: string): boolean => ch.toUpperCase() === ch; const filterKey = (keys: TExclude[]) => (key: TAll): key is Exclude => keys.indexOf(key as any) === -1; export const omit = , TKeys extends keyof T>( obj: T, keys: TKeys[] ): Omit => { const res = {} as Omit; Object.keys(obj) .filter(filterKey(keys)) .forEach((key) => { res[key] = obj[key]; }); return res; }; function filterProps, TKeys extends keyof T>( asIs: boolean, props: T, omitKeys: TKeys[] ): Partial> { const filteredProps = omit(props, omitKeys) as Partial; if (!asIs) { /** * A failsafe check for esModule import issues * if validAttr !== 'function' then it is an object of { default: Fn } */ const interopValidAttr = typeof validAttr === 'function' ? { default: validAttr } : validAttr; Object.keys(filteredProps).forEach((key) => { if (!interopValidAttr.default(key)) { // Don't pass through invalid attributes to HTML elements delete filteredProps[key]; } }); } return filteredProps; } const warnIfInvalid = (value: unknown, componentName: string) => { if (process.env.NODE_ENV !== 'production') { if ( typeof value === 'string' || // eslint-disable-next-line no-self-compare,no-restricted-globals (typeof value === 'number' && isFinite(value)) ) { return; } const stringified = typeof value === 'object' ? JSON.stringify(value) : String(value); // eslint-disable-next-line no-console console.warn( `An interpolation evaluated to '${stringified}' in the component '${componentName}', which is probably a mistake. You should explicitly cast or transform the value to a string.` ); } }; interface IProps { [props: string]: unknown; className?: string; style?: Record; } declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace JSX { interface IntrinsicElements {} } } let idx = 0; type GlobalJSXIntrinsicElements = JSX.IntrinsicElements; declare module 'react' { // eslint-disable-next-line @typescript-eslint/no-namespace namespace JSX { interface IntrinsicElements extends GlobalJSXIntrinsicElements {} } } type IntrinsicElements = React.JSX.IntrinsicElements; // Components with props are not allowed function styled( componentWithStyle: () => any ): (error: 'The target component should have a className prop') => void; // Property-based interpolation is allowed only if `style` property exists function styled< TProps extends Has, TMustHave extends { style?: React.CSSProperties }, TConstructor extends Component, >( componentWithStyle: TConstructor & Component ): ComponentStyledTagWithInterpolation; // If styled wraps custom component, that component should have className property function styled< TProps extends Has, TMustHave extends { className?: string }, TConstructor extends Component, >( componentWithoutStyle: TConstructor & Component ): ComponentStyledTagWithoutInterpolation; function styled( tag: TName ): HtmlStyledTag; function styled( component: 'The target component should have a className prop' ): never; function styled(tag: any): any { let mockedClass = ''; if (process.env.NODE_ENV === 'test') { // eslint-disable-next-line no-plusplus mockedClass += `mocked-styled-${idx++}`; if (tag && tag.__wyw_meta && tag.__wyw_meta.className) { mockedClass += ` ${tag.__wyw_meta.className}`; } } return (options: Options) => { if ( process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test' ) { if (Array.isArray(options)) { // We received a strings array since it's used as a tag throw new Error( 'Using the "styled" tag in runtime is not supported. Make sure you have set up the Babel plugin correctly. See https://github.com/callstack/linaria#setup' ); } } const render = (props: any, ref: any) => { const { as: component = tag, class: className = mockedClass } = props; const shouldKeepProps = options.propsAsIs === undefined ? !( typeof component === 'string' && component.indexOf('-') === -1 && !isCapital(component[0]) ) : options.propsAsIs; const filteredProps: IProps = filterProps(shouldKeepProps, props, [ 'as', 'class', ]); filteredProps.ref = ref; filteredProps.className = options.atomic ? cx(options.class, filteredProps.className || className) : cx(filteredProps.className || className, options.class); const { vars } = options; if (vars) { const style: Record = {}; // eslint-disable-next-line guard-for-in,no-restricted-syntax for (const name in vars) { const variable = vars[name]; const result = variable[0]; const unit = variable[1] || ''; const value = typeof result === 'function' ? result(props) : result; warnIfInvalid(value, options.name); style[`--${name}`] = `${value}${unit}`; } const ownStyle = filteredProps.style || {}; const keys = Object.keys(ownStyle); if (keys.length > 0) { keys.forEach((key) => { style[key] = ownStyle[key]; }); } filteredProps.style = style; } if ((tag as any).__wyw_meta && tag !== component) { // If the underlying tag is a styled component, forward the `as` prop // Otherwise the styles from the underlying component will be ignored filteredProps.as = component; return createElement(tag, filteredProps); } return createElement(component, filteredProps); }; const Result = forwardRef ? forwardRef(render) : // React.forwardRef won't available on older React versions and in Preact // Fallback to a innerRef prop in that case (props: any) => { const rest = omit(props, ['innerRef']); return render(rest, props.innerRef); }; (Result as any).displayName = options.name; // These properties will be read by the babel plugin for interpolation (Result as any).__wyw_meta = { className: options.class || mockedClass, extends: tag, }; return Result; }; } export type StyledComponent = WYWEvalMeta & ([T] extends [React.FunctionComponent] ? T : React.FunctionComponent); type StaticPlaceholder = string | number | CSSProperties | WYWEvalMeta; export type HtmlStyledTag = < TAdditionalProps = Record, >( strings: TemplateStringsArray, ...exprs: Array< | StaticPlaceholder | (( // Without Omit here TS tries to infer TAdditionalProps // from a component passed for interpolation props: IntrinsicElements[TName] & Omit ) => string | number) > ) => StyledComponent; type ComponentStyledTagWithoutInterpolation = ( strings: TemplateStringsArray, ...exprs: Array< | StaticPlaceholder | ((props: 'The target component should have a style prop') => never) > ) => WYWEvalMeta & TOrigCmp; // eslint-disable-next-line @typescript-eslint/ban-types type ComponentStyledTagWithInterpolation = ( strings: TemplateStringsArray, ...exprs: Array< | StaticPlaceholder | ((props: NoInfer) => string | number) > ) => keyof OwnProps extends never ? WYWEvalMeta & TOrigCmp : StyledComponent; export type StyledJSXIntrinsics = { readonly [P in keyof IntrinsicElements]: HtmlStyledTag

; }; export type Styled = typeof styled & StyledJSXIntrinsics; export default (process.env.NODE_ENV !== 'production' ? new Proxy(styled, { get(o, prop: keyof IntrinsicElements) { return o(prop); }, }) : styled) as Styled; ================================================ FILE: packages/react/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "paths": {}, "rootDir": "src/", "types": [ "node" ], }, "include": ["src"], "references": [{ "path": "../core" }] } ================================================ FILE: packages/server/CHANGELOG.md ================================================ # Change Log ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ## 6.0.0 ### Major Changes - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 ## 4.5.0 ### Minor Changes - 16c057df: Breaking Change: Performance Optimization for `styled` When a component is wrapped in `styled`, Linaria needs to determine if that component is already a styled component. To accomplish this, the wrapped component is included in the list of variables for evaluation, along with the interpolated values used in styles. The issue arises when a wrapped component, even if it is not styled, brings along a substantial dependency tree. This situation is particularly evident when using `styled` to style components from third-party UI libraries. To address this problem, Linaria will now examine the import location of the component and check if there is an annotation in the `package.json` file of the package containing the components. This annotation indicates whether the package includes other Linaria components. If there is no such annotation, Linaria will refrain from evaluating the component. Please note that this Breaking Change solely affects developers of component libraries. In order for users to style components from your library, you must include the `linaria.components` property in the library's `package.json` file. This property should have a mask that covers all imported files with components. Here's an example of how to specify it: ```json "linaria": { "components": "**/*" } ``` ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. ## 4.1.0 ### Minor Changes - 77bcf2e7: - 714a8e86: Modify the handling of CSS @ rules in `collect` to only include child rules if critical - 1559cfa9: Add support in `collect` for ignoring and blocking classes from the regex for critical CSS extraction ## 4.0.0 ### Major Changes - bc0cbeea: A completely new async mode with native support for Vite, Rollup, esbuild and Webpack resolvers. BREAKING CHANGES: Despite the fact, that it should be fully compatible with 3.0 and 2.0 branches, the new version of styles evaluator can have some serious bugs which can make your project unbuildable (however, since there is no runtime, if the build is finished successfully, everything will continue work as it was on 2.0 and 3.0). If you face some problems please let us know and we will fix it as soon as possible. ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - ea41d440: New package @linaria/tags that contains all abstract logic for tags processors. - 4cdf0315: Tagged template-specific logic has been moved from `BaseProcessor` to `TaggedTemplateProcessor`. `BaseProcessor` now can be used to define any type of expressions for zero-runtime transformations, such as `makeStyles` from `@griffel/react`. ## 3.0.0-beta.20 ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo # [3.0.0-beta.19](https://github.com/callstack/linaria/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2022-06-03) ### Features - **babel:** api for custom tags ([#976](https://github.com/callstack/linaria/issues/976)) ([3285ccc](https://github.com/callstack/linaria/commit/3285ccc1d00449b78b3fc74087528cd38cbdd116)) - **babel:** new way for detecting tag imports ([#974](https://github.com/callstack/linaria/issues/974)) ([3305cfb](https://github.com/callstack/linaria/commit/3305cfb0c0f65abdacceeb7e6bad118c59f7d551)) # [3.0.0-beta.13](https://github.com/callstack/linaria/compare/v3.0.0-beta.12...v3.0.0-beta.13) (2021-09-13) ### Bug Fixes - **server:** fix collect to ignore empty class ([#832](https://github.com/callstack/linaria/issues/832)) ([639fcca](https://github.com/callstack/linaria/commit/639fccae7f814eaa2714354aaa516a85cc8c4ebf)) # [3.0.0-beta.3](https://github.com/callstack/linaria/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2021-04-20) **Note:** Version bump only for package @linaria/server ================================================ FILE: packages/server/README.md ================================================

Linaria

Zero-runtime CSS in JS library.

--- ### 📖 Please refer to the [GitHub](https://github.com/callstack/linaria#readme) for full documentation. ## Features - Write CSS in JS, but with **zero runtime**, CSS is extracted to CSS files during build - Familiar **CSS syntax** with Sass like nesting - Use **dynamic prop based styles** with the React bindings, uses CSS variables behind the scenes - Easily find where the style was defined with **CSS sourcemaps** - **Lint your CSS** in JS with [stylelint](https://github.com/stylelint/stylelint) - Use **JavaScript for logic**, no CSS preprocessor needed - Optionally use any **CSS preprocessor** such as Sass or PostCSS **[Why use Linaria](../../docs/BENEFITS.md)** ## Installation ```sh npm install @linaria/core @linaria/react @linaria/babel-preset ``` or ```sh yarn add @linaria/core @linaria/react @linaria/babel-preset ``` ================================================ FILE: packages/server/__tests__/__snapshots__/collect.test.ts.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`classname in @rule critical 1`] = ` "@supports (object-fit: cover) { .linaria { } } @media (min-width: 600px) { .linaria { } } @charset() { .linaria { } } @import() { .linaria { } } @namespace () { .linaria { } } @media() { .linaria { } } @supports () { .linaria { } } @document() { .linaria { } } @page() { .linaria { } } @viewport() { .linaria { } } @counter-style() { .linaria { } } @font-feature-values() { .linaria { } } " `; exports[`classname in @rule other 1`] = ` "@supports (object-fit: cover) { .other { } } @media (min-width: 600px) { .other { } } @charset() { .other { } } @import() { .other { } } @namespace () { .other { } } @media() { .other { } } @supports () { .other { } } @document() { .other { } } @page() { .other { } } @viewport() { .other { } } @counter-style() { .other { } } @font-feature-values() { .other { } } " `; exports[`collects complex css critical 1`] = ` ".lotus { vertical-align: top; } @media (max-width: 1200px) { .lotus { vertical-align: bottom; } } @supports (object-fit: contain) { .lotus { object-fit: contain; } .linaria::before, .linaria::after { content: \\"\\"; object-fit: contain; } } .linaria { float: left; flex: 1; animation: custom-animation 0.2s; } .linaria:hover { float: right; } .linaria > span, .linaria + .linaria, .linaria ~ div { display: none; } .linaria > span { display: none; } .linaria::after { display: block; } .lily { color: #fff; } [data-theme=\\"dark\\"] .lily { color: #000; } .linaria ~ div { } .linaria.linaria2 { } @keyframes custom-animation { 0% { opacity: 0; } 50% { opacity: 0; } 100% { opacity: 1; } } " `; exports[`collects complex css other 1`] = ` "@supports (object-fit: cover) { .unrelated-nested { float: left; animation: custom-animation; } .unrelated-nested2 { float: left; } } .unrelated { animation-name: custom-animation; } .unrelated2 { animation: custom-animation 0.3s; } .unrelated3 { flex: 0; } " `; exports[`handles top-level @font-face critical 1`] = ` "@font-face { font-family: MyFont; font-weight: normal; font-style: normal; src: url(MyFont.woff); } " `; exports[`handles top-level @font-face other 1`] = `""`; exports[`include atrule once critical 1`] = ` "@media screen { body { font-size: 10px; } h1 { font-size: 20px; } } " `; exports[`include atrule once other 1`] = ` "@media screen { .class { font-size: 15px; } } " `; exports[`simple class name critical 1`] = ` ".linaria { } " `; exports[`simple class name other 1`] = ` ".classname { } " `; exports[`works with CSS combinators critical 1`] = ` ".linaria + span { } .linaria ~ div { } .linaria > a { } .linaria b { } " `; exports[`works with CSS combinators other 1`] = ` ".other + span { } .other ~ div { } .other > a { } .other b { } " `; exports[`works with global css critical 1`] = ` "body { font-size: 13.37px; } html { -webkit-font-smoothing: antialiased; } h1 { font-weight: bold; } .linaria:active { } .linaria::before { } " `; exports[`works with global css other 1`] = ` ".other:active { } .other::before { } " `; exports[`works with pseudo-class and pseudo-elements critical 1`] = ` ".linaria:active { } .linaria::before { } " `; exports[`works with pseudo-class and pseudo-elements other 1`] = ` ".other:active { } .other::before { } " `; ================================================ FILE: packages/server/__tests__/collect.test.ts ================================================ import dedent from 'dedent'; import prettier from 'prettier'; import collect from '../src/collect'; const prettyPrint = (src: string) => prettier.format(src, { parser: 'scss' }); const testCollect = (html: string, css: string) => { const { critical, other } = collect(html, css); test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot()); test('other', () => expect(prettyPrint(other)).toMatchSnapshot()); }; const html = dedent`
`; describe('collects complex css', () => { const css = dedent` .lotus { vertical-align: top; } @media (max-width: 1200px) { .lotus { vertical-align: bottom; } } @supports (object-fit: cover) { .unrelated-nested { float: left; animation: custom-animation; } .unrelated-nested2 { float: left; } } @supports (object-fit: contain) { .lotus { object-fit: contain; } .linaria::before, .linaria::after { content: ''; object-fit: contain; } } @keyframes custom-animation { 0% { opacity: 0 } 50% { opacity: 0 } 100% { opacity: 1 } } .linaria { float: left; flex: 1; animation: custom-animation .2s; } .linaria:hover { float: right; } .linaria > span, .linaria + .linaria, .linaria ~ div { display: none; } .linaria > span { display: none; } .linaria::after { display: block; } .unrelated { animation-name: custom-animation; } .unrelated2 { animation: custom-animation .3s; } .lily { color: #fff; } [data-theme=dark] .lily { color: #000; } .unrelated3 { flex: 0; } .linaria ~ div {} .linaria.linaria2{} `; testCollect(html, css); }); describe('simple class name', () => { const css = dedent` .linaria {} .classname {} `; testCollect(html, css); }); describe('classname in @rule', () => { const css = dedent` @supports (object-fit: cover) { .linaria {} } @media (min-width: 600px) { .linaria {} } @charset () { .linaria {} } @import () { .linaria {} } @namespace () { .linaria {} } @media () { .linaria {} } @supports () { .linaria {} } @document () { .linaria {} } @page () { .linaria {} } @keyframes () { .linaria {} } @viewport () { .linaria {} } @counter-style () { .linaria {} } @font-feature-values () { .linaria {} } @supports (object-fit: cover) { .other {} } @media (min-width: 600px) { .other {} } @charset () { .other {} } @import () { .other {} } @namespace () { .other {} } @media () { .other {} } @supports () { .other {} } @document () { .other {} } @page () { .other {} } @keyframes () { .other {} } @viewport () { .other {} } @counter-style () { .other {} } @font-feature-values () { .other {} } `; testCollect(html, css); }); describe('works with CSS combinators', () => { const css = dedent` .linaria + span {} .linaria ~ div {} .linaria > a {} .linaria b {} .other + span {} .other ~ div {} .other > a {} .other b {} `; testCollect(html, css); }); describe('works with pseudo-class and pseudo-elements', () => { const css = dedent` .linaria:active {} .linaria::before {} .other:active {} .other::before {} `; testCollect(html, css); }); describe('works with global css', () => { const css = dedent` body { font-size: 13.37px; } html { -webkit-font-smoothing: antialiased; } h1 { font-weight: bold; } .linaria:active {} .linaria::before {} .other:active {} .other::before {} `; const { critical, other } = collect(html, css); test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot()); test('other', () => expect(prettyPrint(other)).toMatchSnapshot()); }); describe('handles top-level @font-face', () => { const css = dedent` @font-face { font-family: MyFont; font-weight: normal; font-style: normal; src: url(MyFont.woff); } `; const { critical, other } = collect(html, css); test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot()); test('other', () => expect(prettyPrint(other)).toMatchSnapshot()); }); // there was a bug when the whole atrule was included for each child rule describe('include atrule once', () => { const css = dedent` @media screen { body { font-size: 10px; } h1 { font-size: 20px; } .class { font-size: 15px; } } `; const { critical, other } = collect(html, css); test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot()); test('other', () => expect(prettyPrint(other)).toMatchSnapshot()); }); describe('ignore empty class attribute', () => { const code = dedent`
`; const css = dedent` .not-exist {} `; const { critical } = collect(code, css); test('critical should be empty', () => expect(critical).toEqual('')); }); test('does not match selectors in ignoredClasses list', () => { const code = dedent`
`; const css = dedent` .linaria.dir {} .linaria.ltr {} .lily {} `; const { critical, other } = collect(code, css, { ignoredClasses: ['ltr', 'dir'], }); expect(critical).toMatchInlineSnapshot(`".lily {}"`); expect(other).toMatchInlineSnapshot(`".linaria.dir {}.linaria.ltr {}"`); }); test('does not match selectors in blockedClasses list', () => { const code = dedent`
`; const css = dedent` .linaria.ltr {} .linaria.rtl {} .lily {} `; const { critical, other } = collect(code, css, { blockedClasses: ['rtl'] }); expect(critical).toMatchInlineSnapshot(`".linaria.ltr {}.lily {}"`); expect(other).toMatchInlineSnapshot(`".linaria.rtl {}"`); }); test('does not match child selectors in blockedClasses list for media queries', () => { const code = dedent`
`; const css = dedent` @media only screen and (max-width:561.5px) { .dir-ltr.left_6_3_l9xil3s { padding-left: 24px !important; } .dir-rtl.left_6_3_l9xil3s { padding-right: 24px !important; } } `; const { critical, other } = collect(code, css, { blockedClasses: ['dir-rtl'], }); expect(critical).toMatchInlineSnapshot(` "@media only screen and (max-width:561.5px) { .dir-ltr.left_6_3_l9xil3s { padding-left: 24px !important; } }" `); expect(other).toMatchInlineSnapshot(` "@media only screen and (max-width:561.5px) { .dir-rtl.left_6_3_l9xil3s { padding-right: 24px !important; } }" `); }); ================================================ FILE: packages/server/babel.config.js ================================================ const config = require('../../babel.config'); module.exports = config; ================================================ FILE: packages/server/package.json ================================================ { "name": "@linaria/server", "version": "7.0.0", "description": "Blazing fast zero-runtime CSS in JS library", "keywords": [ "css", "css-in-js", "linaria", "react", "styled-components" ], "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "main": "lib/index.js", "module": "esm/index.js", "types": "types", "files": [ "types/", "lib/", "esm/" ], "scripts": { "build": "pnpm build:lib && pnpm build:esm && pnpm build:declarations", "build:declarations": "tsc --emitDeclarationOnly --outDir types", "build:esm": "babel src --out-dir esm --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "build:lib": "cross-env NODE_ENV=legacy babel src --out-dir lib --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "typecheck": "tsc --noEmit --composite false", "watch": "pnpm build:lib --watch & pnpm build:esm --watch & pnpm build:declarations --watch" }, "dependencies": { "postcss": "^8.4.31" }, "devDependencies": { "dedent": "^1.5.1", "prettier": "^3.0.3" }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" } } ================================================ FILE: packages/server/src/collect.ts ================================================ import type { AtRule, ChildNode } from 'postcss'; import postcss from 'postcss'; type CollectResult = { critical: string; other: string; }; interface ClassnameModifiers { blockedClasses?: string[]; ignoredClasses?: string[]; } /** * Used to escape `RegExp` * [syntax characters](https://262.ecma-international.org/7.0/#sec-regular-expressions-patterns). */ function escapeRegex(string: string) { return string.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&'); } const extractClassesFromHtml = ( html: string, ignoredClasses: string[] ): RegExp => { const htmlClasses: string[] = []; const regex = /\s+class="([^"]+)"/gm; let match = regex.exec(html); const ignoredClassesDeduped = new Set(ignoredClasses); while (match !== null) { match[1].split(' ').forEach((className) => { // eslint-disable-next-line no-param-reassign className = escapeRegex(className); if (className !== '' && !ignoredClassesDeduped.has(className)) { htmlClasses.push(className); } }); match = regex.exec(html); } return new RegExp(htmlClasses.join('|'), 'gm'); }; /** * This utility extracts critical CSS from given HTML and CSS file to be used in SSR environments * @param {string} html the HTML from which classes will be parsed * @param {string} css the CSS file from which selectors will be parsed and determined as critical or other * @param {string[]} ignoredClasses classes that, when present in the HTML, will not be included in the regular expression used to match selectors * @param {string[]} blockedClasses classes that, when contained in a selector, will cause the selector to be marked as not critical * @returns {CollectResult} object containing the critical and other CSS styles */ export default function collect( html: string, css: string, classnameModifiers?: ClassnameModifiers ): CollectResult { const animations = new Set(); const other = postcss.root(); const critical = postcss.root(); const stylesheet = postcss.parse(css); const ignoredClasses = classnameModifiers?.ignoredClasses ?? []; const blockedClasses = classnameModifiers?.blockedClasses ?? []; const htmlClassesRegExp = extractClassesFromHtml(html, ignoredClasses); const blockedClassesSanitized = blockedClasses.map(escapeRegex); const blockedClassesRegExp = new RegExp( blockedClassesSanitized.join('|'), 'gm' ); const isCritical = (rule: ChildNode) => { // Only check class names selectors if ('selector' in rule && rule.selector.startsWith('.')) { const isExcluded = blockedClasses.length > 0 && blockedClassesRegExp.test(rule.selector); if (isExcluded) return false; return Boolean(rule.selector.match(htmlClassesRegExp)); } return true; }; const handleAtRule = (rule: AtRule) => { if (rule.name === 'keyframes') { return; } const criticalRule = rule.clone(); const otherRule = rule.clone(); let removedNodesFromOther = 0; criticalRule.each((childRule: ChildNode, index: number) => { if (isCritical(childRule)) { otherRule.nodes[index - removedNodesFromOther]?.remove(); removedNodesFromOther += 1; } else { childRule.remove(); } }); rule.remove(); if (criticalRule.nodes.length > 0) { critical.append(criticalRule); } if (otherRule.nodes.length > 0) { other.append(otherRule); } }; stylesheet.walkAtRules('font-face', (rule) => { /** * @font-face rules may be defined also in CSS conditional groups (eg. @media) * we want only handle those from top-level, rest will be handled in stylesheet.walkRules */ if (rule.parent?.type === 'root') { critical.append(rule); } }); const walkedAtRules = new Set(); stylesheet.walkRules((rule) => { if ( rule.parent && 'name' in rule.parent && (rule.parent as { name: string }).name === 'keyframes' ) { return; } if (rule.parent?.type === 'atrule') { if (!walkedAtRules.has(rule.parent)) { handleAtRule(rule.parent as AtRule); walkedAtRules.add(rule.parent); } return; } if (isCritical(rule)) { critical.append(rule); } else { other.append(rule); } }); critical.walkDecls(/animation/, (decl) => { animations.add(decl.value.split(' ')[0]); }); stylesheet.walkAtRules('keyframes', (rule) => { if (animations.has(rule.params)) { critical.append(rule); } }); return { critical: critical.toString(), other: other.toString(), }; } ================================================ FILE: packages/server/src/index.ts ================================================ export { default as collect } from './collect'; ================================================ FILE: packages/server/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "paths": {}, "rootDir": "src/" } } ================================================ FILE: packages/stylelint/CHANGELOG.md ================================================ # Change Log ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ### Patch Changes - 8d4ebd33: chore: bump @wyw-in-js/\* packages ## 6.0.0 ### Major Changes - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ## 5.0.4 ### Patch Changes - Updated dependencies [e25e91ff] - @linaria/babel-preset@5.0.4 ## 5.0.3 ### Patch Changes - Updated dependencies [5f216d3b] - Updated dependencies [4992c14d] - Updated dependencies [70000ec8] - Updated dependencies [15fa87a5] - Updated dependencies [5a32f4fd] - Updated dependencies [727dc2bd] - Updated dependencies [25ba1344] - Updated dependencies [5a32f4fd] - Updated dependencies [5f216d3b] - @linaria/babel-preset@5.0.3 - @linaria/utils@5.0.2 ## 5.0.2 ### Patch Changes - Updated dependencies [38796a57] - @linaria/babel-preset@5.0.2 ## 5.0.1 ### Patch Changes - Updated dependencies [6fb6eb69] - Updated dependencies [6fb6eb69] - @linaria/babel-preset@5.0.1 - @linaria/utils@5.0.1 ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 - Updated dependencies [9cb4143d] - Updated dependencies [ae162f46] - Updated dependencies [88e07613] - Updated dependencies [715dc93c] - Updated dependencies [b3ef8c1f] - Updated dependencies [144995f0] - Updated dependencies [f8b9bff5] - Updated dependencies [63902332] - Updated dependencies [8a5d734b] - Updated dependencies [aa100453] - Updated dependencies [ea1444f6] - Updated dependencies [9bb782d0] - Updated dependencies [2a1e24a0] - Updated dependencies [16320d71] - Updated dependencies [cb853e14] - Updated dependencies [e042f96d] - @linaria/babel-preset@5.0.0 - @linaria/utils@5.0.0 ## 4.5.4 ### Patch Changes - Updated dependencies [10bcd241] - @linaria/babel-preset@4.5.4 - @linaria/utils@4.5.3 ## 4.5.3 ### Patch Changes - 79557248: Nothing has changed. Just moved some utils and types from babel to utils package. - Updated dependencies [79557248] - Updated dependencies [b191f543] - Updated dependencies [e59bf809] - Updated dependencies [520ba8da] - Updated dependencies [ae3727f9] - Updated dependencies [dca076ef] - @linaria/babel-preset@4.5.3 - @linaria/utils@4.5.2 ## 4.5.2 ### Patch Changes - Updated dependencies [85e74df6] - Updated dependencies [1bf5c5b8] - @linaria/utils@4.5.1 - @linaria/babel-preset@4.5.2 ## 4.5.1 ### Patch Changes - Updated dependencies [ceca1611] - Updated dependencies [13258306] - @linaria/babel-preset@4.5.1 ## 4.5.0 ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. - Updated dependencies [890b4aca] - Updated dependencies [418e40af] - Updated dependencies [05ad266c] - Updated dependencies [16c057df] - Updated dependencies [af5bb92d] - @linaria/utils@4.5.0 - @linaria/babel-preset@4.5.0 ## 4.1.17 ### Patch Changes - Updated dependencies [821a6819] - Updated dependencies [54ab61b2] - @linaria/babel-preset@4.4.5 - @linaria/utils@4.3.4 ## 4.1.16 ### Patch Changes - Updated dependencies [1c3f309d] - Updated dependencies [dbe250b5] - Updated dependencies [a62e7ba6] - @linaria/babel-preset@4.4.4 - @linaria/utils@4.3.3 ## 4.1.15 ### Patch Changes - @linaria/babel-preset@4.4.3 ## 4.1.14 ### Patch Changes - Updated dependencies [f9df4ed8] - @linaria/babel-preset@4.4.2 - @linaria/utils@4.3.2 ## 4.1.13 ### Patch Changes - Updated dependencies [917db446] - Updated dependencies [57c0dc4f] - @linaria/babel-preset@4.4.1 ## 4.1.12 ### Patch Changes - Updated dependencies [9cf41fae] - Updated dependencies [860b8d21] - Updated dependencies [af783273] - Updated dependencies [28f3f93d] - Updated dependencies [1d4d6833] - Updated dependencies [71a5b351] - Updated dependencies [2d3a741f] - Updated dependencies [61d49a39] - @linaria/babel-preset@4.4.0 - @linaria/utils@4.3.1 ## 4.1.11 ### Patch Changes - Updated dependencies [3ce985e0] - Updated dependencies [d11174d0] - @linaria/babel-preset@4.3.3 - @linaria/utils@4.3.0 ## 4.1.10 ### Patch Changes - Updated dependencies [315f0366] - @linaria/utils@4.2.6 - @linaria/babel-preset@4.3.2 ## 4.1.9 ### Patch Changes - e6420897: Update patch version so npm will pick up readme change - Updated dependencies [5edde648] - Updated dependencies [b9e49b74] - @linaria/babel-preset@4.3.1 - @linaria/utils@4.2.5 ## 4.1.8 ### Patch Changes - Updated dependencies [63f56d47] - Updated dependencies [963508a2] - @linaria/babel-preset@4.3.0 - @linaria/utils@4.2.4 ## 4.1.7 ### Patch Changes - Updated dependencies [cc2f87a8] - @linaria/babel-preset@4.2.4 - @linaria/utils@4.2.3 ## 4.1.6 ### Patch Changes - Updated dependencies [9111b4ea] - @linaria/babel-preset@4.2.3 ## 4.1.5 ### Patch Changes - Updated dependencies [8a8be242] - Updated dependencies [8a8be242] - Updated dependencies [c2092f61] - Updated dependencies [08304e09] - Updated dependencies [87ffe61c] - @linaria/utils@4.2.2 - @linaria/babel-preset@4.2.2 ## 4.1.4 ### Patch Changes - Updated dependencies [24b4a4bd] - @linaria/babel-preset@4.2.1 - @linaria/utils@4.2.1 ## 4.1.3 ### Patch Changes - Updated dependencies [8590e134] - Updated dependencies [f7351b09] - Updated dependencies [c0bd271a] - Updated dependencies [8f90fa75] - Updated dependencies [a5169f16] - Updated dependencies [ac0991a6] - @linaria/babel-preset@4.2.0 - @linaria/utils@4.2.0 ## 4.1.2 ### Patch Changes - Updated dependencies [3c593aa8] - Updated dependencies [50bc0c79] - @linaria/babel-preset@4.1.2 - @linaria/utils@4.1.1 ## 4.1.1 ### Patch Changes - Updated dependencies [21ba7a44] - Updated dependencies [21ba7a44] - Updated dependencies [21ba7a44] - Updated dependencies [2abc55b3] - Updated dependencies [21ba7a44] - @linaria/babel-preset@4.1.1 ## 4.1.0 ### Patch Changes - Updated dependencies [92f6d871] - @linaria/babel-preset@4.1.0 - @linaria/utils@4.1.0 ## 4.0.0 ### Major Changes - bc0cbeea: A completely new async mode with native support for Vite, Rollup, esbuild and Webpack resolvers. BREAKING CHANGES: Despite the fact, that it should be fully compatible with 3.0 and 2.0 branches, the new version of styles evaluator can have some serious bugs which can make your project unbuildable (however, since there is no runtime, if the build is finished successfully, everything will continue work as it was on 2.0 and 3.0). If you face some problems please let us know and we will fix it as soon as possible. ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - ea41d440: New package @linaria/tags that contains all abstract logic for tags processors. - Updated dependencies [f0cddda4] - @linaria/babel-preset@4.0.0 - @linaria/utils@4.0.0 ## 3.0.0-beta.21 ### Patch Changes - Updated dependencies [17c83e34] - @linaria/babel-preset@3.0.0-beta.21 ## 3.0.0-beta.20 ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - Updated dependencies [8be5650d] - @linaria/babel-preset@3.0.0-beta.20 # [3.0.0-beta.19](https://github.com/callstack/linaria/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2022-06-03) ### Bug Fixes - **stylelint:** remove console.log from stylelint preprocessor ([#969](https://github.com/callstack/linaria/issues/969)) ([1ae913b](https://github.com/callstack/linaria/commit/1ae913b0e6091e95c8d9ee42d98bfbe78260d65d)) ### Features - **babel:** api for custom tags ([#976](https://github.com/callstack/linaria/issues/976)) ([3285ccc](https://github.com/callstack/linaria/commit/3285ccc1d00449b78b3fc74087528cd38cbdd116)) - **babel:** new way for detecting tag imports ([#974](https://github.com/callstack/linaria/issues/974)) ([3305cfb](https://github.com/callstack/linaria/commit/3305cfb0c0f65abdacceeb7e6bad118c59f7d551)) # [3.0.0-beta.18](https://github.com/callstack/linaria/compare/v3.0.0-beta.17...v3.0.0-beta.18) (2022-04-01) **Note:** Version bump only for package @linaria/stylelint # [3.0.0-beta.17](https://github.com/callstack/linaria/compare/v3.0.0-beta.16...v3.0.0-beta.17) (2021-12-27) ### Bug Fixes - **react:** refactored types for styled function (fixes [#872](https://github.com/callstack/linaria/issues/872)) ([#887](https://github.com/callstack/linaria/issues/887)) ([7b8b129](https://github.com/callstack/linaria/commit/7b8b12937f9a0d1730d908e7cebad1684ccb03c3)) # [3.0.0-beta.15](https://github.com/callstack/linaria/compare/v3.0.0-beta.14...v3.0.0-beta.15) (2021-11-29) ### Bug Fixes - **stylelint:** fix indentation errors (fixes [#693](https://github.com/callstack/linaria/issues/693)) ([#876](https://github.com/callstack/linaria/issues/876)) ([7f9f24f](https://github.com/callstack/linaria/commit/7f9f24f25018e45081efd2da98e70ebed0564da6)) # [3.0.0-beta.14](https://github.com/callstack/linaria/compare/v3.0.0-beta.13...v3.0.0-beta.14) (2021-11-05) **Note:** Version bump only for package @linaria/stylelint # [3.0.0-beta.13](https://github.com/callstack/linaria/compare/v3.0.0-beta.12...v3.0.0-beta.13) (2021-09-13) **Note:** Version bump only for package @linaria/stylelint # [3.0.0-beta.12](https://github.com/callstack/linaria/compare/v3.0.0-beta.11...v3.0.0-beta.12) (2021-08-31) **Note:** Version bump only for package @linaria/stylelint # [3.0.0-beta.7](https://github.com/callstack/linaria/compare/v3.0.0-beta.6...v3.0.0-beta.7) (2021-06-24) **Note:** Version bump only for package @linaria/stylelint # [3.0.0-beta.5](https://github.com/callstack/linaria/compare/v3.0.0-beta.4...v3.0.0-beta.5) (2021-05-31) **Note:** Version bump only for package @linaria/stylelint # [3.0.0-beta.4](https://github.com/callstack/linaria/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2021-05-07) **Note:** Version bump only for package @linaria/stylelint # [3.0.0-beta.3](https://github.com/callstack/linaria/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2021-04-20) **Note:** Version bump only for package @linaria/stylelint # [3.0.0-beta.2](https://github.com/callstack/linaria/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2021-04-11) **Note:** Version bump only for package @linaria/stylelint ================================================ FILE: packages/stylelint/README.md ================================================

Linaria

Zero-runtime CSS in JS library.

--- ## Setup Please check the Linaria [linting documentation](https://github.com/callstack/linaria/blob/master/docs/LINTING.md) for setup instructions. ### 📖 Please refer to the [GitHub](https://github.com/callstack/linaria#readme) for full documentation. ================================================ FILE: packages/stylelint/babel.config.js ================================================ const config = require('../../babel.config'); module.exports = config; ================================================ FILE: packages/stylelint/package.json ================================================ { "name": "@linaria/stylelint", "version": "7.0.0", "description": "Blazing fast zero-runtime CSS in JS library", "keywords": [ "css", "css-in-js", "linaria", "react", "styled-components" ], "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "main": "lib/index.js", "module": "esm/index.js", "types": "types", "files": [ "types/", "lib/", "esm/" ], "scripts": { "build": "pnpm build:lib && pnpm build:esm && pnpm build:declarations", "build:declarations": "tsc --emitDeclarationOnly --outDir types", "build:esm": "babel src --out-dir esm --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "build:lib": "cross-env NODE_ENV=legacy babel src --out-dir lib --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "typecheck": "tsc --noEmit --composite false", "watch": "pnpm build:lib --watch & pnpm build:esm --watch & pnpm build:declarations --watch" }, "dependencies": { "@wyw-in-js/shared": "^1.0.4", "@wyw-in-js/transform": "^1.0.6" }, "devDependencies": { "@types/node": "^17.0.39" }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" } } ================================================ FILE: packages/stylelint/src/index.ts ================================================ export default { processors: [require.resolve('./preprocessor')], syntax: 'scss', rules: { 'property-no-vendor-prefix': true, 'string-no-newline': true, 'value-no-vendor-prefix': true, 'no-empty-source': null, 'no-extra-semicolons': null, }, }; ================================================ FILE: packages/stylelint/src/preprocessor.ts ================================================ import { stripVTControlCharacters as stripAnsi } from 'node:util'; import type { Replacements } from '@wyw-in-js/shared'; import { asyncResolveFallback } from '@wyw-in-js/shared'; import { transform } from '@wyw-in-js/transform'; type Errors = { [key: string]: | { code?: string; loc?: { column: number; line: number; }; message: string; name?: string; pos?: number; } | null | undefined; }; type Cache = { [key: string]: Replacements | null | undefined; }; type Warning = { column: number; line: number; rule?: string; severity: 'error' | 'warning'; text: string; }; type LintResult = { errored: boolean; warnings: Warning[]; }; interface IPosition { column: number; line: number; } interface ISourceOffset { generated: IPosition; name: string; original: IPosition; } function preprocessor() { const errors: Errors = {}; const cache: Cache = {}; const offsets: Record = {}; return { async code(input: string, filename: string) { let result; const transformServices = { options: { filename, }, }; try { result = await transform( transformServices, input, asyncResolveFallback ); cache[filename] = undefined; errors[filename] = undefined; offsets[filename] = []; } catch (e: unknown) { cache[filename] = undefined; offsets[filename] = undefined; errors[filename] = e as Error; // Ignore parse errors here // We handle it separately return ''; } const { rules, replacements } = result; if (!rules) { return ''; } // Construct a CSS-ish file from the unprocessed style rules let generatedLineNumber = 1; const cssText = Object.values(rules) .map((rule) => { const ruleText = `.${rule.className} {${rule.cssText}}`; if (rule.start && 'line' in rule.start) { offsets[filename]?.push({ generated: { line: generatedLineNumber, column: 1, }, original: { ...rule.start, }, name: rule.displayName, }); generatedLineNumber += 1; } generatedLineNumber += ruleText.split('\n').length + 2; return ruleText; }) .join('\n\n'); cache[filename] = replacements; offsets[filename] = offsets[filename]?.reverse(); return `${cssText}\n`; }, result(result: LintResult, filename: string) { const error = errors[filename]; const replacements = cache[filename]; const sourceMap = offsets[filename]; if (sourceMap) { // eslint-disable-next-line no-param-reassign result.warnings = result.warnings.map((warning) => { const offset = sourceMap.find( (o) => o.generated.line <= warning.line ); if (offset) { // eslint-disable-next-line no-param-reassign warning.line += offset.original.line - offset.generated.line; } return warning; }); } if (error) { // Babel adds this to the error message const prefix = `${filename}: `; let message = stripAnsi( error.message.startsWith(prefix) ? error.message.replace(prefix, '') : error.message ); let { loc } = error; if (!loc) { // If the error doesn't have location info, try to find it from the code frame const line = message.split('\n').find((l) => l.startsWith('>')); const column = message.split('\n').find((l) => l.includes('^')); if (line && column) { loc = { line: Number(line.replace(/^> /, '').split('|')[0].trim()), column: column.replace(/[^|]+\|\s/, '').length, }; } } if (loc) { // Strip the codeframe text if we have location of the error // It's formatted badly by stylelint, so not very helpful message = message.replace(/^>?\s+\d?\s\|.*$/gm, '').trim(); } // eslint-disable-next-line no-param-reassign result.errored = true; result.warnings.push({ rule: error.code || error.name, text: message, line: loc ? loc.line : 0, column: loc ? loc.column : 0, severity: 'error', }); } if (replacements) { replacements.forEach(({ original, length }) => { // If the warnings contain stuff that's been replaced, // Correct the line and column numbers to what's replaced result.warnings.forEach((w) => { /* eslint-disable no-param-reassign */ if (w.line === original.start.line) { // If the error is on the same line where an interpolation started, we need to adjust the line and column numbers // Because a replacement would have increased or decreased the column numbers // If it's in the same line where interpolation ended, it would have been adjusted during replacement if (w.column > original.start.column + length) { // The error is from an item after the replacements // So we need to adjust the column w.column += original.end.column - original.start.column + 1 - length; } else if ( w.column >= original.start.column && w.column < original.start.column + length ) { // The linter will underline the whole word in the editor if column is in inside a word // Set the column to the end, so it will underline the word inside the interpolation // e.g. in `${colors.primary}`, `primary` will be underlined w.column = original.start.line === original.end.line ? original.end.column - 1 : original.start.column; } } }); }); } return result; }, }; } export default preprocessor; ================================================ FILE: packages/stylelint/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "paths": {}, "rootDir": "src/", "types": ["node"] }, "references": [] } ================================================ FILE: packages/stylelint-config-standard-linaria/CHANGELOG.md ================================================ # Change Log ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ### Patch Changes - Updated dependencies [ab11ebb7] - Updated dependencies [b04f025e] - @linaria/postcss-linaria@7.0.0 ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ### Patch Changes - Updated dependencies [281ca4f5] - @linaria/postcss-linaria@6.3.0 ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ### Patch Changes - Updated dependencies [a3dcee2e] - @linaria/postcss-linaria@6.2.0 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ### Patch Changes - Updated dependencies [8ba655d3] - @linaria/postcss-linaria@6.1.0 ## 6.0.0 ### Major Changes - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ### Patch Changes - Updated dependencies [63392f9a] - Updated dependencies [2ac94b99] - @linaria/postcss-linaria@6.0.0 ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 - Updated dependencies [9cb4143d] - Updated dependencies [88e07613] - Updated dependencies [2a1e24a0] - Updated dependencies [cb853e14] - @linaria/postcss-linaria@5.0.0 ## 4.5.1 ### Patch Changes - Updated dependencies [e59bf809] - @linaria/postcss-linaria@4.5.1 ## 4.5.0 ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. - Updated dependencies [16c057df] - Updated dependencies [af5bb92d] - @linaria/postcss-linaria@4.5.0 ## 4.1.5 ### Patch Changes - e6420897: Update patch version so npm will pick up readme change - Updated dependencies [5edde648] - Updated dependencies [e6420897] - @linaria/postcss-linaria@4.1.5 ## 4.1.4 ### Patch Changes - Updated dependencies [4c2efaa9] - @linaria/postcss-linaria@4.1.4 ## 4.1.3 ### Patch Changes - ce36da42: Add stylelint v14 custom syntax support - Updated dependencies [ce36da42] - @linaria/postcss-linaria@4.1.3 ================================================ FILE: packages/stylelint-config-standard-linaria/README.md ================================================

Linaria

Zero-runtime CSS in JS library.

--- ## Setup Please check the Linaria [linting documentation](https://github.com/callstack/linaria/blob/master/docs/LINTING.md) for setup instructions. ## Acknowledgements This project wouldn't have been possible without the following libraries or the people behind them. - [postcss-lit](https://github.com/43081j/postcss-lit) (One of the first CSS-in-JS custom syntaxes) - [stylelint](https://stylelint.io/) - [postcss](https://postcss.org/) ### 📖 Please refer to [GitHub](https://github.com/callstack/linaria#readme) for full documentation. ================================================ FILE: packages/stylelint-config-standard-linaria/babel.config.js ================================================ const config = require('../../babel.config'); module.exports = config; ================================================ FILE: packages/stylelint-config-standard-linaria/package.json ================================================ { "name": "@linaria/stylelint-config-standard-linaria", "version": "7.0.0", "description": "Blazing fast zero-runtime CSS in JS library", "keywords": [ "css", "css-in-js", "linaria", "react", "styled-components" ], "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "sideEffects": false, "main": "lib/index.js", "module": "esm/index.js", "types": "types/index.d.ts", "files": [ "esm/", "lib/", "processors/", "types/" ], "scripts": { "build": "pnpm build:lib && pnpm build:esm && pnpm build:declarations", "build:declarations": "tsc --emitDeclarationOnly --outDir types", "build:esm": "babel src --out-dir esm --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "build:lib": "cross-env NODE_ENV=legacy babel src --out-dir lib --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start", "typecheck": "tsc --noEmit --composite false", "watch": "pnpm build:lib --watch & pnpm build:esm --watch & pnpm build:declarations --watch" }, "dependencies": { "@linaria/postcss-linaria": "workspace:^", "stylelint": "^14.11.0", "stylelint-config-standard": "^28.0.0" }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" } } ================================================ FILE: packages/stylelint-config-standard-linaria/src/index.js ================================================ module.exports = { extends: ['stylelint-config-standard'], // eslint-disable-next-line global-require customSyntax: require('@linaria/postcss-linaria'), rules: { 'property-no-vendor-prefix': true, 'string-no-newline': true, 'value-no-vendor-prefix': true, 'no-empty-source': null, 'no-extra-semicolons': null, // /* pcss-lin */ placeholder comments are added during parsing 'comment-empty-line-before': [ 'always', { except: ['first-nested'], ignore: ['stylelint-commands'], ignoreComments: [/pcss-lin/], }, ], // '//' comments create unknown word issues while linting. Force using /* */ 'no-invalid-double-slash-comments': true, }, }; ================================================ FILE: packages/stylelint-config-standard-linaria/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "compilerOptions": { "paths": {}, "rootDir": "src/" }, "references": [] } ================================================ FILE: packages/testkit/CHANGELOG.md ================================================ # Change Log ## 7.0.1 ### Patch Changes - Updated dependencies [b3331e45] - @linaria/react@7.0.1 ## 7.0.0 ### Major Changes - ab11ebb7: BREAKING: bump `@wyw-in-js/*` dependencies to `^1.0.0` (stable). This release updates Linaria's build-time evaluation engine (WyW). See https://wyw-in-js.dev/stability for practical guidance and common pitfalls. Notes: - Linaria 7 requires Node.js 20+ (aligned with WyW 1.x). - If you import JSON from code that is evaluated by WyW, add `.json` to `extensions` and ensure `.json` is ignored by evaluation rules (so it's parsed as JSON, not by Babel). - Rollup users: WyW 1.x serializes `transform()` by default (`serializeTransform: true`). If you hit Rollup "Unexpected early exit" (unresolved plugin promises / deadlock during resolve), set `serializeTransform: false` (see `examples/rollup/rollup.config.mjs`). - WyW 1.x promotes fully-statically-evaluatable modules to `only: ['*']` and can re-evaluate modules when cached exports are incomplete (cached export values might not be reused). ### Patch Changes - Updated dependencies [ab11ebb7] - Updated dependencies [654d8590] - @linaria/react@7.0.0 ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ### Patch Changes - Updated dependencies [bd8d45fd] - Updated dependencies [281ca4f5] - @linaria/react@6.3.0 ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ### Patch Changes - @linaria/react@6.2.1 ## 6.1.1 ### Patch Changes - Updated dependencies [fd60b5de] - @linaria/react@6.2.0 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ### Patch Changes - 8d4ebd33: chore: bump @wyw-in-js/\* packages - Updated dependencies [8d4ebd33] - Updated dependencies [8ba655d3] - @linaria/react@6.1.0 ## 6.0.0 ### Major Changes - 60e6b7e2: Stylis has been upgraded from v3 to v4. - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ### Patch Changes - faf65795: Fix for space inserted after function interpolation. Fixes #1141 and #1368. - Updated dependencies [2ac94b99] - @linaria/react@6.0.0 ## 5.0.5 ### Patch Changes - Updated dependencies [e25e91ff] - @linaria/babel-preset@5.0.4 - @linaria/shaker@5.0.3 ## 5.0.4 ### Patch Changes - Updated dependencies [4b083b7c] - @linaria/react@5.0.3 ## 5.0.3 ### Patch Changes - 5f216d3b: Fix for lost `pluginOptions` in some entrypoints. - 727dc2bd: fix: add caller settings to loadBabelOptions() - 25ba1344: `useBabelConfigs` feature flag. - 5f216d3b: `pluginOptions` could be lost during processing. - Updated dependencies [5f216d3b] - Updated dependencies [1e889937] - Updated dependencies [4992c14d] - Updated dependencies [15fa87a5] - Updated dependencies [1e889937] - Updated dependencies [25ba1344] - Updated dependencies [5f216d3b] - @linaria/babel-preset@5.0.3 - @linaria/react@5.0.2 - @linaria/shaker@5.0.2 - @linaria/tags@5.0.2 ## 5.0.2 ### Patch Changes - Updated dependencies [38796a57] - @linaria/babel-preset@5.0.2 ## 5.0.1 ### Patch Changes - Updated dependencies [6fb6eb69] - Updated dependencies [6fb6eb69] - @linaria/babel-preset@5.0.1 - @linaria/shaker@5.0.1 - @linaria/react@5.0.1 - @linaria/tags@5.0.1 ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Minor Changes - 9cb4143d: Refactoring of the 1st stage of transformation. It opens the road to processing wildcard reexports. - ae162f46: babelrc should not be used for preeval transformations (fixes #1308) ### Patch Changes - 715dc93c: feat: support dynamic imports for evaluation - b3ef8c1f: fix: add support for params in dynamic imports - f8b9bff5: Improved exports finder so it works with pure TS files and better detects transpiled reexports. - 63902332: The exports finder didn't support enums that were transpiled to esm by tsc. Fixed. - 8a5d734b: Add support for `import` and `require` calls with dynamic arguments. - aa100453: In some cases, an asynchronous resolver could cause race conditions. Fixed. - ea1444f6: feat: use happy-dom in module - 9bb782d0: The improved cache that fixes race conditions which lead to "The expression evaluated to 'undefined'" (fixes #1304 and #1287) - 2a1e24a0: Upgrade TypeScript to 5.2 - Updated dependencies [9cb4143d] - Updated dependencies [ae162f46] - Updated dependencies [88e07613] - Updated dependencies [715dc93c] - Updated dependencies [b3ef8c1f] - Updated dependencies [144995f0] - Updated dependencies [f8b9bff5] - Updated dependencies [8a5d734b] - Updated dependencies [aa100453] - Updated dependencies [ea1444f6] - Updated dependencies [9bb782d0] - Updated dependencies [2a1e24a0] - Updated dependencies [cb853e14] - Updated dependencies [e042f96d] - @linaria/babel-preset@5.0.0 - @linaria/extractor@5.0.0 - @linaria/react@5.0.0 - @linaria/shaker@5.0.0 - @linaria/tags@5.0.0 ## 4.5.4 ### Patch Changes - Updated dependencies [10bcd241] - @linaria/babel-preset@4.5.4 - @linaria/react@4.5.4 - @linaria/shaker@4.5.3 - @linaria/tags@4.5.4 ## 4.5.3 ### Patch Changes - 79557248: Nothing has changed. Just moved some utils and types from babel to utils package. - b191f543: New option `features` for fine-tuning the build and evaluation process. - e59bf809: Shaker mistakenly counts references in types as valuable and keeps referenced variables alive. - 520ba8da: Debug mode for CLI, Webpack 5 and Vite. When enabled, prints brief perf report to console and information about processed dependency tree to the specified file. - ae3727f9: Fix the issues with processing files that are supposed to be parsed with their respective Babel config. - Updated dependencies [79557248] - Updated dependencies [b191f543] - Updated dependencies [e59bf809] - Updated dependencies [520ba8da] - Updated dependencies [ae3727f9] - @linaria/babel-preset@4.5.3 - @linaria/react@4.5.3 - @linaria/tags@4.5.3 - @linaria/shaker@4.5.2 ## 4.5.2 ### Patch Changes - 85e74df6: Fix: type imports without `type` annotation may lead to an unexpected increase in the evaluated codebase. - 1bf5c5b8: The cache has been improved, which should address the build time issues for Webpack 4/5 and resolve HMR-related problems for Vite. Fixes #1199, #1265 and maybe some more. - Updated dependencies [85e74df6] - Updated dependencies [1bf5c5b8] - @linaria/shaker@4.5.1 - @linaria/babel-preset@4.5.2 - @linaria/react@4.5.2 - @linaria/tags@4.5.2 ## 4.5.1 ### Patch Changes - ceca1611: Enable optimisation from #1276 for complex expressions such as `styled(Component as unknow)` or `styled(connect(Component))`. - 13258306: Variables in props-based interpolation functions are no longer required for the evaluation stage. Here's an example: ``` import { getColor } from "very-big-library"; export const Box = styled.div\` color: ${props => getColor(props.kind)}; \`; ``` In versions prior to and including 4.5.0, the evaluator would attempt to import `getColor` from `very-big-library`, despite it having no relevance to style generation. However, in versions greater than 4.5.0, `very-big-library` will be ignored. - Updated dependencies [ceca1611] - Updated dependencies [13258306] - @linaria/babel-preset@4.5.1 - @linaria/react@4.5.1 - @linaria/tags@4.5.1 ## 4.5.0 ### Minor Changes - 16c057df: Breaking Change: Performance Optimization for `styled` When a component is wrapped in `styled`, Linaria needs to determine if that component is already a styled component. To accomplish this, the wrapped component is included in the list of variables for evaluation, along with the interpolated values used in styles. The issue arises when a wrapped component, even if it is not styled, brings along a substantial dependency tree. This situation is particularly evident when using `styled` to style components from third-party UI libraries. To address this problem, Linaria will now examine the import location of the component and check if there is an annotation in the `package.json` file of the package containing the components. This annotation indicates whether the package includes other Linaria components. If there is no such annotation, Linaria will refrain from evaluating the component. Please note that this Breaking Change solely affects developers of component libraries. In order for users to style components from your library, you must include the `linaria.components` property in the library's `package.json` file. This property should have a mask that covers all imported files with components. Here's an example of how to specify it: ```json "linaria": { "components": "**/*" } ``` ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. - Updated dependencies [418e40af] - Updated dependencies [05ad266c] - Updated dependencies [16c057df] - Updated dependencies [af5bb92d] - Updated dependencies [10859924] - @linaria/babel-preset@4.5.0 - @linaria/shaker@4.5.0 - @linaria/react@4.5.0 - @linaria/tags@4.5.0 - @linaria/extractor@4.5.0 ## 4.3.6 ### Patch Changes - Updated dependencies [821a6819] - Updated dependencies [54ab61b2] - @linaria/babel-preset@4.4.5 - @linaria/react@4.3.8 - @linaria/shaker@4.2.11 - @linaria/tags@4.3.5 ## 4.3.5 ### Patch Changes - 1c3f309d: Fix tags usage validation (fixes #1224) - dbe250b5: Fix module function deletion when containing restricted code (fixes #1226) - Updated dependencies [2e966f23] - Updated dependencies [1c3f309d] - Updated dependencies [dbe250b5] - Updated dependencies [34029088] - Updated dependencies [a62e7ba6] - @linaria/tags@4.3.4 - @linaria/babel-preset@4.4.4 - @linaria/react@4.3.7 - @linaria/shaker@4.2.10 ## 4.3.4 ### Patch Changes - a3ad617f: Fix "Invalid usage of `styled` tag" when it's not really invalid. Fixes #1214. - Updated dependencies [a3ad617f] - @linaria/react@4.3.6 - @linaria/tags@4.3.3 - @linaria/babel-preset@4.4.3 ## 4.3.3 ### Patch Changes - f9df4ed8: Address the problem in which a module may be erroneously evaluated as an empty object (fixes #1209) - Updated dependencies [f9df4ed8] - @linaria/babel-preset@4.4.2 - @linaria/react@4.3.5 - @linaria/shaker@4.2.9 - @linaria/tags@4.3.2 ## 4.3.2 ### Patch Changes - Updated dependencies [917db446] - Updated dependencies [57c0dc4f] - @linaria/babel-preset@4.4.1 ## 4.3.1 ### Patch Changes - 860b8d21: Ensure that the Proxy for this.#exports forwards unknown properties to the underlying Object instance. - 28f3f93d: Add the tagSource property for processors, indicating the package and name of the imported processor. - 71a5b351: Workaround for weirdly packaged cjs modules. - 2d3a741f: fix: handle .cjs & .mjs extensions - Updated dependencies [b27f328f] - Updated dependencies [9cf41fae] - Updated dependencies [860b8d21] - Updated dependencies [af783273] - Updated dependencies [28f3f93d] - Updated dependencies [1d4d6833] - Updated dependencies [71a5b351] - Updated dependencies [cf1d6611] - Updated dependencies [2d3a741f] - Updated dependencies [61d49a39] - @linaria/shaker@4.2.8 - @linaria/babel-preset@4.4.0 - @linaria/tags@4.3.1 - @linaria/react@4.3.4 ## 4.3.0 ### Minor Changes - d11174d0: Add option to remove var() wrapper around css variables ### Patch Changes - Updated dependencies [3ce985e0] - Updated dependencies [d11174d0] - @linaria/babel-preset@4.3.3 - @linaria/tags@4.3.0 - @linaria/react@4.3.3 - @linaria/shaker@4.2.7 ## 4.2.2 ### Patch Changes - 315f0366: Support for code transpiled with esbuild. - Updated dependencies [315f0366] - @linaria/babel-preset@4.3.2 - @linaria/react@4.3.2 - @linaria/shaker@4.2.6 - @linaria/tags@4.2.2 ## 4.2.1 ### Patch Changes - e2224348: Fix @linaria/shaker from removing exported renamed imports. Fixes #1114. - 5edde648: Upgrade Babel to support TypeScript 4.9. Fixes #1133. - b9e49b74: Support for code transpiled with SWC. - Updated dependencies [e2224348] - Updated dependencies [922f20d6] - Updated dependencies [5edde648] - Updated dependencies [b9e49b74] - @linaria/shaker@4.2.5 - @linaria/react@4.3.1 - @linaria/babel-preset@4.3.1 - @linaria/tags@4.2.1 ## 4.2.0 ### Minor Changes - 63f56d47: Do not filter properties if an unknown component is passed to `styled`. Fixes support of custom elements #968 ### Patch Changes - 963508a2: Shaker shouldn't remove parameters of functions if they aren't used. - Updated dependencies [63f56d47] - Updated dependencies [963508a2] - Updated dependencies [c26d4667] - @linaria/babel-preset@4.3.0 - @linaria/react@4.3.0 - @linaria/tags@4.2.0 - @linaria/shaker@4.2.4 ## 4.1.7 ### Patch Changes - cc2f87a8: Get rid of "expected node to be of a type" errors - Updated dependencies [cc2f87a8] - Updated dependencies [6de22792] - @linaria/babel-preset@4.2.4 - @linaria/shaker@4.2.3 - @linaria/react@4.2.1 - @linaria/tags@4.1.5 ## 4.1.6 ### Patch Changes - Updated dependencies [1e88e95d] - Updated dependencies [9111b4ea] - @linaria/react@4.2.0 - @linaria/babel-preset@4.2.3 ## 4.1.5 ### Patch Changes - c2092f61: Support for rollup@3 and vite@3 (fixes #1044, #1060) - 08304e09: Fix support of re-exports compiled by tsc - 87ffe61c: The new `variableNameSlug` option that allows to customize css variable names (closes #1053). - Updated dependencies [8a8be242] - Updated dependencies [8a8be242] - Updated dependencies [c2092f61] - Updated dependencies [08304e09] - Updated dependencies [87ffe61c] - @linaria/shaker@4.2.2 - @linaria/babel-preset@4.2.2 - @linaria/react@4.1.5 - @linaria/tags@4.1.4 ## 4.1.4 ### Patch Changes - Updated dependencies [24b4a4bd] - @linaria/babel-preset@4.2.1 - @linaria/shaker@4.2.1 - @linaria/tags@4.1.3 - @linaria/react@4.1.4 ## 4.1.3 ### Patch Changes - ac0991a6: Better detection for jsx-runtime. Reduces the amount of evaluated code and improves speed and stability. - Updated dependencies [8590e134] - Updated dependencies [f7351b09] - Updated dependencies [c0bd271a] - Updated dependencies [8f90fa75] - Updated dependencies [a5169f16] - Updated dependencies [ac0991a6] - @linaria/babel-preset@4.2.0 - @linaria/shaker@4.2.0 - @linaria/react@4.1.3 - @linaria/tags@4.1.2 ## 4.1.2 ### Patch Changes - Updated dependencies [3c593aa8] - @linaria/babel-preset@4.1.2 - @linaria/shaker@4.1.2 - @linaria/tags@4.1.1 - @linaria/react@4.1.2 ## 4.1.1 ### Patch Changes - 21ba7a44: The default config was changed to process ES modules inside node_modules. - 21ba7a44: The better detector of React components. - Updated dependencies [21ba7a44] - Updated dependencies [21ba7a44] - Updated dependencies [21ba7a44] - Updated dependencies [2abc55b3] - Updated dependencies [21ba7a44] - @linaria/babel-preset@4.1.1 - @linaria/react@4.1.1 - @linaria/shaker@4.1.1 ## 4.1.0 ### Minor Changes - 92f6d871: Instead of just replacing tags with their runtime versions, `transform` mistakenly applied all babel transformations. (fixes #1018) ### Patch Changes - Updated dependencies [92f6d871] - @linaria/babel-preset@4.1.0 - @linaria/shaker@4.1.0 - @linaria/tags@4.1.0 - @linaria/react@4.1.0 ## 4.0.0 ### Major Changes - bc0cbeea: A completely new async mode with native support for Vite, Rollup, esbuild and Webpack resolvers. BREAKING CHANGES: Despite the fact, that it should be fully compatible with 3.0 and 2.0 branches, the new version of styles evaluator can have some serious bugs which can make your project unbuildable (however, since there is no runtime, if the build is finished successfully, everything will continue work as it was on 2.0 and 3.0). If you face some problems please let us know and we will fix it as soon as possible. ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - 17c83e34: Fix for the case when `styled` wraps an imported component. - ea41d440: New package @linaria/tags that contains all abstract logic for tags processors. - 592b89b5: Fix for broken object interpolation (#995) - 9a50c1c1: Linaria now removes all unused css-related code from the runtime. - 4cdf0315: Tagged template-specific logic has been moved from `BaseProcessor` to `TaggedTemplateProcessor`. `BaseProcessor` now can be used to define any type of expressions for zero-runtime transformations, such as `makeStyles` from `@griffel/react`. - 17c83e34: Aliases for environments without the support of `exports` in package.json. - f0cddda4: Extends `BaseProcessor` to support tags other than tagged templates, such as `makeStyles` from `@griffel/react`. - Updated dependencies [f0cddda4] - @linaria/babel-preset@4.0.0 - @linaria/extractor@4.0.0 - @linaria/react@4.0.0 - @linaria/shaker@4.0.0 - @linaria/tags@4.0.0 ## 3.0.0-beta.21 ### Patch Changes - 17c83e34: Aliases for environments without the support of `exports` in package.json. - Updated dependencies [17c83e34] - @linaria/react@3.0.0-beta.21 - @linaria/babel-preset@3.0.0-beta.21 - @linaria/extractor@3.0.0-beta.21 - @linaria/preeval@3.0.0-beta.21 - @linaria/shaker@3.0.0-beta.21 ## 3.0.0-beta.20 ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - Updated dependencies - @linaria/babel-preset@3.0.0-beta.20 - @linaria/extractor@3.0.0-beta.20 - @linaria/preeval@3.0.0-beta.20 - @linaria/react@3.0.0-beta.20 - @linaria/shaker@3.0.0-beta.20 ================================================ FILE: packages/testkit/jest.config.js ================================================ /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ module.exports = { preset: 'ts-jest', testEnvironment: 'node', }; ================================================ FILE: packages/testkit/package.json ================================================ { "name": "@linaria/testkit", "version": "7.0.1", "private": true, "description": "Blazing fast zero-runtime CSS in JS library", "keywords": [ "babel", "babel-plugin", "css", "css-in-js", "linaria", "react", "styled-components" ], "homepage": "https://github.com/callstack/linaria#readme", "bugs": "https://github.com/callstack/linaria/issues", "repository": "git@github.com:callstack/linaria.git", "license": "MIT", "scripts": { "test": "jest --config ./jest.config.js --rootDir .", "typecheck": "tsc --noEmit --composite false" }, "dependencies": { "@babel/core": "^7.23.5", "@babel/generator": "^7.23.5", "@babel/traverse": "^7.23.5", "@linaria/react": "workspace:^", "@swc/core": "^1.3.20", "@wyw-in-js/processor-utils": "^1.0.4", "@wyw-in-js/shared": "^1.0.4", "@wyw-in-js/transform": "^1.0.6", "debug": "^4.3.4", "dedent": "^1.5.1", "esbuild": "^0.15.16", "typescript": "^5.2.2" }, "devDependencies": { "@babel/plugin-syntax-jsx": "^7.23.3", "@babel/plugin-syntax-typescript": "^7.23.3", "@babel/plugin-transform-modules-commonjs": "^7.23.3", "@babel/preset-typescript": "^7.23.3", "@babel/runtime": "^7.23.5", "@babel/types": "^7.23.5", "@linaria/atomic": "workspace:^", "@linaria/core": "workspace:^", "@types/babel__core": "^7.20.5", "@types/babel__generator": "^7.6.7", "@types/babel__traverse": "^7.20.4", "@types/debug": "^4.1.8", "@types/jest": "^28.1.0", "@types/node": "^17.0.39", "babel-plugin-istanbul": "^6.1.1", "babel-plugin-module-resolver": "^4.1.0", "jest": "^29.6.2", "linaria": "workspace:^", "ts-jest": "^29.1.1" }, "engines": { "node": ">=20.0.0" }, "publishConfig": { "access": "public" } } ================================================ FILE: packages/testkit/src/__fixtures__/assignToExport.js ================================================ var Padding = (exports.Padding = 4); ================================================ FILE: packages/testkit/src/__fixtures__/bar.js ================================================ export * from './re-exports/constants'; export const bar1 = 'bar1'; export const bar2 = 'bar2'; ================================================ FILE: packages/testkit/src/__fixtures__/circular-imports/bar.js ================================================ export const bar = 'bar'; ================================================ FILE: packages/testkit/src/__fixtures__/circular-imports/constants.js ================================================ import { bar } from './index'; export const foo = 'foo'; export const constBar = bar; ================================================ FILE: packages/testkit/src/__fixtures__/circular-imports/foo.js ================================================ import * as fooStyles from './constants'; export { fooStyles }; ================================================ FILE: packages/testkit/src/__fixtures__/circular-imports/index.js ================================================ export * from './bar'; export * from './foo'; ================================================ FILE: packages/testkit/src/__fixtures__/complex-component.js ================================================ // Dead code in this file should be ignored import deadDep from 'unknown-dependency'; import { styled } from '@linaria/react'; export const deadValue = deadDep(); const objects = { font: { fontSize: 12 }, box: { border: '1px solid red' } }; const foo = (k) => { const { [k]: obj } = objects; return obj; }; objects.font.fontWeight = 'bold'; export const whiteColor = '#fff'; export const Title = styled.h1` ${foo('font')} ${foo('box')} `; ================================================ FILE: packages/testkit/src/__fixtures__/components-library.js ================================================ import { styled } from '@linaria/react'; export const T1 = styled.h1` background: #111; `; export const T2 = styled.h2` background: #222; `; export const T3 = styled.h3` ${T2} { background: #333; } `; export default styled.p` background: #333; `; ================================================ FILE: packages/testkit/src/__fixtures__/computedKeys.js ================================================ const computedKeyName = 'red'; export const object = { [computedKeyName]: 'red', blue: 'blue', }; ================================================ FILE: packages/testkit/src/__fixtures__/enums.ts ================================================ export enum Colors { BLUE = '#27509A', } ================================================ FILE: packages/testkit/src/__fixtures__/escape-character.js ================================================ import { styled } from '@linaria/react'; const selectors = ['a', 'b']; export const Block = styled.div` ${selectors.map((c) => String.raw`${c} { content: "\u000A"; }`).join('\n')}; `; ================================================ FILE: packages/testkit/src/__fixtures__/foo-nonstatic.js ================================================ export const foo1 = String('foo1'); export const foo2 = String('foo2'); export const foo3 = () => 'foo3'; ================================================ FILE: packages/testkit/src/__fixtures__/foo.js ================================================ export const foo1 = 'foo1'; export const foo2 = 'foo2'; export const foo3 = () => 'foo3'; ================================================ FILE: packages/testkit/src/__fixtures__/linaria-ui-library/components/index.js ================================================ export const Title = () => 'Title'; ================================================ FILE: packages/testkit/src/__fixtures__/linaria-ui-library/hocs.js ================================================ export const connect = (i) => i; ================================================ FILE: packages/testkit/src/__fixtures__/linaria-ui-library/non-linaria-components.js ================================================ export const Title = () => 'Title'; throw new Error('This file should not be imported'); ================================================ FILE: packages/testkit/src/__fixtures__/linaria-ui-library/package.json ================================================ { "name": "linaria-ui-library", "version": "1.0.0", "dependencies": { }, "linaria": { "components": "components/**/*" } } ================================================ FILE: packages/testkit/src/__fixtures__/linaria-ui-library/types.ts ================================================ export type ComponentType = 'class' | 'function' | 'arrow'; export Unexpected token; ================================================ FILE: packages/testkit/src/__fixtures__/loop/a.js ================================================ const b = require('./b'); exports.A = 'A'; exports.smallB = b.B.toLowerCase(); ================================================ FILE: packages/testkit/src/__fixtures__/loop/ab.js ================================================ const a = require('./a'); exports.AB = a.A + a.smallB; ================================================ FILE: packages/testkit/src/__fixtures__/loop/b.js ================================================ const a = require('./a'); exports.B = 'B'; exports.smallA = a.A.toLowerCase(); ================================================ FILE: packages/testkit/src/__fixtures__/loop/ba.js ================================================ const b = require('./b'); exports.BA = b.B + b.smallA; ================================================ FILE: packages/testkit/src/__fixtures__/loop/index.js ================================================ const ab = require('./ab'); const ba = require('./ba'); exports.AB = ab.AB; exports.BA = ba.BA; ================================================ FILE: packages/testkit/src/__fixtures__/module-reexport.js ================================================ module.exports = require('./re-exports/constants'); ================================================ FILE: packages/testkit/src/__fixtures__/non-linaria-ui-library/index.js ================================================ export const Title = () => 'Title'; throw new Error('This file should not be imported'); ================================================ FILE: packages/testkit/src/__fixtures__/non-linaria-ui-library/package.json ================================================ { "name": "non-linaria-ui-library", "version": "1.0.0", "dependencies": { } } ================================================ FILE: packages/testkit/src/__fixtures__/objectExport.js ================================================ module.exports = { margin: 5, }; ================================================ FILE: packages/testkit/src/__fixtures__/re-exports/constants.js ================================================ export const foo = 'foo'; export const bar = 'bar'; ================================================ FILE: packages/testkit/src/__fixtures__/re-exports/empty.js ================================================ export {}; ================================================ FILE: packages/testkit/src/__fixtures__/re-exports/foo.js ================================================ import * as fooStyles from './constants'; export * from '../bar'; export { fooStyles }; ================================================ FILE: packages/testkit/src/__fixtures__/re-exports/index.js ================================================ export * from './empty'; export * from './foo'; ================================================ FILE: packages/testkit/src/__fixtures__/reexports.js ================================================ export * from './foo'; export * from './bar'; ================================================ FILE: packages/testkit/src/__fixtures__/runNearFramePaint.js ================================================ /** * The whole this file should be shaken out because it uses DOM API */ let isHidden = document.visibilityState !== 'visible'; document.addEventListener('visibilitychange', () => { isHidden = document.visibilityState !== 'visible'; }); export function runNearFramePaint(callback) { if (isHidden) { return; } else { callback(); } } ================================================ FILE: packages/testkit/src/__fixtures__/sample-data.json ================================================ { "name": "Luke Skywalker", "height": "172", "mass": "77", "hair_color": "blond", "skin_color": "fair", "eye_color": "blue", "birth_year": "19BBY", "gender": "male" } ================================================ FILE: packages/testkit/src/__fixtures__/sample-script.cjs ================================================ module.exports = 42; ================================================ FILE: packages/testkit/src/__fixtures__/sample-script.js ================================================ module.exports = 42; ================================================ FILE: packages/testkit/src/__fixtures__/sample-typescript.tsx ================================================ export default 27; ================================================ FILE: packages/testkit/src/__fixtures__/self-import.js ================================================ import { constant as importedConstant } from './self-import'; export const constant = 42; export const stringConstant = importedConstant.toString(16); ================================================ FILE: packages/testkit/src/__fixtures__/sequenceExport.js ================================================ let n = 0; export default ((n = 5), n); ================================================ FILE: packages/testkit/src/__fixtures__/slugify.js ================================================ /* eslint-disable no-plusplus, no-bitwise, default-case, no-param-reassign, prefer-destructuring */ /** * This file contains a utility to generate hashes to be used as generated class names */ /** * murmurhash2 via https://gist.github.com/raycmorgan/588423 */ function UInt32(str, pos) { return ( str.charCodeAt(pos++) + (str.charCodeAt(pos++) << 8) + (str.charCodeAt(pos++) << 16) + (str.charCodeAt(pos) << 24) ); } function UInt16(str, pos) { return str.charCodeAt(pos++) + (str.charCodeAt(pos++) << 8); } function Umul32(n, m) { n |= 0; m |= 0; const nlo = n & 0xffff; const nhi = n >>> 16; return (nlo * m + (((nhi * m) & 0xffff) << 16)) | 0; } function doHash(str, seed = 0) { const m = 0x5bd1e995; const r = 24; let h = seed ^ str.length; let length = str.length; let currentIndex = 0; while (length >= 4) { let k = UInt32(str, currentIndex); k = Umul32(k, m); k ^= k >>> r; k = Umul32(k, m); h = Umul32(h, m); h ^= k; currentIndex += 4; length -= 4; } switch (length) { case 3: h ^= UInt16(str, currentIndex); h ^= str.charCodeAt(currentIndex + 2) << 16; h = Umul32(h, m); break; case 2: h ^= UInt16(str, currentIndex); h = Umul32(h, m); break; case 1: h ^= str.charCodeAt(currentIndex); h = Umul32(h, m); break; } h ^= h >>> 13; h = Umul32(h, m); h ^= h >>> 15; return h >>> 0; } export default function slugify(code) { return doHash(code).toString(36); } ================================================ FILE: packages/testkit/src/__fixtures__/ts-compiled-re-exports/constants.js ================================================ "use strict"; exports.__esModule = true; exports.bar = exports.foo = void 0; exports.foo = 'foo'; exports.bar = 'bar'; ================================================ FILE: packages/testkit/src/__fixtures__/ts-compiled-re-exports/index.js ================================================ "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; exports.__esModule = true; __exportStar(require("./constants"), exports); ================================================ FILE: packages/testkit/src/__fixtures__/ts-data.ts ================================================ export enum TestEnum { FirstValue, SecondValue, } ================================================ FILE: packages/testkit/src/__fixtures__/with-babelrc/.babelrc.js ================================================ const path = require('path'); module.exports = { "plugins": [ [ "module-resolver", { "alias": { "_": "./src/__fixtures__" } } ] ] } ================================================ FILE: packages/testkit/src/__fixtures__/with-babelrc/index.js ================================================ import { styled } from '@linaria/react'; import { fooStyles } from "_/re-exports"; const value = fooStyles.foo; export const H1 = styled.h1` color: ${value}; `; ================================================ FILE: packages/testkit/src/__snapshots__/babel.test.ts.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`strategy shaker assigning to exports 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker assigning to exports 2`] = ` CSS: .square_s13jq05 { div { padding: 4px; } } Dependencies: ./__fixtures__/assignToExport `; exports[`strategy shaker cache should cache evaluation 1`] = ` "import { foo2 } from "./__fixtures__/foo-nonstatic"; export const text = "text_t13jq05";" `; exports[`strategy shaker cache should cache evaluation 2`] = ` CSS: .text_t13jq05 {font-size: foo1} Dependencies: ./__fixtures__/foo-nonstatic `; exports[`strategy shaker cache should reprocess module when cached exports are incomplete 1`] = `"export const text = "text_t13jq05";"`; exports[`strategy shaker cache should reprocess module when cached exports are incomplete 2`] = ` CSS: .text_t13jq05 {font-size: foo1foo2} Dependencies: ./__fixtures__/foo-nonstatic `; exports[`strategy shaker cache should use cached value 1`] = `"export const text = "text_t13jq05";"`; exports[`strategy shaker cache should use cached value 2`] = ` CSS: .text_t13jq05 {font-size: cached-foo1} Dependencies: ./__fixtures__/foo-nonstatic `; exports[`strategy shaker cache should use cached value even if only part is required 1`] = `"export const text = "text_t13jq05";"`; exports[`strategy shaker cache should use cached value even if only part is required 2`] = ` CSS: .text_t13jq05 {font-size: cached-foo1} Dependencies: ./__fixtures__/foo-nonstatic `; exports[`strategy shaker compiles atomic css 1`] = ` "/* @flow */ const x = "atm_26_5scuol atm_e2_12xxubj"; console.log(x);" `; exports[`strategy shaker compiles atomic css 2`] = ` CSS: .atm_26_5scuol{background:red;} .atm_e2_12xxubj{height:100px;} Dependencies: NA `; exports[`strategy shaker compiles atomic css with at-rules and property priorities 1`] = ` "/* @flow */ const x = "atm_1h9nsec_idpfg4 atm_7xgmf7_14y27yu atm_ci1k5c_i2wt44 atm_le_1v6z61t"; console.log(x);" `; exports[`strategy shaker compiles atomic css with at-rules and property priorities 2`] = ` CSS: @media (max-width: 500px){.atm_1h9nsec_idpfg4.atm_1h9nsec_idpfg4{padding:0;}} @media (min-width: 300px){.atm_7xgmf7_14y27yu.atm_7xgmf7_14y27yu.atm_7xgmf7_14y27yu:hover{padding-top:5px;}} .atm_ci1k5c_i2wt44.atm_ci1k5c_i2wt44:enabled{padding-left:6px;} .atm_le_1v6z61t.atm_le_1v6z61t{padding-bottom:7px;} Dependencies: NA `; exports[`strategy shaker compiles atomic css with at-rules and pseudo classes 1`] = ` "/* @flow */ const x = "atm_1apu8aw_13q2bts atm_1yli2by_1cnho6b atm_1hwwax4_1osqo2v atm_26_5scuol atm_e2_12xxubj"; console.log(x);" `; exports[`strategy shaker compiles atomic css with at-rules and pseudo classes 2`] = ` CSS: @media (max-width: 500px){.atm_1apu8aw_13q2bts.atm_1apu8aw_13q2bts{background:blue;}} @media (min-width: 300px){.atm_1yli2by_1cnho6b.atm_1yli2by_1cnho6b:hover{background:purple;}} .atm_1hwwax4_1osqo2v:enabled{width:100%;} .atm_26_5scuol{background:red;} .atm_e2_12xxubj{height:100px;} Dependencies: NA `; exports[`strategy shaker compiles atomic css with keyframes 1`] = ` "/* @flow */ const x = "atm_p_x1wbsp atm_26_5scuol atm_e2_12xxubj"; console.log(x);" `; exports[`strategy shaker compiles atomic css with keyframes 2`] = ` CSS: @keyframes fade { from { opacity: 0; } to { opacity: 1; } } .atm_p_x1wbsp{animation:fade 1s infinite;} .atm_26_5scuol{background:red;} .atm_e2_12xxubj{height:100px;} Dependencies: NA `; exports[`strategy shaker compiles atomic css with property priorities 1`] = ` "/* @flow */ const y = "atm_gz_14y27yu"; const x = "atm_gi_idpfg4"; console.log(x, y);" `; exports[`strategy shaker compiles atomic css with property priorities 2`] = ` CSS: .atm_gz_14y27yu.atm_gz_14y27yu{margin-left:5px;} .atm_gi_idpfg4{margin:0;} Dependencies: NA `; exports[`strategy shaker compiles atomic css with unique atoms based on key value pairs 1`] = ` "/* @flow */ const x = "atm_e2_12xxubj"; const y = "atm_e2_tnzek8"; console.log(x, y);" `; exports[`strategy shaker compiles atomic css with unique atoms based on key value pairs 2`] = ` CSS: .atm_e2_12xxubj{height:100px;} .atm_e2_tnzek8{height:99px;} Dependencies: NA `; exports[`strategy shaker compiles atomic styled with dynamic interpolations as unique variables based on the interpolation text 1`] = ` "/* @flow */ import { styled } from '@linaria/atomic'; const _exp2 = () => props => props.color; const _exp3 = () => props => props.backgroundColor; const Component = /*#__PURE__*/styled('div')({ name: "Component", class: "atm_7l_15g95l5 atm_4b_15g95l5 atm_2d_1en4k16 Component_c13jq05", propsAsIs: false, vars: { "1p69eoh": [_exp2()], "l12cfn": [_exp3()] }, atomic: true }); const _exp4 = () => props => props.color; const _exp5 = () => props => props.color || "black"; const Component2 = /*#__PURE__*/styled('div')({ name: "Component2", class: "atm_7l_15g95l5 atm_4b_1kgl01d Component2_c1vhermz", propsAsIs: false, vars: { "1p69eoh": [_exp4()], "1n9iccq": [_exp5()] }, atomic: true }); console.log(Component, Component2);" `; exports[`strategy shaker compiles atomic styled with dynamic interpolations as unique variables based on the interpolation text 2`] = ` CSS: .atm_7l_15g95l5{color:var(--1p69eoh);} .atm_4b_15g95l5.atm_4b_15g95l5{border-color:var(--1p69eoh);} .atm_2d_1en4k16.atm_2d_1en4k16{background-color:var(--l12cfn);} .atm_4b_1kgl01d.atm_4b_1kgl01d{border-color:var(--1n9iccq);} Dependencies: NA `; exports[`strategy shaker compiles atomic styled with plain css, static and dynamic interpolations 1`] = ` "/* @flow */ import { styled } from '@linaria/atomic'; const _exp2 = () => props => props.color; const Component = /*#__PURE__*/styled('div')({ name: "Component", class: "atm_7l_13q2bts atm_e2_12xxubj atm_gi_12am3vd atm_2d_15g95l5 Component_c13jq05", propsAsIs: false, vars: { "1p69eoh": [_exp2()] }, atomic: true }); console.log(Component);" `; exports[`strategy shaker compiles atomic styled with plain css, static and dynamic interpolations 2`] = ` CSS: .atm_7l_13q2bts{color:blue;} .atm_e2_12xxubj{height:100px;} .atm_gi_12am3vd{margin:50px;} .atm_2d_15g95l5.atm_2d_15g95l5{background-color:var(--1p69eoh);} Dependencies: NA `; exports[`strategy shaker compiles atomic styled with static css 1`] = ` "/* @flow */ import { styled } from '@linaria/atomic'; const Component = /*#__PURE__*/styled('div')({ name: "Component", class: "atm_7l_13q2bts atm_e2_12xxubj Component_c13jq05", propsAsIs: false, atomic: true }); console.log(Component);" `; exports[`strategy shaker compiles atomic styled with static css 2`] = ` CSS: .atm_7l_13q2bts{color:blue;} .atm_e2_12xxubj{height:100px;} Dependencies: NA `; exports[`strategy shaker compiles atomic styled without colliding by property 1`] = ` "/* @flow */ import { styled } from '@linaria/atomic'; export const Component = /*#__PURE__*/styled('ul')({ name: "Component", class: "atm_9s_1txwivl atm_l8_idpfg4 Component_c13jq05", propsAsIs: false, atomic: true }); export const Component2 = /*#__PURE__*/styled('ul')({ name: "Component2", class: "atm_9s_1ulexfb atm_l8_idpfg4 Component2_c1vhermz", propsAsIs: false, atomic: true });" `; exports[`strategy shaker compiles atomic styled without colliding by property 2`] = ` CSS: .atm_9s_1txwivl{display:flex;} .atm_l8_idpfg4{padding:0;} .atm_9s_1ulexfb{display:block;} Dependencies: NA `; exports[`strategy shaker compiles atomic styled wrapping other components with extra priority 1`] = ` "/* @flow */ import { styled } from '@linaria/atomic'; const Component = /*#__PURE__*/styled('div')({ name: "Component", class: "atm_2d_13q2bts atm_e2_12xxubj Component_c13jq05", propsAsIs: false, atomic: true }); const _exp = () => Component; const ComponentCompositing = /*#__PURE__*/styled(_exp())({ name: "ComponentCompositing", class: "atm_26_5scuol atm_e2_1nzxncv ComponentCompositing_c1vhermz", propsAsIs: true, atomic: true }); console.log(ComponentCompositing);" `; exports[`strategy shaker compiles atomic styled wrapping other components with extra priority 2`] = ` CSS: .atm_2d_13q2bts.atm_2d_13q2bts{background-color:blue;} .atm_e2_12xxubj{height:100px;} .atm_26_5scuol.atm_26_5scuol{background:red;} .atm_e2_1nzxncv.atm_e2_1nzxncv{height:105px;} Dependencies: NA `; exports[`strategy shaker compiles atoms that are shared between css and styled templates 1`] = ` "/* @flow */ import { styled } from '@linaria/atomic'; const x = "atm_26_5scuol atm_e2_12xxubj"; const _exp2 = () => props => props.color; const Component = /*#__PURE__*/styled('div')({ name: "Component", class: "atm_26_5scuol atm_e2_12xxubj atm_gi_19bvopo atm_7l_15g95l5 Component_c1vhermz", propsAsIs: false, vars: { "1p69eoh": [_exp2()] }, atomic: true }); console.log(x, Component);" `; exports[`strategy shaker compiles atoms that are shared between css and styled templates 2`] = ` CSS: .atm_26_5scuol{background:red;} .atm_e2_12xxubj{height:100px;} .atm_gi_19bvopo{margin:10px;} .atm_7l_15g95l5{color:var(--1p69eoh);} Dependencies: NA `; exports[`strategy shaker compiles css with keyframes 1`] = ` "const x = "x_x13jq05"; console.log(x);" `; exports[`strategy shaker compiles css with keyframes 2`] = ` CSS: .x_x13jq05 { @keyframes fade { from { opacity: 0; } to { opacity: 1; } } animation: fade 1s infinite; background: red; height: 100px; } Dependencies: NA `; exports[`strategy shaker concurrent multiple parallel chains of reexports 1`] = ` "import { styled } from '@linaria/react'; export const H1foo = /*#__PURE__*/styled('h1')({ name: "H1foo", class: "H1foo_h1m1lid5", propsAsIs: false });" `; exports[`strategy shaker concurrent multiple parallel chains of reexports 2`] = ` CSS: .H1foo_h1m1lid5 { color: foo; } Dependencies: ./__fixtures__/re-exports `; exports[`strategy shaker concurrent multiple parallel chains of reexports 3`] = ` "import { styled } from '@linaria/react'; export const H1bar = /*#__PURE__*/styled('h1')({ name: "H1bar", class: "H1bar_h1r70tzz", propsAsIs: false });" `; exports[`strategy shaker concurrent multiple parallel chains of reexports 4`] = ` CSS: .H1bar_h1r70tzz { color: bar; } Dependencies: ./__fixtures__/re-exports `; exports[`strategy shaker concurrent multiple parallel chains of reexports 5`] = ` "import { styled } from '@linaria/react'; export const H1bar1 = /*#__PURE__*/styled('h1')({ name: "H1bar1", class: "H1bar1_hsluxkf", propsAsIs: false });" `; exports[`strategy shaker concurrent multiple parallel chains of reexports 6`] = ` CSS: .H1bar1_hsluxkf { color: bar1; } Dependencies: ./__fixtures__/re-exports `; exports[`strategy shaker concurrent multiple parallel chains of reexports 7`] = ` "import { styled } from '@linaria/react'; export const H1bar2 = /*#__PURE__*/styled('h1')({ name: "H1bar2", class: "H1bar2_ht4s9ym", propsAsIs: false });" `; exports[`strategy shaker concurrent multiple parallel chains of reexports 8`] = ` CSS: .H1bar2_ht4s9ym { color: bar2; } Dependencies: ./__fixtures__/re-exports `; exports[`strategy shaker concurrent two parallel chains of reexports 1`] = ` "import { styled } from '@linaria/react'; export const H1 = /*#__PURE__*/styled('h1')({ name: "H1", class: "H1_hpsacp3", propsAsIs: false });" `; exports[`strategy shaker concurrent two parallel chains of reexports 2`] = ` CSS: .H1_hpsacp3 { color: foo; } Dependencies: ./__fixtures__/re-exports `; exports[`strategy shaker concurrent two parallel chains of reexports 3`] = ` "import { styled } from '@linaria/react'; export const H1 = /*#__PURE__*/styled('h1')({ name: "H1", class: "H1_htinbxh", propsAsIs: false });" `; exports[`strategy shaker concurrent two parallel chains of reexports 4`] = ` CSS: .H1_htinbxh { color: bar2; } Dependencies: ./__fixtures__/re-exports `; exports[`strategy shaker derives display name from filename 1`] = ` "import { styled } from '@linaria/react'; export default /*#__PURE__*/styled('h1')({ name: "FancyName0", class: "FancyName0_f15w9xbr", propsAsIs: false });" `; exports[`strategy shaker derives display name from filename 2`] = ` CSS: .FancyName0_f15w9xbr { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker derives display name from parent folder name 1`] = ` "import { styled } from '@linaria/react'; export default /*#__PURE__*/styled('h1')({ name: "FancyName0", class: "FancyName0_f13t8ham", propsAsIs: false });" `; exports[`strategy shaker derives display name from parent folder name 2`] = ` CSS: .FancyName0_f13t8ham { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker do not include in dependencies expressions from interpolation functions bodies 1`] = ` "import { styled } from '@linaria/react'; import constant from './broken-dependency-1'; import modifier from './broken-dependency-2'; const _exp = () => props => props.size + constant; const _exp2 = () => props => modifier(props.size); export const Box = /*#__PURE__*/styled('div')({ name: "Box", class: "Box_b13jq05", propsAsIs: false, vars: { "b13jq05-0": [_exp(), "px"], "b13jq05-1": [_exp2(), "px"] } });" `; exports[`strategy shaker do not include in dependencies expressions from interpolation functions bodies 2`] = ` CSS: .Box_b13jq05 { height: var(--b13jq05-0); width: var(--b13jq05-1); } Dependencies: NA `; exports[`strategy shaker does not include styles if not referenced anywhere 1`] = ` "import { styled } from '@linaria/react'; const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false }); const title = "title_t1vhermz";" `; exports[`strategy shaker does not include styles if not referenced anywhere 2`] = ` CSS: Dependencies: NA `; exports[`strategy shaker does not output CSS if none present 1`] = ` "const number = 42; const title = String.raw\`This is something\`;" `; exports[`strategy shaker does not output CSS if none present 2`] = ` CSS: Dependencies: NA `; exports[`strategy shaker does not output CSS property when value is a blank string 1`] = `"export const title = "title_t13jq05";"`; exports[`strategy shaker does not output CSS property when value is a blank string 2`] = ` CSS: .title_t13jq05 { font-size: ; margin: 6px; } Dependencies: NA `; exports[`strategy shaker does not strip istanbul coverage sequences 1`] = ` "function cov___HASH__() { var path = "__PATH__"; var hash = "__HASH__"; var global = new Function("return this")(); var gcv = "__coverage__"; var coverageData = { path: "__PATH__", statementMap: { "0": { start: { line: 2, column: 10 }, end: { line: 2, column: 12 } }, "1": { start: { line: 4, column: 26 }, end: { line: 6, column: 1 } } }, fnMap: {}, branchMap: {}, s: { "0": 0, "1": 0 }, f: {}, b: {}, _coverageSchema: "1a1c01bbd47fc00a2c39e90264f33305004495a9", hash: "__HASH__" }; var coverage = global[gcv] || (global[gcv] = {}); if (!coverage[path] || coverage[path].hash !== hash) { coverage[path] = coverageData; } var actualCoverage = coverage[path]; { // @ts-ignore cov___HASH__ = function () { return actualCoverage; }; } return actualCoverage; } cov___HASH__(); export const titleClass = "titleClass_t13jq05";" `; exports[`strategy shaker does not strip istanbul coverage sequences 2`] = ` CSS: .titleClass_t13jq05 { height: 42px; } Dependencies: NA `; exports[`strategy shaker evaluates and inlines expressions in scope 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker evaluates and inlines expressions in scope 2`] = ` CSS: .Title_t13jq05 { color: blue; width: 33.333333333333336%; } Dependencies: NA `; exports[`strategy shaker evaluates babel helpers 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker evaluates babel helpers 2`] = ` CSS: .Title_t13jq05 { &:before { content: "2" } } Dependencies: NA `; exports[`strategy shaker evaluates chain of reexports 1`] = ` "import { styled } from '@linaria/react'; export const H1 = /*#__PURE__*/styled('h1')({ name: "H1", class: "H1_h13jq05", propsAsIs: false });" `; exports[`strategy shaker evaluates chain of reexports 2`] = ` CSS: .H1_h13jq05 { color: foo; } Dependencies: ./__fixtures__/re-exports `; exports[`strategy shaker evaluates complex styles with functions and nested selectors 1`] = ` "export const bareIconClass = "bareIconClass_b13jq05"; export const SIZES = { XS: "XS_x1vhermz" };" `; exports[`strategy shaker evaluates complex styles with functions and nested selectors 2`] = ` CSS: .bareIconClass_b13jq05 {} .XS_x1vhermz {&.bareIconClass_b13jq05 { font-size: 16.5px; }} Dependencies: NA `; exports[`strategy shaker evaluates component interpolations 1`] = ` "const { styled } = require('@linaria/react'); export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false }); export const Paragraph = /*#__PURE__*/styled('p')({ name: "Paragraph", class: "Paragraph_p1vhermz", propsAsIs: false });" `; exports[`strategy shaker evaluates component interpolations 2`] = ` CSS: .Title_t13jq05 { color: red; } .Paragraph_p1vhermz { .Title_t13jq05 { color: blue; } } Dependencies: NA `; exports[`strategy shaker evaluates dependencies with sequence expression 1`] = ` "import { styled } from '@linaria/react'; let external = 0; const color = (external, () => 'blue'); const _exp = () => color; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "t13jq05-0": [_exp()] } });" `; exports[`strategy shaker evaluates dependencies with sequence expression 2`] = ` CSS: .Title_t13jq05 { color: var(--t13jq05-0); } Dependencies: NA `; exports[`strategy shaker evaluates expressions with dependencies 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker evaluates expressions with dependencies 2`] = ` CSS: .Title_t13jq05 { &:before { content: "6og6jy" } } Dependencies: ./__fixtures__/slugify `; exports[`strategy shaker evaluates expressions with expressions depending on shared dependency 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker evaluates expressions with expressions depending on shared dependency 2`] = ` CSS: .Title_t13jq05 { &:before { content: "6og6jyboo6og6jybar" } } Dependencies: ./__fixtures__/slugify `; exports[`strategy shaker evaluates functions with nested identifiers 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker evaluates functions with nested identifiers 2`] = ` CSS: .Title_t13jq05 { font-size: 12px; } Dependencies: NA `; exports[`strategy shaker evaluates identifier in scope 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker evaluates identifier in scope 2`] = ` CSS: .Title_t13jq05 { &:before { content: "42 days" } } Dependencies: NA `; exports[`strategy shaker evaluates imported typescript enums 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t9vkbjs", propsAsIs: false });" `; exports[`strategy shaker evaluates imported typescript enums 2`] = ` CSS: .Title_t9vkbjs { color: #27509A; } Dependencies: ./__fixtures__/enums `; exports[`strategy shaker evaluates interpolations with sequence expression 1`] = ` "import { styled } from '@linaria/react'; const _exp = () => (0, () => "blue"); export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "t13jq05-0": [_exp()] } });" `; exports[`strategy shaker evaluates interpolations with sequence expression 2`] = ` CSS: .Title_t13jq05 { color: var(--t13jq05-0); } Dependencies: NA `; exports[`strategy shaker evaluates local expressions 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker evaluates local expressions 2`] = ` CSS: .Title_t13jq05 { &:before { content: "42 days" } } Dependencies: NA `; exports[`strategy shaker evaluates multiple expressions with shared dependency 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker evaluates multiple expressions with shared dependency 2`] = ` CSS: .Title_t13jq05 { &:before { content: "6og6jyboo" content: "6og6jybar" } } Dependencies: ./__fixtures__/slugify `; exports[`strategy shaker evaluates nested nested object interpolation 1`] = `"export const greenContentStyles = "greenContentStyles_g1vhermz";"`; exports[`strategy shaker evaluates nested nested object interpolation 2`] = ` CSS: .defaultStyle_d13jq05 { color: red; padding-bottom: 0px; } .greenContentStyles_g1vhermz { &.defaultStyle_d13jq05 .green { display: inline-block; border: 1px solid green; } } Dependencies: NA `; exports[`strategy shaker evaluates typescript enums 1`] = ` "import { styled } from '@linaria/react'; enum Colors { BLUE = '#27509A', } export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t9vkbjs", propsAsIs: false });" `; exports[`strategy shaker evaluates typescript enums 2`] = ` CSS: .Title_t9vkbjs { color: #27509A; } Dependencies: NA `; exports[`strategy shaker exporting objects 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker exporting objects 2`] = ` CSS: .square_s13jq05 { div { margin: 5px; } } Dependencies: ./__fixtures__/objectExport `; exports[`strategy shaker exporting objects with computed keys 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker exporting objects with computed keys 2`] = ` CSS: .square_s13jq05 { div { color: blue; } } Dependencies: ./__fixtures__/computedKeys `; exports[`strategy shaker exporting sequence expressions 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker exporting sequence expressions 2`] = ` CSS: .square_s13jq05 { div { height: 5px; } } Dependencies: ./__fixtures__/sequenceExport `; exports[`strategy shaker generates stable class names 1`] = ` "import { styled } from '@linaria/react'; export const T1 = /*#__PURE__*/styled('h1')({ name: "T1", class: "T1_t11kcpnd", propsAsIs: false }); export const T2 = /*#__PURE__*/styled('h2')({ name: "T2", class: "T2_t1xdipzs", propsAsIs: false }); export const T3 = /*#__PURE__*/styled('h3')({ name: "T3", class: "T3_tmgfls7", propsAsIs: false }); export default /*#__PURE__*/styled('p')({ name: "components-library3", class: "components-library3_c30gynh", propsAsIs: false });" `; exports[`strategy shaker generates stable class names 2`] = ` CSS: .T1_t11kcpnd { background: #111; } .T2_t1xdipzs { background: #222; } .T3_tmgfls7 { .T2_t1xdipzs { background: #333; } } .components-library3_c30gynh { background: #333; } Dependencies: NA `; exports[`strategy shaker handles complex component 1`] = ` "// Dead code in this file should be ignored import deadDep from 'unknown-dependency'; import { styled } from '@linaria/react'; export const deadValue = deadDep(); const objects = { font: { fontSize: 12 }, box: { border: '1px solid red' } }; objects.font.fontWeight = 'bold'; export const whiteColor = '#fff'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t1us8k4s", propsAsIs: false });" `; exports[`strategy shaker handles complex component 2`] = ` CSS: .Title_t1us8k4s { font-size: 12px; font-weight: bold; border: 1px solid red; } Dependencies: NA `; exports[`strategy shaker handles css template literal in JSX element 1`] = `";"`; exports[`strategy shaker handles css template literal in JSX element 2`] = ` CSS: .Title_twgemqq { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker handles css template literal in object property 1`] = ` "const components = { title: "title_t13jq05" };" `; exports[`strategy shaker handles css template literal in object property 2`] = ` CSS: .title_t13jq05 { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker handles dashes in variableNameConfig 1`] = ` "import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; const _exp = () => props => props.size; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "t13jq05-0": [_exp(), "px"] } }); const _exp2 = () => props => props.size; export const Body = /*#__PURE__*/atomicStyled('h1')({ name: "Body", class: "atm_c8_trva6l Body_b1vhermz", propsAsIs: false, vars: { "1qqvhyq": [_exp2(), "px"] }, atomic: true });" `; exports[`strategy shaker handles dashes in variableNameConfig 2`] = ` CSS: .Title_t13jq05 { font-size: --t13jq05-0; } .atm_c8_trva6l.atm_c8_trva6l{font-size:--1qqvhyq;} Dependencies: NA `; exports[`strategy shaker handles escapes properly 1`] = ` "import { styled } from '@linaria/react'; export const Block = /*#__PURE__*/styled('div')({ name: "Block", class: "Block_b3rflbm", propsAsIs: false });" `; exports[`strategy shaker handles escapes properly 2`] = ` CSS: .Block_b3rflbm { a { content: "\\u000A"; } b { content: "\\u000A"; }; } Dependencies: NA `; exports[`strategy shaker handles fn passed in classNameSlug 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "t13jq05_Title_t13jq05_Title_src_source_js_source__js_src", propsAsIs: false });" `; exports[`strategy shaker handles fn passed in classNameSlug 2`] = ` CSS: .t13jq05_Title_t13jq05_Title_src_source_js_source__js_src { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker handles fn passed in variableNameSlug 1`] = ` "import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; const _exp = () => props => props.size; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "_qqvhyq__Title__font-size": [_exp(), "px"] } }); const _exp2 = () => props => props.size; export const Body = /*#__PURE__*/atomicStyled('h1')({ name: "Body", class: "atm_c8_f3y1j4 Body_b1vhermz", propsAsIs: false, vars: { "1qqvhyq__Body__font-size": [_exp2(), "px"] }, atomic: true });" `; exports[`strategy shaker handles fn passed in variableNameSlug 2`] = ` CSS: .Title_t13jq05 { font-size: var(--_qqvhyq__Title__font-size); } .atm_c8_f3y1j4.atm_c8_f3y1j4{font-size:var(--1qqvhyq__Body__font-size);} Dependencies: NA `; exports[`strategy shaker handles indirect wrapping another styled component 1`] = ` "const { styled } = require('@linaria/react'); const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false }); const hoc = Cmp => Cmp; const _exp = () => hoc(Title); export const CustomTitle = /*#__PURE__*/styled(_exp())({ name: "CustomTitle", class: "CustomTitle_c1vhermz", propsAsIs: true });" `; exports[`strategy shaker handles indirect wrapping another styled component 2`] = ` CSS: .Title_t13jq05 { color: red; } .CustomTitle_c1vhermz.Title_t13jq05 { font-size: 24px; color: blue; } Dependencies: NA `; exports[`strategy shaker handles interpolation followed by unit 1`] = ` "import { styled } from '@linaria/react'; const size = () => 100; const shadow = () => 5; const unit = () => 1; const _exp = () => size; const _exp2 = () => shadow; const _exp3 = () => size; const _exp4 = () => props => props.width; const _exp5 = () => props => { if (true) { return props.height; } else { return 200; } }; const _exp7 = () => unit; const _exp8 = () => function (props) { return 200; }; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "t13jq05-0": [_exp(), "em"], "t13jq05-1": [_exp2(), "px"], "t13jq05-2": [_exp3(), "px"], "t13jq05-3": [_exp4(), "vw"], "t13jq05-4": [_exp5(), "px"], "t13jq05-5": [_exp7(), "fr"], "t13jq05-6": [_exp8(), "px"] } });" `; exports[`strategy shaker handles interpolation followed by unit 2`] = ` CSS: .Title_t13jq05 { font-size: var(--t13jq05-0); text-shadow: black 1px var(--t13jq05-1), white -2px -2px; margin: var(--t13jq05-2); width: calc(2 * var(--t13jq05-3)); height: var(--t13jq05-4); grid-template-columns: var(--t13jq05-5) 1fr 1fr var(--t13jq05-5); border-radius: var(--t13jq05-6); padding: 10px; } Dependencies: NA `; exports[`strategy shaker handles interpolation in css function followed by unit 1`] = ` "import { styled } from '@linaria/atomic'; const _exp = () => props => props.$rotateDeg; export const Container = /*#__PURE__*/styled('div')({ name: "Container", class: "atm_tr_18309cv atm_vy_uuw12j Container_c13jq05", propsAsIs: false, vars: { "y6125t": [_exp(), "deg"] }, atomic: true });" `; exports[`strategy shaker handles interpolation in css function followed by unit 2`] = ` CSS: .atm_tr_18309cv{transform:rotate(var(--y6125t));} .atm_vy_uuw12j{width:200px;} Dependencies: NA `; exports[`strategy shaker handles nested blocks 1`] = ` "import { styled } from '@linaria/react'; const regular = () => "arial"; const _exp = () => regular; export const Button = /*#__PURE__*/styled('button')({ name: "Button", class: "Button_b13jq05", propsAsIs: false, vars: { "b13jq05-0": [_exp()] } });" `; exports[`strategy shaker handles nested blocks 2`] = ` CSS: .Button_b13jq05 { font-family: var(--b13jq05-0); &:hover { border-color: blue; } @media (max-width: 200px) { width: 100%; } } Dependencies: NA `; exports[`strategy shaker handles objects with enums as keys 1`] = ` "import { TestEnum } from './__fixtures__/ts-data.ts'; export const object = { [TestEnum.FirstValue]: "TestEnum_FirstValue_t9vkbjs", [TestEnum.SecondValue]: "TestEnum_SecondValue_t17e3x2d" };" `; exports[`strategy shaker handles objects with enums as keys 2`] = ` CSS: .TestEnum_FirstValue_t9vkbjs {} .TestEnum_SecondValue_t17e3x2d {} Dependencies: NA `; exports[`strategy shaker handles objects with numeric keys 1`] = ` "export const object = { stringKey: "stringKey_s13jq05", 42: "_2__1vhermz" };" `; exports[`strategy shaker handles objects with numeric keys 2`] = ` CSS: .stringKey_s13jq05 {} ._2__1vhermz {} Dependencies: NA `; exports[`strategy shaker handles raw in variableNameConfig 1`] = ` "import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; const _exp = () => props => props.size; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "t13jq05-0": [_exp(), "px"] } }); const _exp2 = () => props => props.size; export const Body = /*#__PURE__*/atomicStyled('h1')({ name: "Body", class: "atm_c8_1s69o7d Body_b1vhermz", propsAsIs: false, vars: { "1qqvhyq": [_exp2(), "px"] }, atomic: true });" `; exports[`strategy shaker handles raw in variableNameConfig 2`] = ` CSS: .Title_t13jq05 { font-size: t13jq05-0; } .atm_c8_1s69o7d.atm_c8_1s69o7d{font-size:1qqvhyq;} Dependencies: NA `; exports[`strategy shaker handles val in variableNameConfig 1`] = ` "import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; const _exp = () => props => props.size; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "t13jq05-0": [_exp(), "px"] } }); const _exp2 = () => props => props.size; export const Body = /*#__PURE__*/atomicStyled('h1')({ name: "Body", class: "atm_c8_1g7eom2 Body_b1vhermz", propsAsIs: false, vars: { "1qqvhyq": [_exp2(), "px"] }, atomic: true });" `; exports[`strategy shaker handles val in variableNameConfig 2`] = ` CSS: .Title_t13jq05 { font-size: var(--t13jq05-0); } .atm_c8_1g7eom2.atm_c8_1g7eom2{font-size:var(--1qqvhyq);} Dependencies: NA `; exports[`strategy shaker handles wrapping another styled component 1`] = ` "const { styled } = require('@linaria/react'); const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false }); const _exp = () => Title; export const BlueTitle = /*#__PURE__*/styled(_exp())({ name: "BlueTitle", class: "BlueTitle_b1vhermz", propsAsIs: true }); const _exp2 = () => BlueTitle; export const GreenTitle = /*#__PURE__*/styled(_exp2())({ name: "GreenTitle", class: "GreenTitle_g1egpet8", propsAsIs: true });" `; exports[`strategy shaker handles wrapping another styled component 2`] = ` CSS: .Title_t13jq05 { color: red; } .BlueTitle_b1vhermz.Title_t13jq05 { font-size: 24px; color: blue; } .GreenTitle_g1egpet8.BlueTitle_b1vhermz.Title_t13jq05 { color: green; } Dependencies: NA `; exports[`strategy shaker hoistable identifiers 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker hoistable identifiers 2`] = ` CSS: .Title_t13jq05 { &:before { content: "42" } } Dependencies: NA `; exports[`strategy shaker ignores external expressions 1`] = ` "import { styled } from '@linaria/react'; const generate = props => props.content; const _exp = () => generate; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "t13jq05-0": [_exp()] } });" `; exports[`strategy shaker ignores external expressions 2`] = ` CSS: .Title_t13jq05 { &:before { content: "var(--t13jq05-0)" } } Dependencies: NA `; exports[`strategy shaker ignores inline arrow function expressions 1`] = ` "import { styled } from '@linaria/react'; const _exp = () => props => props.content; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "t13jq05-0": [_exp()] } });" `; exports[`strategy shaker ignores inline arrow function expressions 2`] = ` CSS: .Title_t13jq05 { &:before { content: "var(--t13jq05-0)" } } Dependencies: NA `; exports[`strategy shaker ignores inline vanilla function expressions 1`] = ` "import { styled } from '@linaria/react'; const _exp = () => function (props) { return props.content; }; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "t13jq05-0": [_exp()] } });" `; exports[`strategy shaker ignores inline vanilla function expressions 2`] = ` CSS: .Title_t13jq05 { &:before { content: "var(--t13jq05-0)" } } Dependencies: NA `; exports[`strategy shaker includes unreferenced styles for :global 1`] = ` "import { styled } from '@linaria/react'; const a = "a_a13jq05"; const B = /*#__PURE__*/styled('div')({ name: "B", class: "B_b1vhermz", propsAsIs: false });" `; exports[`strategy shaker includes unreferenced styles for :global 2`] = ` CSS: .a_a13jq05 { :global() { .title { font-size: 14px; } } } .B_b1vhermz { :global(.title) { font-size: 14px; } } Dependencies: NA `; exports[`strategy shaker inlines array styles as CSS string 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker inlines array styles as CSS string 2`] = ` CSS: .Title_t13jq05 { flex: 1; display: block; height: 24px; } Dependencies: NA `; exports[`strategy shaker inlines array styles as CSS string 3`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker inlines array styles as CSS string 4`] = ` CSS: .Title_t13jq05 { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } Dependencies: NA `; exports[`strategy shaker inlines object styles as CSS string 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker inlines object styles as CSS string 2`] = ` CSS: .Title_t13jq05 { --color-primaryText: #222; position: absolute; top: 0; right: 0; bottom: 0; left: 0; opacity: 1; min-height: 420px; &.shouldNotBeChanged { border-color: #fff; } @media (min-width: 200px) { -webkit-opacity: 0.8; -moz-opacity: 0.8; -ms-opacity: 0.8; -o-opacity: 0.8; -webkit-border-radius: 2px; -moz-border-radius: 2px; -ms-border-radius: 2px; -o-border-radius: 2px; -webkit-transition: 400ms; -moz-transition: 400ms; -o-transition: 400ms; -ms-transition: 400ms; } } Dependencies: NA `; exports[`strategy shaker inlines object styles as CSS string 3`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker inlines object styles as CSS string 4`] = ` CSS: .Title_t13jq05 { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } Dependencies: NA `; exports[`strategy shaker it should not throw location error for hoisted identifier 1`] = ` "import React from 'react'; export default function Component() { return "source0_s13jq05"; }" `; exports[`strategy shaker it should not throw location error for hoisted identifier 2`] = ` CSS: .source0_s13jq05 {opacity:5;} Dependencies: NA `; exports[`strategy shaker keeps cx import and removes css 1`] = ` "import { cx } from '@linaria/core'; const defaultStyle = "defaultStyle_d13jq05"; export const combined = cx(defaultStyle, Math.random() > 0.5 ? 'green' : 'red');" `; exports[`strategy shaker keeps cx import and removes css 2`] = ` CSS: .defaultStyle_d13jq05 { color: red; } Dependencies: NA `; exports[`strategy shaker non-hoistable identifiers 1`] = ` "<<DIRNAME>>/source.js: An error occurred when evaluating the expression: > days is not defined. Make sure you are not using a browser or Node specific API and all the variables are available in static context. Linaria have to extract pieces of your code to resolve the interpolated values. Defining styled component or class will not work inside: - function, - class, - method, - loop, because it cannot be statically determined in which context you use them. That's why some variables may be not defined during evaluation. 7 | export const Title = styled.h1\` 8 | &:before { > 9 | content: "\${days}" | ^^^^ 10 | } 11 | \`;" `; exports[`strategy shaker outputs valid CSS classname 1`] = ` "import { styled } from '@linaria/react'; export const ΩPage$Title = /*#__PURE__*/styled('h1')({ name: "\\u03A9Page$Title", class: "\\u03A9Page_Title_\\u03C913jq05", propsAsIs: false });" `; exports[`strategy shaker outputs valid CSS classname 2`] = ` CSS: .ΩPage_Title_ω13jq05 { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker prevents class name collision 1`] = ` "import { styled } from '@linaria/react'; const size = () => 100; const regular = () => "arial"; const _exp = () => size; const _exp2 = () => props => props.color; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_twgemqq", propsAsIs: false, vars: { "twgemqq-0": [_exp(), "px"], "twgemqq-1": [_exp2()] } }); const _exp3 = () => regular; export function Something() { const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_tjtmpns", propsAsIs: false, vars: { "tjtmpns-0": [_exp3()] } }); return <Title />; }" `; exports[`strategy shaker prevents class name collision 2`] = ` CSS: .Title_twgemqq { font-size: var(--twgemqq-0); color: var(--twgemqq-1) } .Title_tjtmpns { font-family: var(--tjtmpns-0); } Dependencies: NA `; exports[`strategy shaker removes fake replacement patterns in string classNameSlug 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "__", propsAsIs: false });" `; exports[`strategy shaker removes fake replacement patterns in string classNameSlug 2`] = ` CSS: .__ { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker respects module-resolver plugin and don't show waring 1`] = ` "import { styled } from '@linaria/react'; export const H1 = /*#__PURE__*/styled('h1')({ name: "H1", class: "H1_hlxjig5", propsAsIs: false });" `; exports[`strategy shaker respects module-resolver plugin and don't show waring 2`] = ` CSS: .H1_hlxjig5 { color: foo; } Dependencies: ../re-exports `; exports[`strategy shaker respects module-resolver plugin and show waring 1`] = ` "import { styled } from '@linaria/react'; export const H1 = /*#__PURE__*/styled('h1')({ name: "H1", class: "H1_hlxjig5", propsAsIs: false });" `; exports[`strategy shaker respects module-resolver plugin and show waring 2`] = ` CSS: .H1_hlxjig5 { color: foo; } Dependencies: ../re-exports `; exports[`strategy shaker should apply stylis 1`] = ` ".Title_t13jq05.Title_t13jq05>span{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;} " `; exports[`strategy shaker should apply stylis 2`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker should apply stylis 3`] = ` CSS: .Title_t13jq05 { && > span { display:flex; } } Dependencies: NA `; exports[`strategy shaker should eval component from a linaria library 1`] = ` "import { styled } from "@linaria/react"; import { Title } from "./__fixtures__/linaria-ui-library/components/index"; const _exp = () => Title; export const StyledTitle = /*#__PURE__*/styled(_exp())({ name: "StyledTitle", class: "StyledTitle_s13jq05", propsAsIs: true });" `; exports[`strategy shaker should eval component from a linaria library 2`] = ` CSS: .StyledTitle_s13jq05 {} Dependencies: ./__fixtures__/linaria-ui-library/components/index `; exports[`strategy shaker should eval wrapped component from a linaria library 1`] = ` "import { styled } from "@linaria/react"; import { connect } from "./__fixtures__/linaria-ui-library/hocs"; import { Title } from "./__fixtures__/linaria-ui-library/components/index"; const _exp = () => connect(Title); export const StyledTitle = /*#__PURE__*/styled(_exp())({ name: "StyledTitle", class: "StyledTitle_s13jq05", propsAsIs: true });" `; exports[`strategy shaker should eval wrapped component from a linaria library 2`] = ` CSS: .StyledTitle_s13jq05 {} Dependencies: ./__fixtures__/linaria-ui-library/hocs, ./__fixtures__/linaria-ui-library/components/index `; exports[`strategy shaker should handle shadowed identifier inside components 1`] = ` "import React from 'react'; const color = 'red'; export default function Component() { return React.createElement('div', { className: "className_c13jq05" }); }" `; exports[`strategy shaker should handle shadowed identifier inside components 2`] = ` CSS: .className_c13jq05 {background-color:blue;} Dependencies: NA `; exports[`strategy shaker should ignore unused wildcard reexports 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker should ignore unused wildcard reexports 2`] = ` CSS: .square_s13jq05 { color: foo1; } Dependencies: ./__fixtures__/reexports `; exports[`strategy shaker should import react as namespace 1`] = ` "import { styled } from "@linaria/react"; import * as React from "react"; const Cmp = React.memo(() => null); const _exp = () => Cmp; export const StyledTitle = /*#__PURE__*/styled(_exp())({ name: "StyledTitle", class: "StyledTitle_s13jq05", propsAsIs: true });" `; exports[`strategy shaker should import react as namespace 2`] = ` CSS: .StyledTitle_s13jq05 {} Dependencies: react `; exports[`strategy shaker should interpolate imported components 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker should interpolate imported components 2`] = ` CSS: .square_s13jq05 { .Title_t1us8k4s { color: red; } } Dependencies: ./__fixtures__/complex-component `; exports[`strategy shaker should interpolate imported variables 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker should interpolate imported variables 2`] = ` CSS: .square_s13jq05 { color: #fff } Dependencies: ./__fixtures__/complex-component `; exports[`strategy shaker should not drop exported vars of renamed imports 1`] = ` "import { foo3 } from "./__fixtures__/reexports"; export const bar3 = foo3; export const square = "square_s13jq05";" `; exports[`strategy shaker should not drop exported vars of renamed imports 2`] = ` CSS: .square_s13jq05 { color: foo3; } Dependencies: ./__fixtures__/reexports `; exports[`strategy shaker should not eval components from a non-linaria library 1`] = ` "import { styled } from "@linaria/react"; import { Title } from "./__fixtures__/non-linaria-ui-library/index"; const _exp = () => Title; export const StyledTitle = /*#__PURE__*/styled(_exp())({ name: "StyledTitle", class: "StyledTitle_s13jq05", propsAsIs: true });" `; exports[`strategy shaker should not eval components from a non-linaria library 2`] = ` CSS: .StyledTitle_s13jq05 {} Dependencies: NA `; exports[`strategy shaker should not eval non-linaria component from a linaria library 1`] = ` "import { styled } from "@linaria/react"; import { Title } from "./__fixtures__/linaria-ui-library/non-linaria-components"; const _exp = () => Title; export const StyledTitle = /*#__PURE__*/styled(_exp())({ name: "StyledTitle", class: "StyledTitle_s13jq05", propsAsIs: true });" `; exports[`strategy shaker should not eval non-linaria component from a linaria library 2`] = ` CSS: .StyledTitle_s13jq05 {} Dependencies: NA `; exports[`strategy shaker should not eval wrapped component from a non-linaria library 1`] = ` "import { styled } from "@linaria/react"; import { connect } from "./__fixtures__/linaria-ui-library/hocs"; import { Title } from "./__fixtures__/non-linaria-ui-library/index"; const _exp = () => connect(Title); export const StyledTitle = /*#__PURE__*/styled(_exp())({ name: "StyledTitle", class: "StyledTitle_s13jq05", propsAsIs: true });" `; exports[`strategy shaker should not eval wrapped component from a non-linaria library 2`] = ` CSS: .StyledTitle_s13jq05 {} Dependencies: NA `; exports[`strategy shaker should not import types 1`] = ` "import { styled } from "@linaria/react"; import { Title } from "./__fixtures__/linaria-ui-library/components/index"; import { ComponentType } from "./__fixtures__/linaria-ui-library/types"; const map = new Map<string, ComponentType>().set('Title', Title); const Gate = (props: { type: ComponentType; className: string; }) => { const { className, type } = props; const Component = map.get(type); return <Component className={className} />; }; const _exp = () => Gate; export const StyledTitle = /*#__PURE__*/styled(_exp())({ name: "StyledTitle", class: "StyledTitle_s18alru3", propsAsIs: true });" `; exports[`strategy shaker should not import types 2`] = ` CSS: .StyledTitle_s18alru3 {} Dependencies: NA `; exports[`strategy shaker should process \`css\` calls inside components 1`] = ` "import React from 'react'; export function Component() { const className = "className_c13jq05"; return React.createElement("div", { className }); }" `; exports[`strategy shaker should process \`css\` calls inside components 2`] = ` CSS: .className_c13jq05 { opacity: 0.2; } Dependencies: NA `; exports[`strategy shaker should process \`css\` calls referencing other \`css\` calls inside components 1`] = ` "import React from 'react'; export function Component() { const outer = "outer_o13jq05"; const inner = "inner_i1vhermz"; return React.createElement("div", { className: outer }, "outer", React.createElement("div", { className: inner }, "inner")); }" `; exports[`strategy shaker should process \`css\` calls referencing other \`css\` calls inside components 2`] = ` CSS: .outer_o13jq05 { color: red; } .inner_i1vhermz { color: green; .outer_o13jq05:hover & { color: blue; } } Dependencies: NA `; exports[`strategy shaker should process \`css\` calls with complex interpolation inside components 1`] = ` "import React from 'react'; export function Component() { const className = "className_c1vhermz"; return React.createElement("div", { className }); }" `; exports[`strategy shaker should process \`css\` calls with complex interpolation inside components 2`] = ` CSS: .cell_c13jq05 { opacity: 0; } .className_c1vhermz { opacity: 0.5; font-size: 42 font-size: 42 &:hover .cell_c13jq05 { opacity: 0.2; } } Dependencies: ./__fixtures__/sample-script `; exports[`strategy shaker should process \`styled\` calls inside components 1`] = ` "import React from 'react'; import { styled } from '@linaria/react'; export function Component() { const MyComponent = /*#__PURE__*/styled('h1')({ name: "MyComponent", class: "MyComponent_m13jq05", propsAsIs: false }); return React.createElement(MyComponent); }" `; exports[`strategy shaker should process \`styled\` calls inside components 2`] = ` CSS: .MyComponent_m13jq05 { opacity: 0.2; } Dependencies: NA `; exports[`strategy shaker should process \`styled\` calls with complex interpolation inside components 1`] = ` "import React from 'react'; import { styled } from '@linaria/react'; export function Component() { const MyComponent = /*#__PURE__*/styled('h1')({ name: "MyComponent", class: "MyComponent_m1egpet8", propsAsIs: false }); return React.createElement(MyComponent); }" `; exports[`strategy shaker should process \`styled\` calls with complex interpolation inside components 2`] = ` CSS: .Styled1_s13jq05 { opacity: 0.5 } .cell_c1vhermz { opacity: 0; } .MyComponent_m1egpet8 { opacity: 0.5; &:hover .cell_c1vhermz { opacity: 0.2; } .Styled1_s13jq05 { font-size: 1; } } Dependencies: NA `; exports[`strategy shaker should process circular imports 1`] = ` "import { styled } from '@linaria/react'; export const H1 = /*#__PURE__*/styled('h1')({ name: "H1", class: "H1_h13jq05", propsAsIs: false });" `; exports[`strategy shaker should process circular imports 2`] = ` CSS: .H1_h13jq05 { color: bar; } Dependencies: ./__fixtures__/circular-imports `; exports[`strategy shaker should process dynamic require 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker should process dynamic require 2`] = ` CSS: .square_s13jq05 { div:before { content: foo2; } } Dependencies: ./__fixtures__/foo `; exports[`strategy shaker should process module.exports = require(…) 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker should process module.exports = require(…) 2`] = ` CSS: .square_s13jq05 { div:before { content: foo; } } Dependencies: ./__fixtures__/module-reexport `; exports[`strategy shaker should process unary expressions in interpolation 1`] = ` "export const class1 = "class1_c13jq05"; export const class2 = "class2_c1vhermz";" `; exports[`strategy shaker should process unary expressions in interpolation 2`] = ` CSS: .class1_c13jq05 {width:1337px;} .class2_c1vhermz {width:1337px;} Dependencies: NA `; exports[`strategy shaker should shake out identifiers that are referenced only in types 1`] = ` "import { styled } from "@linaria/react"; import * as yup from "yup"; import { Form } from "./__fixtures__/linaria-ui-library/components/index"; const validationSchema = yup.object(); type IModel = yup.InferType<typeof validationSchema>; const Editor = () => { const initial: IModel = {}; return <Form schema={validationSchema} data={initial} />; }; const _exp = () => Editor; export const StyledEditor = /*#__PURE__*/styled(_exp())({ name: "StyledEditor", class: "StyledEditor_s18alru3", propsAsIs: true });" `; exports[`strategy shaker should shake out identifiers that are referenced only in types 2`] = ` CSS: .StyledEditor_s18alru3 {} Dependencies: NA `; exports[`strategy shaker should work with String and Number object 1`] = `"export const style = "style_s13jq05";"`; exports[`strategy shaker should work with String and Number object 2`] = ` CSS: .style_s13jq05 { width: 100%; opacity: 0.75; } Dependencies: NA `; exports[`strategy shaker should work with built-in modules 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker should work with built-in modules 2`] = ` CSS: .square_s13jq05 { background: url(https://example.com/); } Dependencies: NA `; exports[`strategy shaker should work with generated classnames as selectors 1`] = ` "export const text = "text_t13jq05"; export const square = "square_s1vhermz";" `; exports[`strategy shaker should work with generated classnames as selectors 2`] = ` CSS: .text_t13jq05 {} .square_s1vhermz { .text_t13jq05 { color: red; } } Dependencies: NA `; exports[`strategy shaker should work with short-circuit imports 1`] = `"export const StyledTitle = "StyledTitle_s13jq05";"`; exports[`strategy shaker should work with short-circuit imports 2`] = ` CSS: .StyledTitle_s13jq05 { content: "2a"; } Dependencies: ./__fixtures__/self-import `; exports[`strategy shaker should work with wildcard imports 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker should work with wildcard imports 2`] = ` CSS: .square_s13jq05 { .Title_t1us8k4s { color: #fff; } } Dependencies: ./__fixtures__/complex-component `; exports[`strategy shaker should work with wildcard reexports 1`] = `"export const square = "square_s13jq05";"`; exports[`strategy shaker should work with wildcard reexports 2`] = ` CSS: .square_s13jq05 { color: foo1; } Dependencies: ./__fixtures__/reexports `; exports[`strategy shaker should wrap memoized components 1`] = ` "import React from 'react'; import { styled } from '@linaria/react'; const MyComponent = React.memo(() => <div />); const _exp = () => MyComponent; export default /*#__PURE__*/styled(_exp())({ name: "source0", class: "source0_swgemqq", propsAsIs: true });" `; exports[`strategy shaker should wrap memoized components 2`] = ` CSS: .source0_swgemqq { color: red; } Dependencies: react `; exports[`strategy shaker simplifies react components 1`] = ` "import React from 'react'; import { styled } from '@linaria/react'; import constant from './broken-dependency'; const FuncComponent = props => <div>{props.children + constant}</div>; class ClassComponent extends React.PureComponent { method() { return constant; } render() { return <div>{props.children + constant}</div>; } } const ComplexFunctionComponent = props => { if (import.meta.env.PROD) { return <div>{props.children + constant}</div>; } return null; }; const _exp = () => FuncComponent; export const StyledFunc = /*#__PURE__*/styled(_exp())({ name: "StyledFunc", class: "StyledFunc_swgemqq", propsAsIs: true }); const _exp2 = () => ClassComponent; export const StyledClass = /*#__PURE__*/styled(_exp2())({ name: "StyledClass", class: "StyledClass_sjtmpns", propsAsIs: true });" `; exports[`strategy shaker simplifies react components 2`] = ` CSS: .StyledFunc_swgemqq { color: red; } .StyledClass_sjtmpns { color: blue; } Dependencies: NA `; exports[`strategy shaker simplifies transpiled react components 1`] = ` "import * as ReactNS from 'react'; import React from 'react'; import { createElement } from 'react'; import { styled } from '@linaria/react'; import constant from './broken-dependency'; const A = () => ReactNS.createElement('div', {}, constant); const B = () => createElement(A, {}, constant); const C = () => React.createElement(FuncComponent, {}, constant); const _exp = () => C; export const D = /*#__PURE__*/styled(_exp())({ name: "D", class: "D_dwgemqq", propsAsIs: true });" `; exports[`strategy shaker simplifies transpiled react components 2`] = ` CSS: .D_dwgemqq { color: red; } Dependencies: NA `; exports[`strategy shaker simplifies transpiled react components CJS 1`] = ` "var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; var React = _interopRequireWildcard(require("react")); var styled = require('@linaria/react').styled; var constant = require('./broken-dependency').default; const A = () => React.createElement('div', {}, constant); const B = () => React.createElement(A, {}, constant); const C = () => React.createElement(FuncComponent, {}, constant); const _exp = () => C; exports.D = /*#__PURE__*/styled(_exp())({ name: "source0", class: "source0_swgemqq", propsAsIs: true });" `; exports[`strategy shaker simplifies transpiled react components CJS 2`] = ` CSS: .source0_swgemqq { color: red; } Dependencies: NA `; exports[`strategy shaker supports both css and styled tags 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false }); export const title = "title_t1vhermz";" `; exports[`strategy shaker supports both css and styled tags 2`] = ` CSS: .Title_t13jq05 { font-size: 14px; } .title_t1vhermz { color: blue; } Dependencies: NA `; exports[`strategy shaker throws codeframe error when evaluation fails 1`] = ` "<<DIRNAME>>/source.js: An error occurred when evaluating the expression: > This will fail. Make sure you are not using a browser or Node specific API and all the variables are available in static context. Linaria have to extract pieces of your code to resolve the interpolated values. Defining styled component or class will not work inside: - function, - class, - method, - loop, because it cannot be statically determined in which context you use them. That's why some variables may be not defined during evaluation. 4 | 5 | export const Title = styled.h1\` > 6 | font-size: \${foo()}px; | ^^^^^ 7 | \`;" `; exports[`strategy shaker throws if couldn't determine a display name 1`] = ` "<<DIRNAME>>/.js: Couldn't determine a name for the component. Ensure that it's either: - Assigned to a variable - Is an object property - Is a prop in a JSX element 1 | import { styled } from '@linaria/react'; 2 | > 3 | export default styled.h1\` | ^^^^^^ 4 | font-size: 14px; 5 | \`;" `; exports[`strategy shaker throws when contains unsupported expression 1`] = ` "<<DIRNAME>>/source.js: css tag cannot handle '() => size' as an interpolated value 4 | 5 | const title = css\` > 6 | font-size: \${() => size}px; | ^^^^^^^^^^ 7 | \`;" `; exports[`strategy shaker throws when interpolation evaluates to NaN 1`] = ` "<<DIRNAME>>/source.js: The expression evaluated to 'NaN', which is probably a mistake. If you want it to be inserted into CSS, explicitly cast or transform the value to a string, e.g. - 'String(height)'. 4 | 5 | export const Title = styled.h1\` > 6 | height: \${height}px; | ^^^^^^ 7 | \`;" `; exports[`strategy shaker throws when interpolation evaluates to null 1`] = ` "<<DIRNAME>>/source.js: The expression evaluated to 'null', which is probably a mistake. If you want it to be inserted into CSS, explicitly cast or transform the value to a string, e.g. - 'String(color)'. 4 | 5 | export const Title = styled.h1\` > 6 | color: \${color}; | ^^^^^ 7 | \`;" `; exports[`strategy shaker throws when interpolation evaluates to undefined 1`] = ` "<<DIRNAME>>/source.js: The expression evaluated to 'undefined', which is probably a mistake. If you want it to be inserted into CSS, explicitly cast or transform the value to a string, e.g. - 'String(fontSize)'. 4 | 5 | export const Title = styled.h1\` > 6 | font-size: \${fontSize}; | ^^^^^^^^ 7 | \`;" `; exports[`strategy shaker transpiles css template literal 1`] = `"export const title = "title_t13jq05";"`; exports[`strategy shaker transpiles css template literal 2`] = ` CSS: .title_t13jq05 { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker transpiles renamed css and atomic-css imports in the same file 1`] = ` "/* @flow */ const x = "x_x13jq05"; const y = "atm_26_5scuol"; console.log(x, y);" `; exports[`strategy shaker transpiles renamed css and atomic-css imports in the same file 2`] = ` CSS: .x_x13jq05 { background: red; } .atm_26_5scuol{background:red;} Dependencies: NA `; exports[`strategy shaker transpiles renamed css from linaria v2 1`] = ` "const x = "x_x13jq05"; console.log(x);" `; exports[`strategy shaker transpiles renamed css from linaria v2 2`] = ` CSS: .x_x13jq05 { background: red; } Dependencies: NA `; exports[`strategy shaker transpiles renamed styled and atomic-styled imports in the same file 1`] = ` "/* @flow */ import { styled as reactStyled } from '@linaria/react'; import { styled as atomicStyled } from '@linaria/atomic'; const StyledComponent = /*#__PURE__*/reactStyled('div')({ name: "StyledComponent", class: "StyledComponent_s13jq05", propsAsIs: false }); const _exp = () => StyledComponent; const StyledComponent2 = /*#__PURE__*/reactStyled(_exp())({ name: "StyledComponent2", class: "StyledComponent2_s1vhermz", propsAsIs: true }); const AtomicComponent = /*#__PURE__*/atomicStyled('div')({ name: "AtomicComponent", class: "atm_26_5scuol AtomicComponent_a1egpet8", propsAsIs: false, atomic: true }); const _exp2 = () => AtomicComponent; const AtomicComponent2 = /*#__PURE__*/atomicStyled(_exp2())({ name: "AtomicComponent2", class: "atm_26_13q2bts AtomicComponent2_avc9xb3", propsAsIs: true, atomic: true }); console.log(StyledComponent, StyledComponent2, AtomicComponent, AtomicComponent2);" `; exports[`strategy shaker transpiles renamed styled and atomic-styled imports in the same file 2`] = ` CSS: .StyledComponent_s13jq05 { background: red; } .StyledComponent2_s1vhermz.StyledComponent_s13jq05 { background: blue; } .atm_26_5scuol{background:red;} .atm_26_13q2bts.atm_26_13q2bts{background:blue;} Dependencies: NA `; exports[`strategy shaker transpiles renamed styled import 1`] = ` "import { styled as custom } from '@linaria/react'; export const Title = /*#__PURE__*/custom('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker transpiles renamed styled import 2`] = ` CSS: .Title_t13jq05 { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker transpiles styled template literal with TS component 1`] = ` "import { styled } from '@linaria/react'; type Props = { className?: string; children?: React.ReactNode; }; export const Title = /*#__PURE__*/styled(() => {})({ name: "Title", class: "Title_t9vkbjs", propsAsIs: true });" `; exports[`strategy shaker transpiles styled template literal with TS component 2`] = ` CSS: .Title_t9vkbjs { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker transpiles styled template literal with function and component 1`] = ` "import { styled } from '@linaria/react'; const Heading = () => null; const _exp = () => Heading; export const Title = /*#__PURE__*/styled(_exp())({ name: "Title", class: "Title_t13jq05", propsAsIs: true });" `; exports[`strategy shaker transpiles styled template literal with function and component 2`] = ` CSS: .Title_t13jq05 { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker transpiles styled template literal with function and tag 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker transpiles styled template literal with function and tag 2`] = ` CSS: .Title_t13jq05 { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker transpiles styled template literal with object 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false });" `; exports[`strategy shaker transpiles styled template literal with object 2`] = ` CSS: .Title_t13jq05 { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker transpiles with typed fn as interpolated value 1`] = ` "import { styled } from '@linaria/react'; type Props = { className?: string; children?: React.ReactNode; }; const _exp = () => (props: Props) => props.className; export const Title = /*#__PURE__*/styled('div')({ name: "Title", class: "Title_t9vkbjs", propsAsIs: false, vars: { "t9vkbjs-0": [_exp()] } });" `; exports[`strategy shaker transpiles with typed fn as interpolated value 2`] = ` CSS: .Title_t9vkbjs { font-size: 14px; content: "var(--t9vkbjs-0)" } Dependencies: NA `; exports[`strategy shaker understands satisfies keyword 1`] = ` "interface ColorTokenMap { primary: string; secondary: string; } export const text = "text_t9vkbjs";" `; exports[`strategy shaker understands satisfies keyword 2`] = ` CSS: .text_t9vkbjs { color: #111; } Dependencies: NA `; exports[`strategy shaker uses string passed in classNameSlug 1`] = ` "import { styled } from '@linaria/react'; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "t13jq05_Title_src_source_js_source__js_src", propsAsIs: false });" `; exports[`strategy shaker uses string passed in classNameSlug 2`] = ` CSS: .t13jq05_Title_src_source_js_source__js_src { font-size: 14px; } Dependencies: NA `; exports[`strategy shaker uses string passed in variableNameSlug 1`] = ` "import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; const _exp = () => props => props.size; export const Title = /*#__PURE__*/styled('h1')({ name: "Title", class: "Title_t13jq05", propsAsIs: false, vars: { "Title_t13jq05_StyledProcessor_1qqvhyq_0": [_exp(), "px"] } }); const _exp2 = () => props => props.size; export const Body = /*#__PURE__*/atomicStyled('h1')({ name: "Body", class: "atm_c8_1cjuufw Body_b1vhermz", propsAsIs: false, vars: { "Body_b1vhermz_AtomicStyledProcessor_1qqvhyq_0": [_exp2(), "px"] }, atomic: true });" `; exports[`strategy shaker uses string passed in variableNameSlug 2`] = ` CSS: .Title_t13jq05 { font-size: var(--Title_t13jq05_StyledProcessor_1qqvhyq_0); } .atm_c8_1cjuufw.atm_c8_1cjuufw{font-size:var(--Body_b1vhermz_AtomicStyledProcessor_1qqvhyq_0);} Dependencies: NA `; exports[`strategy shaker uses the same custom property for the same expression 1`] = ` "import { styled } from '@linaria/react'; const _exp2 = () => props => props.size; export const Box = /*#__PURE__*/styled('div')({ name: "Box", class: "Box_b13jq05", propsAsIs: false, vars: { "b13jq05-0": [_exp2(), "px"] } });" `; exports[`strategy shaker uses the same custom property for the same expression 2`] = ` CSS: .Box_b13jq05 { height: var(--b13jq05-0); width: var(--b13jq05-0); } Dependencies: NA `; exports[`strategy shaker uses the same custom property for the same identifier 1`] = ` "import { styled } from '@linaria/react'; const size = () => 100; const _exp2 = () => size; export const Box = /*#__PURE__*/styled('div')({ name: "Box", class: "Box_b13jq05", propsAsIs: false, vars: { "b13jq05-0": [_exp2(), "px"] } });" `; exports[`strategy shaker uses the same custom property for the same identifier 2`] = ` CSS: .Box_b13jq05 { height: var(--b13jq05-0); width: var(--b13jq05-0); } Dependencies: NA `; exports[`strategy shaker uses values from json 1`] = `"export const eyeColorClass = "eyeColorClass_e13jq05";"`; exports[`strategy shaker uses values from json 2`] = ` CSS: .eyeColorClass_e13jq05 { color: blue; } Dependencies: ./__fixtures__/sample-data.json `; ================================================ FILE: packages/testkit/src/__snapshots__/transform.test.ts.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`doesn't rewrite an absolute path in url() declarations 1`] = ` ".tpyglzj{background-image:url(/assets/test.jpg);} " `; exports[`rewrites a relative path in url() declarations 1`] = ` ".tpyglzj{background-image:url(../assets/test.jpg);background-image:url("../assets/test.jpg");background-image:url('../assets/test.jpg');} " `; exports[`rewrites multiple relative paths in url() declarations 1`] = ` "@font-face{font-family:Test;src:url(../assets/font.woff2) format("woff2"),url(../assets/font.woff) format("woff");} " `; ================================================ FILE: packages/testkit/src/__utils__/linaria-snapshot-serializer.ts ================================================ import type { WYWTransformMetadata } from '@wyw-in-js/transform'; import { withTransformMetadata } from '@wyw-in-js/transform'; type Serializer<T> = { serialize: (value: T) => string; test: (value: unknown) => value is T; }; export default { test: withTransformMetadata, serialize: ({ wywInJS }) => ` CSS: ${Object.keys(wywInJS.rules ?? {}) .map((selector) => wywInJS.rules[selector].atom ? wywInJS.rules[selector].cssText : `${selector} {${wywInJS.rules[selector].cssText}}` ) .join('\n')} Dependencies: ${ wywInJS.dependencies?.length ? wywInJS.dependencies.join(', ') : 'NA' } `, } as Serializer<{ wywInJS: WYWTransformMetadata & { rules?: any } }>; ================================================ FILE: packages/testkit/src/babel.test.ts ================================================ /* eslint-disable no-restricted-syntax */ import { readFileSync } from 'fs'; import { stripVTControlCharacters as stripAnsi } from 'node:util'; import { dirname, join, resolve, sep } from 'path'; import * as babel from '@babel/core'; import type { PluginItem } from '@babel/core'; import { logger } from '@wyw-in-js/shared'; import type { Evaluator, FeatureFlags } from '@wyw-in-js/shared'; import { Entrypoint, EventEmitter, TransformCacheCollection, loadWywOptions, shaker, transform as wywTransform, } from '@wyw-in-js/transform'; import type { EntrypointEvent, OnEvent, OnActionStartArgs, OnActionFinishArgs, PluginOptions, Stage, } from '@wyw-in-js/transform'; import dedent from 'dedent'; import serializer from './__utils__/linaria-snapshot-serializer'; expect.addSnapshotSerializer(serializer); const dirName = __dirname; type PartialOptions = Partial<Omit<PluginOptions, 'features'>> & { features?: Partial<FeatureFlags>; }; type Options = [ evaluator: Evaluator, linariaConfig?: PartialOptions, extension?: 'js' | 'ts' | 'jsx' | 'tsx', filename?: string, babelConfig?: babel.TransformOptions, ]; const asyncResolve = (what: string, importer: string, stack: string[]) => { const where = [importer, ...stack].map((p) => dirname(p)); try { return Promise.resolve(require.resolve(what, { paths: where })); } catch { return Promise.reject(); } }; const getPresets = (extension: 'js' | 'ts' | 'jsx' | 'tsx') => { const presets: PluginItem[] = []; if (extension === 'ts' || extension === 'tsx') { presets.push(require.resolve('@babel/preset-typescript')); } if (extension === 'jsx' || extension === 'tsx') { presets.push(require.resolve('@babel/preset-react')); } return presets; }; const getLinariaConfig = ( evaluator: Evaluator, linariaConfig: PartialOptions, presets: PluginItem[], stage?: Stage ): PluginOptions => { const { features: customFeatures, ...restConfig } = linariaConfig; return loadWywOptions({ babelOptions: { presets, plugins: [], }, extensions: [ '.cjs', '.cts', '.js', '.jsx', '.mjs', '.mts', '.ts', '.tsx', '.json', ], displayName: true, rules: [ { action: evaluator, babelOptions: { plugins: [ require.resolve('@babel/plugin-transform-modules-commonjs'), ], }, }, { test: /[\\/]node_modules[\\/](?!@linaria)/, action: 'ignore', }, { test: /\.json$/, action: 'ignore', }, ], features: { ...customFeatures, happyDOM: false, softErrors: false, }, stage, ...restConfig, }); }; async function transform( originalCode: string, opts: Options, cache?: TransformCacheCollection, eventEmitter?: EventEmitter, filename = 'source' ) { const [ evaluator, linariaPartialConfig = {}, extension = 'js', fullFilename = join(dirName, `${filename}.${extension}`), babelPartialConfig = {}, ] = opts; const presets = getPresets(extension); const linariaConfig = getLinariaConfig( evaluator, linariaPartialConfig, presets, 'collect' ); const services = { babel, cache, options: { filename: babelPartialConfig.filename ?? fullFilename, root: babelPartialConfig.root ?? undefined, inputSourceMap: babelPartialConfig.inputSourceMap ?? undefined, pluginOptions: linariaConfig, }, eventEmitter, }; const result = await wywTransform(services, originalCode, asyncResolve); return { cssText: result.cssText, code: result.code, metadata: { wywInJS: { rules: result.rules, dependencies: result.dependencies, cssText: result.cssText, }, }, }; } async function transformFile(filename: string, opts: Options) { const [evaluator, linariaPartialConfig = {}, extension = 'js'] = opts; const code = readFileSync(filename, 'utf8'); return transform(code, [ evaluator, linariaPartialConfig, extension, filename, ]); } describe('strategy shaker', () => { const evaluator = shaker; let onEvent: jest.Mock<void, Parameters<OnEvent>>; let onAction: jest.Mock<number, OnActionStartArgs | OnActionFinishArgs>; let onEntrypointEvent: jest.Mock< void, [idx: number, timestamp: number, event: EntrypointEvent] >; let emitter: EventEmitter; function hasNotBeenProcessed(filename: string) { expect(onEntrypointEvent).toHaveBeenCalledWith( expect.any(Number), expect.any(Number), expect.objectContaining({ filename, type: 'created', }) ); const entrypointId = onEntrypointEvent.mock.calls.find( (call) => call[2].type === 'created' && call[2].filename === filename )![0]; expect(onEntrypointEvent).not.toHaveBeenCalledWith( entrypointId, expect.any(Number), expect.objectContaining({ type: 'actionCreated', actionType: 'explodeReexports', }) ); } beforeEach(() => { onEvent = jest.fn(); onAction = jest.fn(); onEntrypointEvent = jest.fn(); emitter = new EventEmitter(onEvent, onAction, onEntrypointEvent); }); it('transpiles styled template literal with object', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const Title = styled.h1\` font-size: 14px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should apply stylis', async () => { const { cssText, code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const Title = styled.h1\` && > span { display:flex; } \`; `, [evaluator] ); expect(cssText).toMatchSnapshot(); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('uses string passed in classNameSlug', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const Title = styled('h1')\` font-size: 14px; \`; `, [ evaluator, { classNameSlug: ['hash', 'title', 'file', 'name', 'ext', 'dir'] .map((s) => `[${s}]`) .join('_'), }, ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('uses string passed in variableNameSlug', async () => { const { code, metadata } = await transform( dedent` import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; export const Title = styled('h1')\` font-size: ${'${props => props.size}px'}; \`; export const Body = atomicStyled('h1')\` font-size: ${'${props => props.size}px'}; \`; `, [ evaluator, { variableNameSlug: [ 'componentName', 'componentSlug', 'processor', 'valueSlug', 'index', ] .map((s) => `[${s}]`) .join('_'), }, ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('removes fake replacement patterns in string classNameSlug', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const Title = styled('h1')\` font-size: 14px; \`; `, [ evaluator, { classNameSlug: '[not]_[actual]_[replacements]', }, ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles fn passed in classNameSlug', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const Title = styled('h1')\` font-size: 14px; \`; `, [ evaluator, { classNameSlug: (hash, title, vars) => [ hash, title, vars.hash, vars.title, vars.file, vars.name, vars.ext, vars.dir, ].join('_'), }, ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles fn passed in variableNameSlug', async () => { const { code, metadata } = await transform( dedent` import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; export const Title = styled('h1')\` font-size: ${'${props => props.size}px'}; \`; export const Body = atomicStyled('h1')\` font-size: ${'${props => props.size}px'}; \`; `, [ evaluator, { variableNameSlug: (context) => `${context.valueSlug}__${context.componentName}__${ context.precedingCss.match(/([\w-]+)\s*:\s*$/)?.[1] ?? 'unknown' }`, }, ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles val in variableNameConfig', async () => { const { code, metadata } = await transform( dedent` import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; export const Title = styled('h1')\` font-size: ${'${props => props.size}px'}; \`; export const Body = atomicStyled('h1')\` font-size: ${'${props => props.size}px'}; \`; `, [ evaluator, { variableNameConfig: 'var', }, ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles dashes in variableNameConfig', async () => { const { code, metadata } = await transform( dedent` import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; export const Title = styled('h1')\` font-size: ${'${props => props.size}px'}; \`; export const Body = atomicStyled('h1')\` font-size: ${'${props => props.size}px'}; \`; `, [ evaluator, { variableNameConfig: 'dashes', }, ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles raw in variableNameConfig', async () => { const { code, metadata } = await transform( dedent` import { styled as atomicStyled } from '@linaria/atomic'; import { styled } from '@linaria/react'; export const Title = styled('h1')\` font-size: ${'${props => props.size}px'}; \`; export const Body = atomicStyled('h1')\` font-size: ${'${props => props.size}px'}; \`; `, [ evaluator, { variableNameConfig: 'raw', }, ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('transpiles styled template literal with function and tag', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const Title = styled('h1')\` font-size: 14px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('transpiles renamed styled import', async () => { const { code, metadata } = await transform( dedent` import { styled as custom } from '@linaria/react'; export const Title = custom('h1')\` font-size: 14px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('transpiles renamed css and atomic-css imports in the same file', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { css as coreCss } from '@linaria/core'; import { css as atomicCss } from '@linaria/atomic'; const x = coreCss\` background: red; \`; const y = atomicCss\` background: red; \`; console.log(x, y); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('transpiles renamed styled and atomic-styled imports in the same file', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { styled as reactStyled } from '@linaria/react'; import { styled as atomicStyled } from '@linaria/atomic'; const StyledComponent = reactStyled.div\` background: red; \`; const StyledComponent2 = reactStyled(StyledComponent)\` background: blue; \`; const AtomicComponent = atomicStyled.div\` background: red; \`; const AtomicComponent2 = atomicStyled(AtomicComponent)\` background: blue; \`; console.log(StyledComponent, StyledComponent2, AtomicComponent, AtomicComponent2); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('transpiles renamed css from linaria v2', async () => { const { code, metadata } = await transform( dedent` import {css as coreCss} from 'linaria'; const x = coreCss\` background: red; \`; console.log(x); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('transpiles styled template literal with function and component', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const Heading = () => null; export const Title = styled(Heading)\` font-size: 14px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('transpiles styled template literal with TS component', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; type Props = { className?: string; children?: React.ReactNode }; export const Title = styled((props: Props) => null)\` font-size: 14px; \`; `, [ evaluator, { evaluate: false, }, 'ts', ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('transpiles with typed fn as interpolated value', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; type Props = { className?: string; children?: React.ReactNode }; export const Title = styled.div\` font-size: 14px; content: "${'${(props: Props) => props.className}'}" \`; `, [ evaluator, { evaluate: false, }, 'ts', ] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('outputs valid CSS classname', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const ΩPage$Title = styled.h1\` font-size: 14px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates nested nested object interpolation', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; const defaultStyle = css\` color: red; padding-bottom: ${'${0}'}px; \`; const obj = { [\`&.${'${defaultStyle}'} .green\`]: { display: "inline-block", border: "1px solid green", }, }; export const greenContentStyles = css\` ${'${obj}'} \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('keeps cx import and removes css', async () => { const { code, metadata } = await transform( dedent` import { css, cx } from '@linaria/core'; const defaultStyle = css\` color: red; \`; export const combined = cx(defaultStyle, Math.random() > 0.5 ? 'green' : 'red'); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates and inlines expressions in scope', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const color = 'blue'; export const Title = styled.h1\` color: ${'${color}'}; width: ${'${100 / 3}'}%; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('inlines object styles as CSS string', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const cover = { '--color-primaryText': '#222', position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, opacity: 1, minHeight: 420, '&.shouldNotBeChanged': { borderColor: '#fff', }, '@media (min-width: 200px)': { WebkitOpacity: .8, MozOpacity: .8, msOpacity: .8, OOpacity: .8, WebkitBorderRadius: 2, MozBorderRadius: 2, msBorderRadius: 2, OBorderRadius: 2, WebkitTransition: '400ms', MozTransition: '400ms', OTransition: '400ms', msTransition: '400ms', } }; export const Title = styled.h1\` ${'${cover}'} \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('inlines array styles as CSS string', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const styles = [ { flex: 1 }, { display: 'block', height: 24 }, ]; export const Title = styled.h1\` ${'${styles}'} \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles interpolation followed by unit', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const padding = 10; const size = () => 100; const shadow = () => 5; const unit = () => 1; export const Title = styled.h1\` font-size: ${'${size}'}em; text-shadow: black 1px ${'${shadow}'}px, white -2px -2px; margin: ${'${size}'}px; width: calc(2 * ${'${props => props.width}'}vw); height: ${'${props => { if (true) { return props.height } else { return 200 } }}'}px; grid-template-columns: ${'${unit}'}fr 1fr 1fr ${'${unit}'}fr; border-radius: ${'${function(props) { return 200 }}'}px; padding: ${'${padding}'}px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles interpolation in css function followed by unit', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/atomic'; const size = 200; export const Container = styled.div\` transform: rotate(${'${props => props.$rotateDeg}'}deg); width: ${'${size}'}px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('uses the same custom property for the same identifier', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const size = () => 100; export const Box = styled.div\` height: ${'${size}'}px; width: ${'${size}'}px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('uses the same custom property for the same expression', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const Box = styled.div\` height: ${'${props => props.size}'}px; width: ${'${props => props.size}'}px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('do not include in dependencies expressions from interpolation functions bodies', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; import constant from './broken-dependency-1'; import modifier from './broken-dependency-2'; export const Box = styled.div\` height: ${'${props => props.size + constant}'}px; width: ${'${props => modifier(props.size)}'}px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles nested blocks', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const regular = () => "arial"; export const Button = styled.button\` font-family: ${'${regular}'}; &:hover { border-color: blue; } @media (max-width: 200px) { width: 100%; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('prevents class name collision', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const size = () => 100; const regular = () => "arial"; export const Title = styled.h1\` font-size: ${'${size}'}px; color: ${'${props => props.color}'} \`; export function Something() { const Title = styled.h1\` font-family: ${'${regular}'}; \`; return <Title />; } `, [evaluator, {}, 'jsx'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('does not output CSS if none present', async () => { const { code, metadata } = await transform( dedent` const number = 42; const title = String.raw\`This is something\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('does not output CSS property when value is a blank string', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; export const title = css\` font-size: ${''}; margin: 6px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('transpiles css template literal', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; export const title = css\` font-size: 14px; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles css template literal in object property', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; const components = { title: css\` font-size: 14px; \` }; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles css template literal in JSX element', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; <Title class={css\` font-size: 14px; \`} /> `, [evaluator, {}, 'jsx'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('throws when contains unsupported expression', async () => { expect.assertions(1); try { await transform( dedent` import { css } from '@linaria/core'; const size = 100; const title = css\` font-size: ${'${() => size}'}px; \`; `, [evaluator] ); } catch (e) { expect( stripAnsi( (e as { message: string }).message.replace( dirName + sep, '<<DIRNAME>>/' ) ) ).toMatchSnapshot(); } }); it('supports both css and styled tags', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; import { styled } from '@linaria/react'; export const Title = styled.h1\` font-size: 14px; \`; export const title = css\` color: blue; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('does not include styles if not referenced anywhere', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; import { styled } from '@linaria/react'; const Title = styled.h1\` font-size: 14px; \`; const title = css\` color: blue; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('includes unreferenced styles for :global', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; import { styled } from '@linaria/react'; const a = css\` :global() { .title { font-size: 14px; } } \`; const B = styled.div\` :global(.title) { font-size: 14px; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles objects with numeric keys', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; export const object = { stringKey: css\`\`, 42: css\`\`, } `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles objects with enums as keys', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; import { TestEnum } from './__fixtures__/ts-data.ts'; export const object = { [TestEnum.FirstValue]: css\`\`, [TestEnum.SecondValue]: css\`\`, } `, [evaluator, {}, 'ts'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic css', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { css } from '@linaria/atomic'; const x = css\` background: red; height: 100px; \`; console.log(x); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic css with property priorities', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { css } from '@linaria/atomic'; const y = css\` margin-left: 5px; \`; const x = css\` margin: 0; \`; console.log(x, y); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic css with at-rules and pseudo classes', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { css } from '@linaria/atomic'; const x = css\` @media (max-width: 500px) { background: blue; } @media (min-width: 300px) { &:hover { background: purple; } } &:enabled { width: 100%; } background: red; height: 100px; \`; console.log(x); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic css with at-rules and property priorities', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { css } from '@linaria/atomic'; const x = css\` @media (max-width: 500px) { padding: 0; } @media (min-width: 300px) { &:hover { padding-top: 5px; } } &:enabled { padding-left: 6px; } padding-bottom: 7px; \`; console.log(x); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles css with keyframes', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; const x = css\` @keyframes fade { from { opacity: 0; } to { opacity: 1; } } animation: fade 1s infinite; background: red; height: 100px; \`; console.log(x); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic css with keyframes', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { css } from '@linaria/atomic'; const x = css\` @keyframes fade { from { opacity: 0; } to { opacity: 1; } } animation: fade 1s infinite; background: red; height: 100px; \`; console.log(x); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic styled with static css', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { styled } from '@linaria/atomic'; const Component = styled.div\` color: blue; height: 100px; \`; console.log(Component); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic css with unique atoms based on key value pairs', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { css } from '@linaria/atomic'; const x = css\` height: 100px; \`; const y = css\` height: 99px \`; console.log(x, y); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic styled with plain css, static and dynamic interpolations', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { styled } from '@linaria/atomic'; const Component = styled.div\` color: blue; height: 100px; margin: ${'${100 / 2}'}px; background-color: ${'${props => props.color}'}; \`; console.log(Component); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atoms that are shared between css and styled templates', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { css } from '@linaria/atomic'; import { styled } from '@linaria/atomic'; const x = css\` background: red; height: 100px; \` const Component = styled.div\` background: red; height: ${'${200 / 2}'}px; margin: 10px; color: ${'${props => props.color}'}; \`; console.log(x, Component); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic styled wrapping other components with extra priority', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { styled } from '@linaria/atomic'; const Component = styled.div\` background-color: blue; height: 100px; \`; const ComponentCompositing = styled(Component)\` background: red; height: 105px; \`; console.log(ComponentCompositing); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic styled without colliding by property', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { styled } from '@linaria/atomic'; export const Component = styled.ul\` display: flex; padding: 0; \`; export const Component2 = styled.ul\` display: block; padding: 0; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('compiles atomic styled with dynamic interpolations as unique variables based on the interpolation text', async () => { const { code, metadata } = await transform( dedent` /* @flow */ import { styled } from '@linaria/atomic'; const Component = styled.div\` color: ${'${props => props.color}'}; border-color: ${'${props => props.color}'}; background-color: ${'${props => props.backgroundColor}'}; \`; const Component2 = styled.div\` color: ${'${props => props.color}'}; border-color: ${'${props => props.color || "black"}'}; \`; console.log(Component, Component2); `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates identifier in scope', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const answer = 42; const foo = () => answer; const days = foo() + ' days'; export const Title = styled.h1\` &:before { content: "${'${days}'}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('hoistable identifiers', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; { var days = 42; } export const Title = styled.h1\` &:before { content: "${'${days}'}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('non-hoistable identifiers', async () => { expect.assertions(1); try { await transform( dedent` import { styled } from '@linaria/react'; { const days = 42; } export const Title = styled.h1\` &:before { content: "${'${days}'}" } \`; `, [evaluator] ); } catch (e) { expect( stripAnsi( (e as { message: string }).message.replace( dirName + sep, '<<DIRNAME>>/' ) ) ).toMatchSnapshot(); } }); it('evaluates imported typescript enums', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; import { Colors } from './__fixtures__/enums'; export const Title = styled.h1\` color: ${'${Colors.BLUE}'}; \`; `, [evaluator, {}, 'ts'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates local expressions', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const answer = 42; const foo = () => answer; export const Title = styled.h1\` &:before { content: "${"${foo() + ' days'}"}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates functions with nested identifiers', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const objects = { key: { fontSize: 12 } }; const foo = (k) => { const obj = objects[k]; return obj; }; export const Title = styled.h1\` ${"${foo('key')}"} \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates expressions with dependencies', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; import slugify from './__fixtures__/slugify'; export const Title = styled.h1\` &:before { content: "${"${slugify('test')}"}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates expressions with expressions depending on shared dependency', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const slugify = require('./__fixtures__/slugify').default; const boo = t => slugify(t) + 'boo'; const bar = t => slugify(t) + 'bar'; export const Title = styled.h1\` &:before { content: "${"${boo('test') + bar('test')}"}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates multiple expressions with shared dependency', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const slugify = require('./__fixtures__/slugify').default; const boo = t => slugify(t) + 'boo'; const bar = t => slugify(t) + 'bar'; export const Title = styled.h1\` &:before { content: "${"${boo('test')}"}" content: "${"${bar('test')}"}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates interpolations with sequence expression', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; let external = 0; export const Title = styled.h1\` color: ${'${(external, () => "blue")}'}; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates dependencies with sequence expression', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; let external = 0; const color = (external, () => 'blue'); export const Title = styled.h1\` color: ${'${color}'}; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates component interpolations', async () => { const { code, metadata } = await transform( dedent` const { styled } = require('@linaria/react'); export const Title = styled.h1\` color: red; \`; export const Paragraph = styled.p\` ${'${Title}'} { color: blue; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('throws when interpolation evaluates to undefined', async () => { expect.assertions(1); try { await transform( dedent` const { styled } = require('@linaria/react'); let fontSize; export const Title = styled.h1\` font-size: ${'${fontSize}'}; \`; `, [evaluator] ); } catch (e) { expect( stripAnsi( (e as { message: string }).message.replace( dirName + sep, '<<DIRNAME>>/' ) ) ).toMatchSnapshot(); } }); it('throws when interpolation evaluates to null', async () => { expect.assertions(1); try { await transform( dedent` const { styled } = require('@linaria/react'); const color = null; export const Title = styled.h1\` color: ${'${color}'}; \`; `, [evaluator] ); } catch (e) { expect( stripAnsi( (e as { message: string }).message.replace( dirName + sep, '<<DIRNAME>>/' ) ) ).toMatchSnapshot(); } }); it('throws when interpolation evaluates to NaN', async () => { expect.assertions(1); try { await transform( dedent` const { styled } = require('@linaria/react'); const height = NaN; export const Title = styled.h1\` height: ${'${height}'}px; \`; `, [evaluator] ); } catch (e) { expect( stripAnsi( (e as { message: string }).message.replace( dirName + sep, '<<DIRNAME>>/' ) ) ).toMatchSnapshot(); } }); it('handles wrapping another styled component', async () => { const { code, metadata } = await transform( dedent` const { styled } = require('@linaria/react'); const Title = styled.h1\` color: red; \`; export const BlueTitle = styled(Title)\` font-size: 24px; color: blue; \`; export const GreenTitle = styled(BlueTitle)\` color: green; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles indirect wrapping another styled component', async () => { const { code, metadata } = await transform( dedent` const { styled } = require('@linaria/react'); const Title = styled.h1\` color: red; \`; const hoc = Cmp => Cmp; export const CustomTitle = styled(hoc(Title))\` font-size: 24px; color: blue; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('inlines object styles as CSS string', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const fill = (top = 0, left = 0, right = 0, bottom = 0) => ({ position: 'absolute', top, right, bottom, left, }); export const Title = styled.h1\` ${'${fill(0, 0)}'} \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('inlines array styles as CSS string', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const fill = (top = 0, left = 0, right = 0, bottom = 0) => [ { position: 'absolute' }, { top, right, bottom, left, } ]; export const Title = styled.h1\` ${'${fill(0, 0)}'} \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('ignores inline arrow function expressions', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const Title = styled.h1\` &:before { content: "${'${props => props.content}'}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('simplifies react components', async () => { const div = '<div>{props.children + constant}</div>'; const { code, metadata } = await transform( dedent` import React from 'react'; import { styled } from '@linaria/react'; import constant from './broken-dependency'; const FuncComponent = (props) => ${div}; class ClassComponent extends React.PureComponent { method() { return constant; } render() { return ${div}; } } const ComplexFunctionComponent = (props) => { if (import.meta.env.PROD) { return ${div}; } return null; } export const StyledFunc = styled(FuncComponent)\` color: red; \`; export const StyledClass = styled(ClassComponent)\` color: blue; \`; `, [evaluator, {}, 'jsx'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('simplifies transpiled react components', async () => { const { code, metadata } = await transform( dedent` import * as ReactNS from 'react'; import React from 'react'; import { createElement } from 'react'; import { styled } from '@linaria/react'; import constant from './broken-dependency'; const A = () => ReactNS.createElement('div', {}, constant); const B = () => createElement(A, {}, constant); const C = () => React.createElement(FuncComponent, {}, constant); export const D = styled(C)\` color: red; \`; `, [evaluator, {}, 'jsx'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('simplifies transpiled react components CJS', async () => { const { code, metadata } = await transform( dedent` var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; var React = _interopRequireWildcard(require("react")); var styled = require('@linaria/react').styled; var constant = require('./broken-dependency').default; const A = () => React.createElement('div', {}, constant); const B = () => React.createElement(A, {}, constant); const C = () => React.createElement(FuncComponent, {}, constant); exports.D = styled(C)\` color: red; \`; `, [evaluator, {}, 'jsx'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('ignores inline vanilla function expressions', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export const Title = styled.h1\` &:before { content: "${'${function(props) { return props.content }}'}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('ignores external expressions', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; const generate = props => props.content; export const Title = styled.h1\` &:before { content: "${'${generate}'}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('throws codeframe error when evaluation fails', async () => { expect.assertions(1); try { await transform( dedent` import { styled } from '@linaria/react'; const foo = props => { throw new Error('This will fail') }; export const Title = styled.h1\` font-size: ${'${foo()}'}px; \`; `, [evaluator] ); } catch (e) { expect( stripAnsi( (e as { message: string }).message.replace( dirName + sep, '<<DIRNAME>>/' ) ) ).toMatchSnapshot(); } }); it('generates stable class names', async () => { const { code, metadata } = await transformFile( resolve(__dirname, './__fixtures__/components-library.js'), [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('derives display name from filename', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export default styled.h1\` font-size: 14px; \`; `, [evaluator, {}, 'js', join(dirName, 'FancyName.js')] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('derives display name from parent folder name', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; export default styled.h1\` font-size: 14px; \`; `, [evaluator, {}, 'js', join(dirName, 'FancyName/index.js')] )!; expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it("throws if couldn't determine a display name", async () => { expect.assertions(1); try { await transform( dedent` import { styled } from '@linaria/react'; export default styled.h1\` font-size: 14px; \`; `, [ evaluator, { extensions: [''], }, 'js', join(dirName, '/.js'), ] ); } catch (e) { expect( stripAnsi( (e as { message: string }).message.replace( dirName + sep, '<<DIRNAME>>/' ) ) ).toMatchSnapshot(); } }); it('does not strip istanbul coverage sequences', async () => { const cwd = process.platform === 'win32' ? 'C:\\Users\\project' : '/home/user/project'; const withIstanbul = await babel.transformAsync( dedent` import { css } from './custom-css-tag'; const a = 42; export const titleClass = css\` height: ${'${a}'}px; \`; `, { cwd, filename: 'file.js', plugins: [ [ // eslint-disable-next-line import/no-extraneous-dependencies require('babel-plugin-istanbul').default({ ...babel, assertVersion: () => {}, }), { cwd }, ], ], } ); if (!withIstanbul?.code) { return; } const { code, metadata } = await transform(withIstanbul.code, [ evaluator, { tagResolver: (source, tag) => { if (source === './custom-css-tag' && tag === 'css') { return require.resolve('@linaria/core/processors/css'); } return null; }, }, ]); // The output is different on Windows & POSIX-like system const normalizedCode = code .replace(/(cov_)\w+([\s(])/g, `$1__HASH__$2`) .replace(/(hash\s?[:=]\s")\w+(")/g, `$1__HASH__$2`) .replace(/(path\s?[:=]\s")[\w:\\/.]+(")/g, `$1__PATH__$2`); expect(normalizedCode).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); // PR #524 it('should work with String and Number object', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; export const style = css\` width: ${'${new String("100%")}'}; opacity: ${'${new Number(0.75)}'}; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should work with generated classnames as selectors', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; export const text = css\`\`; export const square = css\` .${'${text}'} { color: red; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should process `css` calls inside components', async () => { const { code, metadata } = await transform( dedent` import React from 'react' import {css} from '@linaria/core' export function Component() { const opacity = 0.2; const className = css\` opacity: ${'${opacity}'}; \`; return React.createElement("div", { className }); } `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should process `styled` calls inside components', async () => { const { code, metadata } = await transform( dedent` import React from 'react' import { styled } from '@linaria/react' export function Component() { const opacity = 0.2; const MyComponent = styled.h1\` opacity: ${'${opacity}'}; \`; return React.createElement(MyComponent); } `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should process `css` calls with complex interpolation inside components', async () => { const { code, metadata } = await transform( dedent` import React from 'react' import {css} from '@linaria/core' import externalDep from './__fixtures__/sample-script'; const globalObj = { opacity: 0.5, }; export function Component() { const classes = { value: 0.2, cell: css\` opacity: 0; \`, }; const classes2 = classes; const referencedExternalDep = externalDep const className = css\` opacity: ${'${globalObj.opacity}'}; font-size: ${'${externalDep}'} font-size: ${'${referencedExternalDep}'} &:hover .${'${classes2.cell}'} { opacity: ${'${classes.value}'}; } \`; return React.createElement("div", { className }); } `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should process `css` calls referencing other `css` calls inside components', async () => { const { code, metadata } = await transform( dedent` import React from 'react' import {css} from '@linaria/core' export function Component() { const outer = css\` color: red; \`; const inner = css\` color: green; .${'${outer}'}:hover & { color: blue; } \`; return React.createElement("div", { className: outer }, "outer", React.createElement("div", { className: inner }, "inner" ) ); } `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should process `styled` calls with complex interpolation inside components', async () => { const { code, metadata } = await transform( dedent` import React from 'react' import {css} from '@linaria/core' import {styled} from '@linaria/react' const globalObj = { opacity: 0.5, }; const Styled1 = styled.p\` opacity: ${'${globalObj.opacity}'} \` export function Component() { const classes = { value: 0.2, cell: css\` opacity: 0; \`, }; const classes2 = classes; const MyComponent = styled.h1\` opacity: ${'${globalObj.opacity}'}; &:hover .${'${classes2.cell}'} { opacity: ${'${classes.value}'}; } ${'${Styled1}'} { font-size: 1; } \`; return React.createElement(MyComponent); } `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should handle shadowed identifier inside components', async () => { const { code, metadata } = await transform( dedent` import React from 'react' import {css} from '@linaria/core' const color = 'red'; export default function Component() { const color = 'blue' const val = { color }; return React.createElement('div', {className: css\`background-color:${'${val.color}'};\`}); } `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('it should not throw location error for hoisted identifier', async () => { const { code, metadata } = await transform( dedent` import React from 'react' import {css} from '@linaria/core' const size = () => 5 export default function Component() { const color = size() return css\`opacity:${'${color}'};\` } `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should wrap memoized components', async () => { const { code, metadata } = await transform( dedent` import React from 'react'; import { styled } from '@linaria/react'; const MyComponent = React.memo(() => <div />); export default styled(MyComponent)\` color: red; \` `, [evaluator, {}, 'jsx'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles escapes properly', async () => { const { code, metadata } = await transformFile( resolve(__dirname, './__fixtures__/escape-character.js'), [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates babel helpers', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; function copyAndExtend(a, b) { return { ...a, ...b }; } const obj = copyAndExtend({ a: 1 }, { a: 2 }); export const Title = styled.h1\` &:before { content: "${'${obj.a}'}" } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('uses values from json', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; import sample from './__fixtures__/sample-data.json'; export const eyeColorClass = css\` color: ${'${sample.eye_color}'}; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates complex styles with functions and nested selectors', async () => { const { code, metadata } = await transform( dedent` import { css } from '@linaria/core'; export const bareIconClass = css\`\`; const getSizeStyles = (fs) => ({ [\`${'&.${bareIconClass}'}\`]: { fontSize: fs * 1.5, }, }); export const SIZES = { XS: css\`${'${getSizeStyles(11)}'}\`, }; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should work with wildcard imports', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import * as mod from "./__fixtures__/complex-component"; const color = mod["whiteColor"]; export const square = css\` ${'${mod.Title}'} { color: ${'${color}'}; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('assigning to exports', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { Padding } from "./__fixtures__/assignToExport"; export const square = css\` div { padding: ${'${Padding}'}px; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('exporting objects', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import object from "./__fixtures__/objectExport"; export const square = css\` div { margin: ${'${object.margin}'}px; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('exporting objects with computed keys', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { object } from "./__fixtures__/computedKeys"; export const square = css\` div { color: ${'${object.blue}'}; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('exporting sequence expressions', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import number from "./__fixtures__/sequenceExport"; export const square = css\` div { height: ${'${number}'}px; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should work with wildcard reexports', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { foo1 } from "./__fixtures__/reexports"; export const square = css\` color: ${'${foo1}'}; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should ignore unused wildcard reexports', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { foo1 } from "./__fixtures__/reexports"; export const square = css\` color: ${'${foo1}'}; \`; `, [evaluator], undefined, emitter ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); const reexports = resolve(__dirname, './__fixtures__/reexports.js'); const unusedFile = resolve(__dirname, './__fixtures__/bar.js'); expect(onEntrypointEvent).toHaveBeenCalledWith( expect.any(Number), expect.any(Number), expect.objectContaining({ filename: reexports, type: 'created' }) ); hasNotBeenProcessed(unusedFile); }); it('should not drop exported vars of renamed imports', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { foo3 } from "./__fixtures__/reexports"; export const bar3 = foo3; export const square = css\` color: ${'${bar3("thing")}'}; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should process unary expressions in interpolation', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; let size = 1337; size += 0; export const class1 = css\`width:${'${+size}'}px;\`; export const class2 = css\`width:${'${size}'}px;\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); xit('should process bindings in interpolation', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; let size = 1337; export const class1 = css\`width:${'${size = 1}'}px;\`; export const class2 = css\`width:${'${size}'}px;\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should interpolate imported components', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { Title } from "./__fixtures__/complex-component"; export const square = css\` ${'${Title}'} { color: red; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should interpolate imported variables', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { whiteColor } from "./__fixtures__/complex-component"; export const square = css\` color: ${'${whiteColor}'} \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates typescript enums', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; enum Colors { BLUE = '#27509A' } export const Title = styled.h1\` color: ${'${Colors.BLUE}'}; \`; `, [evaluator, {}, 'ts'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('understands satisfies keyword', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core" interface ColorTokenMap { primary: string secondary: string } const lightTokens = { primary: "#111", secondary: "#09f", } satisfies ColorTokenMap export const text = css\` color: ${'${lightTokens.primary}'}; \`; `, [evaluator, {}, 'ts'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should process circular imports', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; import { fooStyles } from "./__fixtures__/circular-imports"; const value = fooStyles.constBar; export const H1 = styled.h1\` color: ${'${value}'}; \` `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('evaluates chain of reexports', async () => { const { code, metadata } = await transform( dedent` import { styled } from '@linaria/react'; import { fooStyles } from "./__fixtures__/re-exports"; const value = fooStyles.foo; export const H1 = styled.h1\` color: ${'${value}'}; \` `, [evaluator], undefined, emitter ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); hasNotBeenProcessed(resolve(__dirname, './__fixtures__/bar.js')); hasNotBeenProcessed( resolve(__dirname, './__fixtures__/re-exports/empty.js') ); }); it('should fail because babelrc options is disabled', async () => { const fn = () => transformFile( resolve(__dirname, './__fixtures__/with-babelrc/index.js'), [ evaluator, { features: { useBabelConfigs: false, }, }, ] ); expect(fn).rejects.toThrowError(`Cannot find module '_/re-exports'`); }); it('respects module-resolver plugin and show waring', async () => { const warn = jest.spyOn(console, 'warn').mockImplementation(() => {}); const { code, metadata } = await transformFile( resolve(__dirname, './__fixtures__/with-babelrc/index.js'), [evaluator] ); expect(warn).toHaveBeenCalledWith( expect.stringContaining( 'This works for now but will be an error in the future' ) ); warn.mockRestore(); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it("respects module-resolver plugin and don't show waring", async () => { const warn = jest.spyOn(console, 'warn').mockImplementation(() => {}); const { code, metadata } = await transformFile( resolve(__dirname, './__fixtures__/with-babelrc/index.js'), [ evaluator, { babelOptions: { plugins: [ [ 'module-resolver', { alias: { _: './src/__fixtures__', }, }, ], ], }, }, ] ); expect(warn).toHaveBeenCalledTimes(0); warn.mockRestore(); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('handles complex component', async () => { const { code, metadata } = await transformFile( resolve(__dirname, './__fixtures__/complex-component.js'), [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should eval component from a linaria library', async () => { const { code, metadata } = await transform( dedent` import { styled } from "@linaria/react"; import { Title } from "./__fixtures__/linaria-ui-library/components/index"; export const StyledTitle = styled(Title)\`\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should not eval components from a non-linaria library', async () => { const { code, metadata } = await transform( dedent` import { styled } from "@linaria/react"; import { Title } from "./__fixtures__/non-linaria-ui-library/index"; export const StyledTitle = styled(Title)\`\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should not eval non-linaria component from a linaria library', async () => { const { code, metadata } = await transform( dedent` import { styled } from "@linaria/react"; import { Title } from "./__fixtures__/linaria-ui-library/non-linaria-components"; export const StyledTitle = styled(Title)\`\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should eval wrapped component from a linaria library', async () => { const { code, metadata } = await transform( dedent` import { styled } from "@linaria/react"; import { connect } from "./__fixtures__/linaria-ui-library/hocs"; import { Title } from "./__fixtures__/linaria-ui-library/components/index"; export const StyledTitle = styled(connect(Title))\`\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should not eval wrapped component from a non-linaria library', async () => { const { code, metadata } = await transform( dedent` import { styled } from "@linaria/react"; import { connect } from "./__fixtures__/linaria-ui-library/hocs"; import { Title } from "./__fixtures__/non-linaria-ui-library/index"; export const StyledTitle = styled(connect(Title))\`\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should not import types', async () => { const { code, metadata } = await transform( dedent` import { styled } from "@linaria/react"; import { Title } from "./__fixtures__/linaria-ui-library/components/index"; import { ComponentType } from "./__fixtures__/linaria-ui-library/types"; const map = new Map<string, ComponentType>() .set('Title', Title); const Gate = (props: { type: ComponentType, className: string }) => { const { className, type } = props; const Component = map.get(type); return <Component className={className}/>; }; export const StyledTitle = styled(Gate)\`\`; `, [evaluator, {}, 'tsx'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should shake out identifiers that are referenced only in types', async () => { const { code, metadata } = await transform( dedent` import { styled } from "@linaria/react"; import * as yup from "yup"; import { Form } from "./__fixtures__/linaria-ui-library/components/index"; const validationSchema = yup.object(); type IModel = yup.InferType<typeof validationSchema>; const Editor = () => { const initial: IModel = {}; return <Form schema={validationSchema} data={initial} />; }; export const StyledEditor = styled(Editor)\`\`; `, [evaluator, {}, 'tsx'] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should process dynamic require', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; const url = "./__fixtures__/FOO"; const foo2 = require(url.toLowerCase()).foo2; export const square = css\` div:before { content: ${'${foo2}'}; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should work with built-in modules', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { URL } from "url"; const url = (new URL("https://example.com")).toString(); export const square = css\` background: url(${'${url}'}); \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should process module.exports = require(…)', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; const mod = require("./__fixtures__/module-reexport"); export const square = css\` div:before { content: ${'${mod.foo}'}; } \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should import react as namespace', async () => { const { code, metadata } = await transform( dedent` import { styled } from "@linaria/react"; import * as React from "react"; const Cmp = React.memo(() => null); export const StyledTitle = styled(Cmp)\`\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should work with short-circuit imports', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { stringConstant } from "./__fixtures__/self-import"; export const StyledTitle = css\` content: "${'${stringConstant}'}"; \`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); xit('should shake out side effect because its definition uses DOM API', async () => { const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { runNearFramePaint } from "./__fixtures__/runNearFramePaint"; runNearFramePaint(() => { // Do something }); export const text = css\`\`; `, [evaluator] ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); describe('cache', () => { const getCachedExports = ( cache: TransformCacheCollection, filename: string ) => { const cachedFoo = cache.get('entrypoints', filename); if (!cachedFoo?.evaluated) { throw new Error('Expected entrypoint to be evaluated'); } const result: Record<string | symbol, unknown> = {}; Object.keys(cachedFoo.exports).forEach((key) => { result[key] = cachedFoo.exports[key]; }); return result; }; it('should cache evaluation', async () => { const filename = require.resolve( join(dirName, './__fixtures__/foo-nonstatic') ); const cache = new TransformCacheCollection(); const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { foo1, foo2 } from "./__fixtures__/foo-nonstatic"; export const text = css\`font-size: ${'${foo1}'}\`; `, [evaluator], cache ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); const exports = getCachedExports(cache, filename); expect(exports.foo1).toBe('foo1'); expect(exports.foo2).toBe(undefined); }); it('promotes statically evaluatable modules to "*"', async () => { const filename = require.resolve(join(dirName, './__fixtures__/foo')); const cache = new TransformCacheCollection(); await transform( dedent` import { css } from "@linaria/core"; import { foo1 } from "./__fixtures__/foo"; export const text = css\`font-size: ${'${foo1}'}\`; `, [evaluator], cache ); const cachedFoo = cache.get('entrypoints', filename); expect(cachedFoo?.evaluatedOnly).toContain('*'); const exports = getCachedExports(cache, filename); expect(exports.foo2).toBe('foo2'); }); const createCacheFor = async ( filename: string, exports: Record<string, string> ) => { const fooContent = readFileSync(filename, 'utf-8'); const cache = new TransformCacheCollection(); cache.invalidateIfChanged(filename, fooContent); const only = Object.keys(exports); const exportsProxy = Entrypoint.createExports(logger); only.forEach((key) => { exportsProxy[key] = exports[key]; }); cache.add('entrypoints', filename, { dependencies: new Map(), evaluated: true, evaluatedOnly: only, generation: 1, exports: exportsProxy, ignored: false, log: logger, only, }); return cache; }; it('should use cached value', async () => { const filename = require.resolve( join(dirName, './__fixtures__/foo-nonstatic') ); const cache = await createCacheFor(filename, { foo1: 'cached-foo1' }); const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { foo1 } from "./__fixtures__/foo-nonstatic"; export const text = css\`font-size: ${'${foo1}'}\`; `, [evaluator], cache ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); it('should reprocess module when cached exports are incomplete', async () => { const filename = require.resolve( join(dirName, './__fixtures__/foo-nonstatic') ); const cache = await createCacheFor(filename, { foo1: 'cached-foo1' }); const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { foo1, foo2 } from "./__fixtures__/foo-nonstatic"; export const text = css\`font-size: ${'${foo1 + foo2}'}\`; `, [evaluator], cache ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); const exports = getCachedExports(cache, filename); expect(exports.foo1).toBe('foo1'); expect(exports.foo2).toBe('foo2'); }); it('should use cached value even if only part is required', async () => { const filename = require.resolve( join(dirName, './__fixtures__/foo-nonstatic') ); const cache = await createCacheFor(filename, { foo1: 'cached-foo1', foo2: 'cached-foo2', }); const { code, metadata } = await transform( dedent` import { css } from "@linaria/core"; import { foo1 } from "./__fixtures__/foo-nonstatic"; export const text = css\`font-size: ${'${foo1}'}\`; `, [evaluator], cache ); expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); }); }); describe('concurrent', () => { it('two parallel chains of reexports', async () => { const cache = new TransformCacheCollection(); const files = { 'source-1': dedent` import { styled } from '@linaria/react'; import { fooStyles } from "./__fixtures__/re-exports"; const value = fooStyles.foo; export const H1 = styled.h1\` color: ${'${value}'}; \` `, 'source-2': dedent` import { styled } from '@linaria/react'; import { bar2 } from "./__fixtures__/re-exports"; export const H1 = styled.h1\` color: ${'${bar2}'}; \` `, }; const results = await Promise.all( Object.entries(files).map(([filename, content]) => transform(content, [evaluator], cache, emitter, filename) ) ); for (const { code, metadata } of results) { expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); } hasNotBeenProcessed( resolve(__dirname, './__fixtures__/re-exports/empty.js') ); }); it('multiple parallel chains of reexports', async () => { const cache = new TransformCacheCollection(); const tokens = ['foo', 'bar', 'bar1', 'bar2']; const results = await Promise.all( tokens.map((token) => transform( dedent` import { styled } from '@linaria/react'; import { ${token} } from "./__fixtures__/re-exports"; export const H1${token} = styled.h1\` color: ${`\${${token}}`}; \` `, [evaluator], cache, emitter, token ) ) ); for (const { code, metadata } of results) { expect(code).toMatchSnapshot(); expect(metadata).toMatchSnapshot(); } }); it('loop in evaluated files', async () => { const cache = new TransformCacheCollection(); await expect(() => Promise.all( ['AB', 'BA'].map((token) => transform( dedent` import { styled } from '@linaria/react'; import { ${token} } from "./__fixtures__/loop/${token.toLowerCase()}"; export const H1${token} = styled.h1\` color: ${`\${${token}}`}; \` `, [evaluator], cache, emitter, token ) ) ) ).rejects.toThrowError(/reading 'toLowerCase'/); }); }); }); ================================================ FILE: packages/testkit/src/transform.test.ts ================================================ /* eslint-disable no-template-curly-in-string */ import path from 'path'; import { asyncResolveFallback } from '@wyw-in-js/shared'; import { shaker, transform, transformUrl } from '@wyw-in-js/transform'; import dedent from 'dedent'; const outputFilename = './.linaria-cache/test.css'; const rules = [ { test: () => true, action: shaker, }, ]; const basePluginOptions = { features: { happyDOM: false, }, rules, }; describe('transformUrl', () => { type TransformUrlArgs = Parameters<typeof transformUrl>; const dataset: Record<string, TransformUrlArgs> = { '../assets/test.jpg': [ './assets/test.jpg', './.linaria-cache/test.css', './test.js', ], '../a/b/test.jpg': [ '../a/b/test.jpg', './.linaria-cache/test.css', './a/test.js', ], }; it('should work with posix paths', () => { Object.keys(dataset).forEach((result) => { expect(transformUrl(...dataset[result])).toBe(result); }); }); it('should work with win32 paths', () => { const toWin32 = (p: string) => p.split(path.posix.sep).join(path.win32.sep); const win32Dataset = Object.keys(dataset).reduce( (acc, key) => ({ ...acc, [key]: [ dataset[key][0], toWin32(dataset[key][1]), toWin32(dataset[key][2]), path.win32, ] as TransformUrlArgs, }), {} as Record<string, TransformUrlArgs> ); Object.keys(win32Dataset).forEach((result) => { expect(transformUrl(...win32Dataset[result])).toBe(result); }); }); }); it('rewrites a relative path in url() declarations', async () => { const { cssText } = await transform( { options: { filename: './test.js', outputFilename: './.linaria-cache/test.css', pluginOptions: { ...basePluginOptions, }, }, }, dedent` import { css } from '@linaria/core'; export const title = css\` background-image: url(./assets/test.jpg); background-image: url("./assets/test.jpg"); background-image: url('./assets/test.jpg'); \`; `, asyncResolveFallback ); expect(cssText).toMatchSnapshot(); }); it('rewrites multiple relative paths in url() declarations', async () => { const { cssText } = await transform( { options: { filename: './test.js', outputFilename, pluginOptions: { ...basePluginOptions, }, }, }, dedent` import { css } from '@linaria/core'; export const title = css\` @font-face { font-family: Test; src: url(./assets/font.woff2) format("woff2"), url(./assets/font.woff) format("woff"); } \`; `, asyncResolveFallback ); expect(cssText).toMatchSnapshot(); }); it("doesn't rewrite an absolute path in url() declarations", async () => { const { cssText } = await transform( { options: { filename: './test.js', outputFilename, pluginOptions: { ...basePluginOptions, }, }, }, dedent` import { css } from '@linaria/core'; export const title = css\` background-image: url(/assets/test.jpg); \`; `, asyncResolveFallback ); expect(cssText).toMatchSnapshot(); }); it('respects passed babel options', async () => { expect.assertions(2); await expect(() => transform( { options: { filename: './test.js', outputFilename, pluginOptions: { ...basePluginOptions, babelOptions: { babelrc: false, configFile: false, presets: [['@babel/preset-env', { loose: true }]], }, }, }, }, dedent` import { css } from '@linaria/core'; export const error = <jsx />; `, asyncResolveFallback ) ).rejects.toThrow( /Support for the experimental syntax 'jsx' isn't currently enabled/ ); await expect(() => transform( { options: { filename: './test.js', outputFilename, pluginOptions: { ...basePluginOptions, babelOptions: { babelrc: false, configFile: false, presets: [ ['@babel/preset-env', { loose: true }], '@babel/preset-react', ], }, }, }, }, dedent` import { css } from '@linaria/core'; export const error = <jsx />; export const title = css\` background-image: url(/assets/test.jpg); \`; `, asyncResolveFallback ) ).not.toThrow('Unexpected token'); }); it("doesn't throw due to duplicate preset", async () => { expect.assertions(1); expect(() => transform( { options: { filename: './test.js', outputFilename, pluginOptions: { ...basePluginOptions, babelOptions: { babelrc: false, configFile: false, presets: [require.resolve('@linaria/babel-preset')], plugins: [ require.resolve('@babel/plugin-transform-modules-commonjs'), ], }, }, }, }, dedent` import { styled } from '@linaria/react'; const Title = styled.h1\` color: blue; \`; const Article = styled.article\` ${'${Title}'} { font-size: 16px; } \`; `, asyncResolveFallback ) ).not.toThrow('Duplicate plugin/preset detected'); }); it('should return transformed code even when file only contains unused linaria code', async () => { const { code } = await transform( { options: { filename: './test.js', outputFilename, pluginOptions: { ...basePluginOptions, }, }, }, dedent` import { css } from '@linaria/core'; const title = css\` color: red; \`; `, asyncResolveFallback ); expect(code).not.toContain('css`'); }); ================================================ FILE: packages/testkit/tsconfig.json ================================================ { "extends": "../../tsconfig.json", "exclude": [ // Contains broken code that should not be type-checked "src/__fixtures__/prepare-code-test-cases/dynamic-import/input.ts", "src/__fixtures__/prepare-code-test-cases/dynamic-import-param/input.ts", "src/__fixtures__/prepare-code-test-cases/for-debug/input.ts", "src/__fixtures__/linaria-ui-library/types.ts", "node_modules" ], "compilerOptions": { "paths": {}, "rootDir": "src/", "types": ["jest", "node"] }, "references": [{ "path": "../core" }, { "path": "../react" }] } ================================================ FILE: pnpm-workspace.yaml ================================================ packages: - 'packages/*' - 'website' - 'examples/**' - '!examples/gatsby/**' # too many dependencies, possible outdated - '!examples/webpack4' # legacy since node 17 ================================================ FILE: react/package.json ================================================ { "main": "../lib/react/index.js", "module": "../esm/react/index.js", "types": "../lib/react/index.d.ts" } ================================================ FILE: tsconfig.eslint.json ================================================ { "extends": "./tsconfig.json", "exclude": ["node_modules"], "include": ["packages/**/*.ts", "packages/**/*.js", "packages/**/*.tsx"] } ================================================ FILE: tsconfig.json ================================================ { "exclude": [ "node_modules", "packages/**/__dtslint__/**", "packages/**/__tests__/**", "packages/**/__fixtures__/**", "packages/**/__utils__/**", "packages/**/dist/**", "packages/**/types/**" ], "compilerOptions": { "baseUrl": ".", "composite": true, "paths": { "@linaria/*": ["./packages/*/src"] }, "jsx": "react", "lib": ["es6", "es2017", "es2018", "es2022", "ES2019.Array", "dom", "esnext.disposable"], "module": "es6", "moduleResolution": "node", "strict": true, "target": "es2022", "allowSyntheticDefaultImports": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "declaration": true, "typeRoots": ["node_modules/@types", "typings"], "skipLibCheck": true, "skipDefaultLibCheck": true, "preserveWatchOutput": true, } } ================================================ FILE: tsconfig.prod.json ================================================ { "extends": "./tsconfig.json", "include": ["src/core/*.ts", "src/react/*.ts"] } ================================================ FILE: tslint.json ================================================ { "extends": "dtslint/dtslint.json", "rules": { "file-name-casing": false, "interface-over-type-literal": false, "strict-export-declare-modifiers": false }, "linterOptions": { "exclude": ["node_modules/**", "packages/*/types"] } } ================================================ FILE: turbo.json ================================================ { "$schema": "https://turborepo.org/schema.json", "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**", "esm/**", "lib/**", "types/**"] }, "build:declarations": { "dependsOn": ["^build:declarations"], "outputs": ["types/**"] }, "check:all": { "dependsOn": ["test:dts", "typecheck", "test"] }, "lint": {}, "test": { "dependsOn": [], "outputs": [], "cache": false }, "@linaria/atomic#test": { "dependsOn": ["@linaria/core#build", "@linaria/react#build"] }, "@linaria/react#test": { "dependsOn": ["@linaria/core#build"] }, "@linaria/postcss-linaria#test": { "dependsOn": ["@linaria/postcss-linaria#build"] }, "@linaria/testkit#test": { "dependsOn": ["^build"] }, "test:dts": { "dependsOn": ["build:declarations", "^build:declarations"], "cache": false }, "typecheck": { "dependsOn": ["build:declarations", "^build:declarations"] } } } ================================================ FILE: website/.eslintrc ================================================ { "settings": { "import/core-modules": [] } } ================================================ FILE: website/CHANGELOG.md ================================================ # Change Log ## 6.3.2 ### Patch Changes - Updated dependencies [b3331e45] - @linaria/react@7.0.1 - @linaria/atomic@7.0.1 ## 6.3.1 ### Patch Changes - Updated dependencies [ab11ebb7] - Updated dependencies [654d8590] - @linaria/atomic@7.0.0 - @linaria/core@7.0.0 - @linaria/react@7.0.0 - @linaria/server@7.0.0 ## 6.3.0 ### Minor Changes - 281ca4f5: The new version of wyw-in-js, with the support of a configurable code remover, can help prevent compilation errors and improve build time. ### Patch Changes - Updated dependencies [bd8d45fd] - Updated dependencies [281ca4f5] - @linaria/react@6.3.0 - @linaria/atomic@6.3.0 - @linaria/core@6.3.0 - @linaria/server@6.3.0 ## 6.2.0 ### Minor Changes - a3dcee2e: Update wyw-in-js to 0.5.3 ### Patch Changes - Updated dependencies [a3dcee2e] - @linaria/atomic@6.2.0 - @linaria/core@6.2.0 - @linaria/server@6.2.0 - @linaria/react@6.2.1 ## 6.1.1 ### Patch Changes - Updated dependencies [fd60b5de] - @linaria/react@6.2.0 - @linaria/atomic@6.1.1 ## 6.1.0 ### Minor Changes - 8ba655d3: Bump wyw-in-js to 0.4.0. The full list of changes https://github.com/Anber/wyw-in-js/compare/%40wyw-in-js/transform%400.2.3...%40wyw-in-js/transform%400.4.0 ### Patch Changes - 8d4ebd33: chore: bump @wyw-in-js/\* packages - Updated dependencies [8d4ebd33] - Updated dependencies [8ba655d3] - @linaria/atomic@6.1.0 - @linaria/core@6.1.0 - @linaria/react@6.1.0 - @linaria/server@6.1.0 ## 6.0.0 ### Major Changes - 2ac94b99: BREAKING CHANGE: Linaria has been migrated to wyw-in-js. # Migration Guide ## For Users The main breaking change is that all tooling has been moved from the `@linaria` scope to the `@wyw-in-js` scope. This means that you will need to update your dependencies as follows: | Old | New | | ------------------------ | ------------------------- | | @linaria/babel-preset | @wyw-in-js/babel-preset | | @linaria/cli | @wyw-in-js/cli | | @linaria/esbuild | @wyw-in-js/esbuild | | @linaria/rollup | @wyw-in-js/rollup | | @linaria/shaker | discontinued | | @linaria/vite | @wyw-in-js/vite | | @linaria/webpack4-loader | discontinued | | @linaria/webpack5-loader | @wyw-in-js/webpack-loader | There is no longer a need to install `@linaria/shaker` as it is now part of `@wyw-in-js/transform`, which will be installed automatically with the bundler plugins. The configuration file has been renamed from `linaria.config.js` (`linariarc`) to `wyw-in-js.config.js` (`.wyw-in-jsrc`). ## For Custom Processor Developers Base classes for processors and most helpers have been moved to `@wyw-in-js/processor-utils`. All APIs that had `linaria` in their names have been renamed: - The field that stores meta information in runtime has been renamed from `__linaria` to `__wyw_meta` - The export with all interpolated values has been renamed from `__linariaPreval` to `__wywPreval` - The caller name in Babel has been renamed from `linaria` to `wyw-in-js` For additional information, please visit the [wyw-in-js.dev](https://wyw-in-js.dev). ### Patch Changes - Updated dependencies [60e6b7e2] - Updated dependencies [2ac94b99] - @linaria/atomic@6.0.0 - @linaria/core@6.0.0 - @linaria/react@6.0.0 - @linaria/server@6.0.0 ## 5.0.3 ### Patch Changes - Updated dependencies [4b083b7c] - @linaria/react@5.0.3 - @linaria/atomic@5.0.3 ## 5.0.2 ### Patch Changes - Updated dependencies [1e889937] - @linaria/react@5.0.2 - @linaria/atomic@5.0.2 - @linaria/core@5.0.2 ## 5.0.1 ### Patch Changes - @linaria/atomic@5.0.1 - @linaria/core@5.0.1 - @linaria/react@5.0.1 ## 5.0.0 ### Major Changes - 88e07613: Rewritten dependecny tree processing with support for wildcard re-exports. - cb853e14: All processing stages were merged into one generators-based processor. It allows the implementation of more complex workflows to support features like dynamic imports and re-exports. ### Patch Changes - 2a1e24a0: Upgrade TypeScript to 5.2 - Updated dependencies [9cb4143d] - Updated dependencies [88e07613] - Updated dependencies [2a1e24a0] - Updated dependencies [cb853e14] - @linaria/atomic@5.0.0 - @linaria/core@5.0.0 - @linaria/react@5.0.0 - @linaria/server@5.0.0 ## 4.5.4 ### Patch Changes - @linaria/atomic@4.5.4 - @linaria/core@4.5.4 - @linaria/react@4.5.4 ## 4.5.3 ### Patch Changes - e59bf809: Shaker mistakenly counts references in types as valuable and keeps referenced variables alive. - 520ba8da: Debug mode for CLI, Webpack 5 and Vite. When enabled, prints brief perf report to console and information about processed dependency tree to the specified file. - Updated dependencies [79557248] - Updated dependencies [e59bf809] - @linaria/atomic@4.5.3 - @linaria/core@4.5.3 - @linaria/react@4.5.3 ## 4.5.2 ### Patch Changes - 1bf5c5b8: The cache has been improved, which should address the build time issues for Webpack 4/5 and resolve HMR-related problems for Vite. Fixes #1199, #1265 and maybe some more. - @linaria/atomic@4.5.2 - @linaria/core@4.5.2 - @linaria/react@4.5.2 ## 4.5.1 ### Patch Changes - Updated dependencies [ceca1611] - Updated dependencies [13258306] - @linaria/react@4.5.1 - @linaria/atomic@4.5.1 - @linaria/core@4.5.1 ## 4.5.0 ### Minor Changes - 16c057df: Breaking Change: Performance Optimization for `styled` When a component is wrapped in `styled`, Linaria needs to determine if that component is already a styled component. To accomplish this, the wrapped component is included in the list of variables for evaluation, along with the interpolated values used in styles. The issue arises when a wrapped component, even if it is not styled, brings along a substantial dependency tree. This situation is particularly evident when using `styled` to style components from third-party UI libraries. To address this problem, Linaria will now examine the import location of the component and check if there is an annotation in the `package.json` file of the package containing the components. This annotation indicates whether the package includes other Linaria components. If there is no such annotation, Linaria will refrain from evaluating the component. Please note that this Breaking Change solely affects developers of component libraries. In order for users to style components from your library, you must include the `linaria.components` property in the library's `package.json` file. This property should have a mask that covers all imported files with components. Here's an example of how to specify it: ```json "linaria": { "components": "**/*" } ``` ### Patch Changes - af5bb92d: The end of support for Node.js 14. Migration to pnpm 8. - Updated dependencies [16c057df] - Updated dependencies [af5bb92d] - Updated dependencies [10859924] - @linaria/react@4.5.0 - @linaria/atomic@4.5.0 - @linaria/core@4.5.0 - @linaria/server@4.5.0 ## 4.1.16 ### Patch Changes - Updated dependencies [54ab61b2] - @linaria/react@4.3.8 - @linaria/atomic@4.2.10 - @linaria/core@4.2.10 ## 4.1.15 ### Patch Changes - Updated dependencies [1c3f309d] - Updated dependencies [34029088] - @linaria/react@4.3.7 - @linaria/atomic@4.2.9 - @linaria/core@4.2.9 ## 4.1.14 ### Patch Changes - Updated dependencies [a3ad617f] - @linaria/react@4.3.6 - @linaria/atomic@4.2.8 - @linaria/core@4.2.8 ## 4.1.13 ### Patch Changes - Updated dependencies [a2b618bc] - @linaria/atomic@4.2.7 - @linaria/core@4.2.7 - @linaria/react@4.3.5 ## 4.1.12 ### Patch Changes - @linaria/atomic@4.2.6 - @linaria/core@4.2.6 - @linaria/react@4.3.4 ## 4.1.11 ### Patch Changes - Updated dependencies [61fe2560] - Updated dependencies [77bcf2e7] - @linaria/atomic@4.2.5 - @linaria/server@4.1.0 - @linaria/core@4.2.5 - @linaria/react@4.3.3 ## 4.1.10 ### Patch Changes - @linaria/atomic@4.2.4 - @linaria/core@4.2.4 - @linaria/react@4.3.2 ## 4.1.9 ### Patch Changes - 6b8bff49: Switch website to pnpm - 5edde648: Upgrade Babel to support TypeScript 4.9. Fixes #1133. - Updated dependencies [922f20d6] - Updated dependencies [5edde648] - @linaria/react@4.3.1 - @linaria/atomic@4.2.3 - @linaria/core@4.2.3 ## 4.1.8 ### Patch Changes - Updated dependencies [63f56d47] - Updated dependencies [c26d4667] - @linaria/react@4.3.0 - @linaria/atomic@4.2.2 - @linaria/core@4.2.2 ## 4.1.7 ### Patch Changes - Updated dependencies [6de22792] - @linaria/react@4.2.1 - @linaria/atomic@4.2.1 - @linaria/core@4.2.1 ## 4.1.6 ### Patch Changes - Updated dependencies [1e88e95d] - @linaria/atomic@4.2.0 - @linaria/core@4.2.0 - @linaria/react@4.2.0 ## 4.1.5 ### Patch Changes - Updated dependencies [87ffe61c] - @linaria/atomic@4.1.5 - @linaria/core@4.1.4 - @linaria/react@4.1.5 ## 4.1.4 ### Patch Changes - @linaria/atomic@4.1.4 - @linaria/core@4.1.3 - @linaria/react@4.1.4 ## 4.1.3 ### Patch Changes - Updated dependencies [c0bd271a] - @linaria/react@4.1.3 - @linaria/atomic@4.1.3 - @linaria/core@4.1.2 ## 4.1.2 ### Patch Changes - @linaria/atomic@4.1.2 - @linaria/core@4.1.1 - @linaria/react@4.1.2 ## 4.1.1 ### Patch Changes - Updated dependencies [2abc55b3] - @linaria/react@4.1.1 - @linaria/atomic@4.1.1 ## 4.1.0 ### Patch Changes - @linaria/atomic@4.1.0 - @linaria/core@4.1.0 - @linaria/react@4.1.0 ## 4.0.0 ### Major Changes - bc0cbeea: A completely new async mode with native support for Vite, Rollup, esbuild and Webpack resolvers. BREAKING CHANGES: Despite the fact, that it should be fully compatible with 3.0 and 2.0 branches, the new version of styles evaluator can have some serious bugs which can make your project unbuildable (however, since there is no runtime, if the build is finished successfully, everything will continue work as it was on 2.0 and 3.0). If you face some problems please let us know and we will fix it as soon as possible. ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - ea41d440: New package @linaria/tags that contains all abstract logic for tags processors. - Updated dependencies [f0cddda4] - @linaria/atomic@4.0.0 - @linaria/core@4.0.0 - @linaria/react@4.0.0 - @linaria/server@4.0.0 ## 3.0.0-beta.21 ### Patch Changes - Updated dependencies [17c83e34] - @linaria/react@3.0.0-beta.21 - @linaria/core@3.0.0-beta.21 - @linaria/atomic@3.0.0-beta.21 ## 3.0.0-beta.20 ### Patch Changes - 8be5650d: The repo has been migrated to PNPM and Turborepo - Updated dependencies - @linaria/atomic@3.0.0-beta.20 - @linaria/core@3.0.0-beta.20 - @linaria/react@3.0.0-beta.20 - @linaria/server@3.0.0-beta.20 # [3.0.0-beta.19](https://github.com/callstack/linaria/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2022-06-03) ### Features - **atomic:** add support for atomic using styled API ([#966](https://github.com/callstack/linaria/issues/966)) ([f59860b](https://github.com/callstack/linaria/commit/f59860b09c5f91b0423dbf188e5f8aaaef38a6b5)) - **babel:** api for custom tags ([#976](https://github.com/callstack/linaria/issues/976)) ([3285ccc](https://github.com/callstack/linaria/commit/3285ccc1d00449b78b3fc74087528cd38cbdd116)) - **babel:** new way for detecting tag imports ([#974](https://github.com/callstack/linaria/issues/974)) ([3305cfb](https://github.com/callstack/linaria/commit/3305cfb0c0f65abdacceeb7e6bad118c59f7d551)) - **core:** allow renaming of css template literals ([#973](https://github.com/callstack/linaria/issues/973)) ([8f59a82](https://github.com/callstack/linaria/commit/8f59a82400143ef35b6ffc7f024ad5e6a16552d8)) # [3.0.0-beta.18](https://github.com/callstack/linaria/compare/v3.0.0-beta.17...v3.0.0-beta.18) (2022-04-01) ### Features - **atomic:** add support for at-rules, keyframes and pseudo classes ([#913](https://github.com/callstack/linaria/issues/913)) ([dee7fa1](https://github.com/callstack/linaria/commit/dee7fa14ea912224cac9f0673be7464e93571a73)) # [3.0.0-beta.17](https://github.com/callstack/linaria/compare/v3.0.0-beta.16...v3.0.0-beta.17) (2021-12-27) ### Features - **resolver:** add custom resolver option to support re-exporting of linaria libs ([#882](https://github.com/callstack/linaria/issues/882)) ([ad4a368](https://github.com/callstack/linaria/commit/ad4a36857faceec19fa083b28d43af01d5f48f11)) # [3.0.0-beta.16](https://github.com/callstack/linaria/compare/v3.0.0-beta.15...v3.0.0-beta.16) (2021-12-01) **Note:** Version bump only for package linaria-website # [3.0.0-beta.15](https://github.com/callstack/linaria/compare/v3.0.0-beta.14...v3.0.0-beta.15) (2021-11-29) ### Features - **atomic:** create an atomic package for the css API ([#867](https://github.com/callstack/linaria/issues/867)) ([4773bcf](https://github.com/callstack/linaria/commit/4773bcf4b14f08cdc4d2b612654b962cdfc97eaa)) # [3.0.0-beta.14](https://github.com/callstack/linaria/compare/v3.0.0-beta.13...v3.0.0-beta.14) (2021-11-05) **Note:** Version bump only for package linaria-website # [3.0.0-beta.13](https://github.com/callstack/linaria/compare/v3.0.0-beta.12...v3.0.0-beta.13) (2021-09-13) **Note:** Version bump only for package linaria-website # [3.0.0-beta.12](https://github.com/callstack/linaria/compare/v3.0.0-beta.11...v3.0.0-beta.12) (2021-08-31) **Note:** Version bump only for package linaria-website # [3.0.0-beta.11](https://github.com/callstack/linaria/compare/v3.0.0-beta.10...v3.0.0-beta.11) (2021-08-08) **Note:** Version bump only for package linaria-website # [3.0.0-beta.7](https://github.com/callstack/linaria/compare/v3.0.0-beta.6...v3.0.0-beta.7) (2021-06-24) **Note:** Version bump only for package linaria-website # [3.0.0-beta.6](https://github.com/callstack/linaria/compare/v3.0.0-beta.5...v3.0.0-beta.6) (2021-06-06) **Note:** Version bump only for package linaria-website # [3.0.0-beta.5](https://github.com/callstack/linaria/compare/v3.0.0-beta.4...v3.0.0-beta.5) (2021-05-31) **Note:** Version bump only for package linaria-website # [3.0.0-beta.4](https://github.com/callstack/linaria/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2021-05-07) **Note:** Version bump only for package linaria-website # [3.0.0-beta.3](https://github.com/callstack/linaria/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2021-04-20) **Note:** Version bump only for package linaria-website # [3.0.0-beta.2](https://github.com/callstack/linaria/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2021-04-11) **Note:** Version bump only for package linaria-website ================================================ FILE: website/babel.config.js ================================================ module.exports = { presets: ['@babel/preset-env', '@babel/preset-react'], env: { server: { presets: [ require.resolve('@wyw-in-js/babel-preset'), ['@babel/preset-env', { targets: { node: 12 } }], ], plugins: [ [ 'file-loader', { publicPath: '/dist', outputPath: '/dist', }, ], ], }, }, }; ================================================ FILE: website/index.html ================================================ <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Linaria – zero-runtime CSS in JS library
================================================ FILE: website/linaria.config.js ================================================ module.exports = { displayName: process.env.NODE_ENV !== 'production', }; ================================================ FILE: website/package.json ================================================ { "name": "linaria-website", "version": "6.3.2", "private": true, "description": "Linaria website", "exports": { ".": "./src/index.jsx", "./*": "./src/*.jsx" }, "main": "./src/index.jsx", "scripts": { "build": "pnpm build:client && pnpm build:server", "build:client": "cross-env NODE_ENV=production webpack", "build:server": "cross-env NODE_ENV=production BABEL_ENV=server babel src --out-dir build", "clean": "pnpm clean:client && pnpm clean:server", "clean:client": "del dist", "clean:server": "del build", "lint:css": "stylelint src/**/*.jsx", "prebuild": "pnpm clean", "prestart": "pnpm -w prepare", "server": "node build/server", "start": "webpack serve" }, "dependencies": { "@babel/runtime": "^7.23.5", "@linaria/atomic": "workspace:^", "@linaria/core": "workspace:^", "@linaria/react": "workspace:^", "@linaria/server": "workspace:^", "babel-plugin-file-loader": "^1.1.1", "dedent": "^1.5.1", "escape-html": "^1.0.3", "ignore-styles": "^5.0.1", "koa": "^2.7.0", "koa-compress": "^3.0.0", "koa-router": "^7.4.0", "koa-send": "^5.0.0", "react": "^16.14.0", "react-dom": "^16.14.0" }, "devDependencies": { "@babel/cli": "^7.23.4", "@babel/core": "^7.23.5", "@linaria/stylelint": "workspace:^", "@wyw-in-js/babel-preset": "^1.0.6", "@wyw-in-js/webpack-loader": "^1.0.6", "babel-loader": "^8.2.5", "babel-plugin-module-resolver": "^4.1.0", "cross-env": "^7.0.3", "css-hot-loader": "^1.4.4", "css-loader": "^6.7.1", "del-cli": "^1.1.0", "html-webpack-plugin": "^5.5.3", "mini-css-extract-plugin": "^2.6.0", "stylelint": "^14.11.0", "stylelint-config-recommended": "^3.0.0", "url": "^0.11.0", "webpack": "^5.94.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.9.1" } } ================================================ FILE: website/serve.config.js ================================================ const path = require('path'); module.exports = { port: 3242, content: path.resolve(__dirname), devMiddleware: { publicPath: '/dist/', }, }; ================================================ FILE: website/src/.eslintrc ================================================ { "env": { "browser": true } } ================================================ FILE: website/src/api/index.js ================================================ ================================================ FILE: website/src/api/react/index.js ================================================ export * from '@linaria/react'; ================================================ FILE: website/src/components/App.jsx ================================================ import React from 'react'; import { css, cx } from '@linaria/atomic'; import Header from './Header'; import Hero from './Hero'; const Page = css` background: linear-gradient(to bottom right, #b24592, #f15f79); color: #fff; min-height: 100vh; text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.08); `; export default function Index() { return (
); } ================================================ FILE: website/src/components/Container.js ================================================ import { styled } from '@linaria/react'; const Container = styled.div` max-width: 1140px; padding: 16px 24px; margin: 0 auto; `; export default Container; ================================================ FILE: website/src/components/Example.js ================================================ import { css } from '@linaria/core'; import { css as atomicCss } from '@linaria/atomic'; export const Page = css` background: linear-gradient(to bottom right, #b24592, #f15f79); color: #fff; min-height: 100vh; text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.08); `; export const AtomicPage = atomicCss` background: linear-gradient(to bottom right, #b24592, #f15f79); color: #fff; min-height: 100vh; text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.08); `; ================================================ FILE: website/src/components/Header.jsx ================================================ import { styled } from '@linaria/react'; import React from 'react'; import constants from '../styles/constants'; import { media } from '../styles/utils'; import Container from './Container'; import logo from '../../assets/linaria-logo.svg'; export default function Header() { return (
  • Features
  • Docs
  • GitHub
  • ); } const NavBar = styled(Container)` display: flex; flex-direction: column; justify-content: space-between; align-items: center; ${media.medium} { flex-direction: row; } `; const LogoImage = styled.img` height: 64px; margin: 16px auto; display: block; ${media.medium} { height: 48px; margin: 0; display: inline-block; vertical-align: middle; } `; const Links = styled.ul` display: flex; padding: 0; margin: 0; list-style: none; align-items: center; `; const LinkItem = styled.a` display: block; font-size: 1.2em; font-weight: 700; padding: 24px 16px; text-decoration: none; color: inherit; transition: color 0.2s; transition: 200ms; &:hover { color: inherit; } @supports (-webkit-background-clip: text) { background-image: ${constants.gradient}; /* stylelint-disable-next-line property-no-vendor-prefix */ -webkit-background-clip: text; &:hover { color: transparent; } } `; ================================================ FILE: website/src/components/Hero.jsx ================================================ import { styled } from '@linaria/react'; import React from 'react'; import { media } from '../styles/utils'; import Container from './Container'; import codeSample from '../../assets/code-sample-v4.png'; import linariaLogomark from '../../assets/linaria-logomark.svg'; export default function Hero() { return ( Zero-Runtime CSS in JS Write CSS in JS and get real CSS files during build. Use dynamic prop based styles with the React bindings and have them transpiled to CSS variables automatically. Great productivity with source maps and linting support. ); } const HeroContainer = styled.main` position: relative; ${media.large} { padding: 64px 0; background-image: url(${linariaLogomark}); background-repeat: no-repeat; background-position: bottom right; } `; const Row = styled.div` ${media.large} { display: flex; align-items: center; justify-content: space-between; } `; const LeftColumn = styled.div` text-align: center; flex: 3; ${media.large} { text-align: left; } `; const RightColumn = styled.div` text-align: center; flex: 2; z-index: 1; `; const Heading = styled.h1` font-weight: 700; font-size: 56px; `; const Description = styled.p` margin-bottom: 60px; `; const Button = styled.button` display: inline-block; appearance: none; background: none; border: 0; padding: 16px 24px; color: inherit; font-size: inherit; font-weight: 700; font-family: inherit; text-transform: uppercase; text-decoration: none; box-shadow: inset 0 0 0 2px currentColor, 1px 1px 1px rgba(0, 0, 0, 0.08); border-radius: 30px; cursor: pointer; transition: color 200ms, background 200ms; &:hover { color: #d2356d; box-shadow: inset 0 0 0 2px transparent, 1px 1px 1px rgba(0, 0, 0, 0.08); background: linear-gradient( to right, hsl(180, 100%, 70%), hsl(64, 57%, 82%), hsl(0, 100%, 84%) ); } `; const CodeSample = styled.img` width: 100%; height: auto; margin: 64px 24px; padding: 20px; border-radius: 5px; max-width: calc(100% - 48px); box-shadow: 3px 3px 32px rgba(0, 0, 0, 0.32); background-color: #272727; ${media.large} { margin: 24px; } `; ================================================ FILE: website/src/index.jsx ================================================ import { css } from '@linaria/core'; import React from 'react'; import ReactDOM from 'react-dom'; import App from './components/App'; import constants from './styles/constants'; ReactDOM.render(, document.getElementById('root')); // eslint-disable-next-line import/prefer-default-export export const globals = css` :global() { html { box-sizing: border-box; height: 100%; width: 100%; } body { margin: 0; padding: 0; height: 100%; width: 100%; font-family: ${constants.fontFamily}; font-size: 20px; line-height: 1.42857; } *, *:before, *:after { box-sizing: inherit; } } `; ================================================ FILE: website/src/server.jsx ================================================ import 'ignore-styles'; import fs from 'fs'; import path from 'path'; import crypto from 'crypto'; import { collect } from '@linaria/server'; import Koa from 'koa'; import Router from 'koa-router'; import compress from 'koa-compress'; import send from 'koa-send'; import dedent from 'dedent'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; import config from '../serve.config'; import App from './components/App'; const cache = {}; const css = fs.readFileSync(path.join(__dirname, '../dist/styles.css'), 'utf8'); const app = new Koa(); const router = new Router(); app.use(compress()); router.get('/', async (ctx) => { const html = ReactDOMServer.renderToStaticMarkup(); const { critical, other } = collect(html, css); const slug = crypto.createHash('md5').update(other).digest('hex'); cache[slug] = other; ctx.type = 'html'; ctx.body = dedent` Linaria – zero-runtime CSS in JS library
    ${html}
    `; }); router.get('/dist/:path+', async (ctx) => { await send(ctx, path.join('dist', ctx.params.path)); }); router.get('/styles/:slug', async (ctx) => { ctx.type = 'text/css'; ctx.body = cache[ctx.params.slug]; }); app.use(router.routes()); app.listen(config.port); // eslint-disable-next-line no-console console.log(`Listening on http://localhost:${config.port}`); ================================================ FILE: website/src/styles/constants.js ================================================ export default { fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", Helvetica, sans-serif', gradient: 'linear-gradient(to right, hsl(180, 100%, 70%), hsl(64, 57%, 82%), hsl(0, 100%, 90%))', }; ================================================ FILE: website/src/styles/utils.js ================================================ export const breakpoints = { medium: 640, large: 1024, }; export const media = Object.keys(breakpoints).reduce((acc, item) => { acc[item] = `@media screen and (min-width: ${breakpoints[item]}px)`; return acc; }, {}); ================================================ FILE: website/stylelint.config.js ================================================ module.exports = { extends: [ 'stylelint-config-recommended', require.resolve('@linaria/stylelint'), ], }; ================================================ FILE: website/webpack.config.js ================================================ const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const { join } = require('path'); // eslint-disable-line import/no-extraneous-dependencies const HtmlWebpackPlugin = require('html-webpack-plugin'); const { WYWinJSDebugPlugin } = require('@wyw-in-js/webpack-loader'); const dev = process.env.NODE_ENV !== 'production'; module.exports = { mode: dev ? 'development' : 'production', devtool: 'source-map', entry: { app: './src/index', }, output: { path: join(__dirname, 'dist'), filename: '[name].bundle.js', }, optimization: { emitOnErrors: false, }, plugins: [ new WYWinJSDebugPlugin({ dir: 'wyw-debug', print: true, }), new MiniCssExtractPlugin({ filename: 'styles.css' }), new HtmlWebpackPlugin({ title: 'Linaria – zero-runtime CSS in JS library', templateContent: `
    `, }), ], resolve: { extensions: ['.js', '.jsx'], }, module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: [ { loader: 'babel-loader' }, { loader: require.resolve('@wyw-in-js/webpack-loader'), options: { sourceMap: dev }, }, ], }, { test: /\.css$/, use: [ 'css-hot-loader', MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { sourceMap: dev }, }, ], }, { test: /\.(png|jpg|gif|svg)$/, type: 'asset/resource', }, ], }, devServer: { static: { directory: join(__dirname, 'dist'), }, hot: true, historyApiFallback: { index: 'index.html', }, }, };