{"id":15391514,"url":"https://github.com/skovy/css-codemod","last_synced_at":"2025-04-15T23:19:16.262Z","repository":{"id":37438577,"uuid":"448700801","full_name":"skovy/css-codemod","owner":"skovy","description":"🐍 Toolkit for running codemods over CSS files","archived":false,"fork":false,"pushed_at":"2022-02-03T02:48:42.000Z","size":1158,"stargazers_count":14,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-29T02:34:08.242Z","etag":null,"topics":["codemod","css","transform"],"latest_commit_sha":null,"homepage":"https://github.com/skovy/css-codemod","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skovy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-16T23:41:57.000Z","updated_at":"2024-12-10T01:03:40.000Z","dependencies_parsed_at":"2022-08-18T05:00:56.596Z","dependency_job_id":null,"html_url":"https://github.com/skovy/css-codemod","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skovy%2Fcss-codemod","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skovy%2Fcss-codemod/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skovy%2Fcss-codemod/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skovy%2Fcss-codemod/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skovy","download_url":"https://codeload.github.com/skovy/css-codemod/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249167861,"owners_count":21223583,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codemod","css","transform"],"created_at":"2024-10-01T15:11:33.107Z","updated_at":"2025-04-15T23:19:16.246Z","avatar_url":"https://github.com/skovy.png","language":"TypeScript","readme":"# :snake: css-codemod\n\n[![npm version](https://img.shields.io/npm/v/css-codemod.svg?style=flat)](https://www.npmjs.com/package/css-codemod)\n\ncss-codemod is a toolkit for running codemods over many CSS files to transform code, powered by [PostCSS](https://postcss.org):\n\n- Any [PostCSS syntax parser and stringifier](https://github.com/postcss/postcss/blob/main/docs/syntax.md) can be added. This extends support for additional syntaxes like SASS and LESS.\n- Any [PostCSS plugin](https://github.com/postcss/postcss/blob/main/docs/plugins.md) can be added. This allows running any plugin as a one-off transform. This can be useful if you want to run a plugin once and remove it from a build tool or convert between syntaxes.\n- Any [PostCSS helpers](https://postcss.org/api/) for working with nodes and the abstract syntax tree can be used to transform CSS arbitrarily to fit your needs.\n\n## Install\n\nThere are a few ways to use css-codemod.\n\nFirst, using [npx](https://www.npmjs.com/package/npx):\n\n```bash\nnpx css-codemod \"./src/**/*.css\" -t ./transform.ts\n```\n\nSecond, install and execute `css-codemod` with a package manager:\n\n```bash\nyarn add -D css-codemod\nyarn css-codemod \"./src/**/*.css\" -t ./transform.ts\n```\n\nThird, globally install `css-codemod`:\n\n```\nyarn add -g css-codemod\ncss-codemod \"./src/**/*.css\" -t ./transform.ts\n```\n\n## Usage (CLI)\n\nThe CLI provides the following options:\n\n```bash\nUsage:\n  $ css-codemod [files]\n\nCommands:\n  [files]  File path to transform. Note glob patterns are supported but must be wrapped in quotes.\n\nFor more info, run any command with the `--help` flag:\n  $ css-codemod --help\n\nOptions:\n  -t, --transform \u003ctransform\u003e  Path to the transform file (default: ./transform.ts)\n  -h, --help                   Display this message\n  -v, --version                Display version number\n\nExamples:\ncss-codemod ./a.css\ncss-codemod ./src/a.css\ncss-codemod \"./src/**/*.css\"\ncss-codemod \"./**/*.css\"\n```\n\nThis will pass the source of all files through the transform function specified with `-t` or `--transform` (defaults to `./transform.ts`). See the following sections for more details on the transform function and API.\n\n## Transform\n\nThe transform function defines the transformation to make to each file. The transform can be written in either JavaScript or TypeScript, but TypeScript is recommended.\n\nThe transform function needs to be a named `transform` export from the transform file.\n\n```ts\n// transform.ts\n\n// Import the `Transform` type to provide type-safety when\n// using and creating a transform function.\nimport { Transform } from 'css-codemod';\n\n// Define a named `transform` export function.\nexport const transform: Transform = (fileInfo, api) =\u003e {\n  // Implement the transform. See below for more details on the API.\n};\n\n// Optionally define a named `parser` export to configure the PostCSS parser.\n// export const parser = ...;\n\n// Optionally define a named `plugins` export to configure PostCSS plugins.\n// export const plugins = [...];\n```\n\n## API\n\n### `Transform`\n\nDefine a transform function.\n\nThis type is provided to explicitly type the exported `transform` function. In general, this should be the only type that needs to be explicitly imported. The expected return value is either a string or `null`.\n\n- When returned a string it will be written back to the original file. - When returned `null`, nothing happens and the original file is skipped.\n\n### `TransformFileInfo`\n\nThe first argument passed to the `transform` function.\n\nIt's an object with metadata about the current file being processed by the transform.\n\n- `path`: the resolved path of the file being transformed.\n- `source`: the file contents source of the file being transformed.\n\n### `TransformAPI`\n\nThe second argument passed to the `transform` function.\n\nIt's an object with helpers provided by `css-codemod` to perform transformations.\n\n- `parse`: parse a raw CSS string into an AST. This returns the root node of the underlying abstract syntax tree. Transformations can be made by making direct mutations to the underlying node. This is performed with [PostCSS](https://postcss.org/) so the returned node is a PostCSS [Root](https://postcss.org/api/#root) node. Refer to the [PostCSS API documentation](https://postcss.org/api/) for documentation on nodes and various helpers.\n- `parseValue`: parse a CSS string [declaration value](https://postcss.org/api/#declaration-value) into a \"mini\" AST. This returns a result with all the nodes representing the string value. This is an alias for the [`postcss-value-parser`](https://github.com/TrySound/postcss-value-parser) package. PostCSS itself doesn't parse values and working with complex string values can be challenging. Converting these string values into nodes when necessary can be useful. There are additional parsers for things like selectors, dimensions, media queries, etc. provided in the [PostCSS documentation for plugins](https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md#step-3-find-nodes). If aliasing any of these would be useful open an issue (or pull request) with an example use case.\n\n### `parser`\n\nDefine the [PostCSS parser](https://postcss.org/api/#parser) to use when parsing the CSS files. This is useful for adding support for additional syntaxes.\n\nTo configure, export `parser` with a PostCSS parser from the transform file.\n\nNote: if you define a `parser` than you almost always want to pass the `stringifier` from the same package to `root.toString(stringifier)`. This will guarantee the output is properly formatted using the same syntax.\n\n### `plugins`\n\nDefine [PostCSS plugins]() to use when parsing the CSS files. This is useful for running plugins one-off, for example to upgrade syntax or perform other transformations already provided as plugins. Creating a custom plugin is one way that transform logic can be shared with other PostCSS tools and `css-codemod`. If you only want to share the codemod, then creating a transform file and sharing it is another option that requires less setup from others.\n\nTo configure, export `plugins` with an array of PostCSS plugins from the transform file.\n\n### Example\n\n```ts\n// transform.ts\n\nimport { Transform } from 'css-codemod';\n// Example PostCSS syntax extension. This isn't required.\nimport { parse, stringify } from 'postcss-scss';\n// Example PostCSS plugin. This isn't required.\nimport calc from 'postcss-calc';\n\nexport const transform: Transform = (fileInfo, api) =\u003e {\n  // Convert the file source into an AST using the provided helper.\n  const root = api.parse(fileInfo.source);\n\n  // Use PostCSS helpers to walk through each descendant node\n  //   Docs: https://postcss.org/api/#root-walk\n  root.walk(node =\u003e {\n    // Example logic to change all `color` declarations to have\n    // a value of red.\n    //\n    // For example:\n    //   `color: green;` -\u003e `color: red;`\n    //   `color: #fff;` -\u003e `color: red;`\n    //   `color: rgb(0, 0, 0);` -\u003e `color: red;`\n    if (node.type === 'decl' \u0026\u0026 node.prop === 'color') {\n      node.value = 'red';\n    }\n  });\n\n  // Convert the mutated AST back into a string.\n  // Since a string is returned this will be written back to the file.\n  //\n  // Note: in this example the `postcss-scss` package is used to add\n  // SCSS syntax support. The stringifier is passed when we call `toString` to\n  // re-output valid SCSS syntax.\n  return root.toString(stringify);\n};\n\n// Note: in this example the `postcss-scss` package is used to add SCSS syntax support.\n// This configures PostCSS to correctly parse SCSS syntax.\n//   API docs: https://postcss.org/api/#parser\n//   Syntax docs: https://github.com/postcss/postcss/blob/main/docs/syntax.md\nexport const parser = parse;\n\n// Note: in this example the `postcss-calc` package is used to compute `calc` expressions.\n// This is used only as an example.\n//   API docs: https://postcss.org/api/#acceptedplugin\n//   Plugin docs: https://github.com/postcss/postcss/blob/main/docs/plugins.md\nexport const plugins = [calc({})];\n```\n\nFor more examples, see the [codemod recipes](https://github.com/skovy/css-codemod/tree/main/recipes).\n\n### PostCSS\n\n[PostCSS](https://postcss.org) is the core tool used for performing code transformations. As a result, much of it's API is re-surfaced in this toolkit and will link to it's documentation.\n\n### AST Explorer\n\n[AST Explorer](https://astexplorer.net) is recommended when working on transforms. Change the language to \"CSS\" and the parser to \"postcss\" to see the underlying abstract syntax tree for a given snippet of CSS. This makes it much easier to understand the transformations that need to be made.\n\n## Motivation\n\ncss-codemod is inspired by tools like [`jscodeshift`](https://github.com/facebook/jscodeshift) to streamline CSS transformations whether it be an evolving codebase, or adopting newer syntax.\n\nRead [CSS codemods with PostCSS](https://www.skovy.dev/blog/css-codemods-with-postcss) for a conceptual overview of how this toolkit works and the initial motivation.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskovy%2Fcss-codemod","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskovy%2Fcss-codemod","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskovy%2Fcss-codemod/lists"}