├── .prettierignore ├── pnpm-workspace.yaml ├── packages ├── examples │ ├── env.d.ts │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── main.ts │ │ ├── App.vue │ │ ├── App.vue.original │ │ └── App.vue.magrated │ ├── tsconfig.json │ ├── tsconfig.app.json │ ├── vite.config.ts │ ├── index.html │ ├── tsconfig.node.json │ ├── package.json │ └── migration │ │ ├── index.js │ │ ├── 001_RegexpExamples.js │ │ ├── 002_AstManipulateExamples.js │ │ └── 003_MagicStringExamples.js └── vue-service-bay │ ├── tsconfig.json │ ├── src │ ├── helper.ts │ ├── index.ts │ ├── languages │ │ ├── style.spec.ts │ │ ├── template.spec.ts │ │ ├── script.ts │ │ ├── script.spec.ts │ │ ├── style.ts │ │ └── template.ts │ ├── save.ts │ └── parse.ts │ ├── CHANGELOG.md │ ├── package.json │ └── README.md ├── .changeset └── config.json ├── package.json ├── renovate.json ├── .github └── workflows │ ├── ci.yaml │ └── release.yml ├── LICENSE ├── .gitignore ├── README.md └── pnpm-lock.yaml /.prettierignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" 3 | -------------------------------------------------------------------------------- /packages/examples/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/examples/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flyle-io/vue-service-bay/HEAD/packages/examples/public/favicon.ico -------------------------------------------------------------------------------- /packages/examples/src/main.ts: -------------------------------------------------------------------------------- 1 | import "./assets/main.css"; 2 | 3 | import { createApp } from "vue"; 4 | import App from "./App.vue"; 5 | 6 | createApp(App).mount("#app"); 7 | -------------------------------------------------------------------------------- /packages/vue-service-bay/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/strictest/tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "module": "Node16", 6 | }, 7 | "exclude": ["node_modules", "dist", "**/*.spec.ts"], 8 | } 9 | -------------------------------------------------------------------------------- /packages/examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.node.json" 6 | }, 7 | { 8 | "path": "./tsconfig.app.json" 9 | } 10 | ], 11 | "compilerOptions": { 12 | "allowJs": true, 13 | "checkJs": true, 14 | "outDir": "dist" 15 | }, 16 | "include": ["migration/*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/vue-service-bay/src/helper.ts: -------------------------------------------------------------------------------- 1 | import { globby } from "globby"; 2 | import { resolve } from "path"; 3 | 4 | export const getAllVueFiles = async (dir: string): Promise => { 5 | const files = await globby("**/*.vue", { 6 | cwd: dir, 7 | ignore: ["node_modules"], 8 | }); 9 | return files.map((file) => resolve(dir, file)); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/examples/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "exclude": ["src/**/__tests__/*"], 5 | "compilerOptions": { 6 | "composite": true, 7 | "noEmit": false, 8 | "baseUrl": ".", 9 | "paths": { 10 | "@/*": ["./src/*"] 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/examples/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [ 9 | vue(), 10 | ], 11 | resolve: { 12 | alias: { 13 | '@': fileURLToPath(new URL('./src', import.meta.url)) 14 | } 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /packages/examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/examples/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node18/tsconfig.json", 3 | "include": [ 4 | "vite.config.*", 5 | "vitest.config.*", 6 | "cypress.config.*", 7 | "nightwatch.conf.*", 8 | "playwright.config.*" 9 | ], 10 | "compilerOptions": { 11 | "composite": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Bundler", 14 | "types": ["node"] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { 6 | "repo": "flyle-io/vue-service-bay" 7 | } 8 | ], 9 | "commit": false, 10 | "fixed": [], 11 | "linked": [], 12 | "access": "public", 13 | "baseBranch": "main", 14 | "updateInternalDependencies": "patch", 15 | "ignore": [] 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "baseballyama", 3 | "license": "MIT", 4 | "scripts": { 5 | "update:version": "changeset version", 6 | "release": "changeset publish" 7 | }, 8 | "devDependencies": { 9 | "@changesets/changelog-github": "0.5.2", 10 | "@changesets/cli": "2.28.1", 11 | "@tsconfig/strictest": "2.0.8", 12 | "@types/node": "22.13.17", 13 | "prettier": "3.5.3", 14 | "typescript": "5.8.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | ":automergePatch", 6 | ":timezone(Asia/Tokyo)", 7 | "npm:unpublishSafe" 8 | ], 9 | "dependencyDashboard": false, 10 | "schedule": ["after 4am and before 7am every weekday"], 11 | "prConcurrentLimit": 10, 12 | "prHourlyLimit": 0, 13 | "minimumReleaseAge": "3 days", 14 | "major": { 15 | "stabilityDays": 30 16 | }, 17 | "minor": { 18 | "stabilityDays": 7 19 | }, 20 | "patch": { 21 | "stabilityDays": 3 22 | }, 23 | "ignoreTests": false 24 | } 25 | -------------------------------------------------------------------------------- /packages/vue-service-bay/src/index.ts: -------------------------------------------------------------------------------- 1 | import MagicString from "magic-string"; 2 | 3 | export { MagicString }; 4 | export { is as tsNodeIs } from "@babel/types"; 5 | 6 | export { getAllVueFiles } from "./helper.js"; 7 | export type { VueFile } from "./parse.js"; 8 | export { parseVueFile } from "./parse.js"; 9 | export { save, saveAsString } from "./save.js"; 10 | export { 11 | walk as walkTemplate, 12 | manipulate as manipulateHtml, 13 | } from "./languages/template.js"; 14 | export { 15 | walk as walkScript, 16 | manipulate as manipulateScript, 17 | } from "./languages/script.js"; 18 | export { 19 | walk as walkStyle, 20 | manipulate as manipulateStyle, 21 | cssNodeIs, 22 | } from "./languages/style.js"; 23 | -------------------------------------------------------------------------------- /packages/vue-service-bay/src/languages/style.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "vitest"; 2 | import * as scss from "./style.js"; 3 | 4 | describe("scss", () => { 5 | test("basic", async () => { 6 | const vueBlock = { 7 | type: "style", 8 | openTag: '", 11 | } as const; 12 | 13 | await scss.manipulate(vueBlock, (node) => { 14 | if (scss.cssNodeIs("rule", node)) { 15 | if (node.selector === ".foo") { 16 | node.selector = ".baz"; 17 | } 18 | } 19 | }); 20 | expect(vueBlock.body).toBe(".baz { &.bar: { color: red; } }"); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/vue-service-bay/src/save.ts: -------------------------------------------------------------------------------- 1 | import type { VueFile } from "./parse.js"; 2 | import { writeFileSync } from "node:fs"; 3 | 4 | export const saveAsString = (vueFile: VueFile): string => { 5 | let updated = ""; 6 | for (const block of vueFile.blocks) { 7 | const prefix = updated ? "\n\n" : ""; 8 | updated += `${prefix}${block.openTag}${block.body}${block.closeTag}`; 9 | } 10 | return updated; 11 | }; 12 | 13 | export const save = async ( 14 | vueFile: VueFile, 15 | format?: (vueFileAsString: string) => Promise, 16 | ) => { 17 | let updated = saveAsString(vueFile); 18 | if (format) { 19 | updated = await format(updated); 20 | } 21 | writeFileSync(vueFile.filePath, updated); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examples", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "run-p type-check \"build-only {@}\" --", 9 | "preview": "vite preview", 10 | "build-only": "vite build", 11 | "type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false" 12 | }, 13 | "dependencies": { 14 | "vue": "3.5.13" 15 | }, 16 | "devDependencies": { 17 | "vue-service-bay": "*", 18 | "@tsconfig/node18": "18.2.4", 19 | "@types/node": "22.13.14", 20 | "@vitejs/plugin-vue": "5.2.3", 21 | "@vue/tsconfig": "0.7.0", 22 | "npm-run-all2": "7.0.2", 23 | "typescript": "5.8.2", 24 | "vite": "6.2.3", 25 | "vue-tsc": "2.2.8" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main, develop] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | test: 15 | timeout-minutes: 15 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: pnpm/action-setup@v4 20 | with: 21 | version: 10 22 | - uses: actions/setup-node@v4 23 | with: 24 | node-version: 22 25 | cache: "pnpm" 26 | 27 | - name: prebuild 28 | run: pnpm install --frozen-lockfile 29 | 30 | - name: check project 31 | run: cd packages/vue-service-bay && pnpm build && pnpm check:all 32 | -------------------------------------------------------------------------------- /packages/examples/migration/index.js: -------------------------------------------------------------------------------- 1 | import { getAllVueFiles, parseVueFile, save } from "vue-service-bay"; 2 | import regexpExamples from "./001_RegexpExamples.js"; 3 | import astManipulateExamples from "./002_AstManipulateExamples.js"; 4 | import magicStringExamples from "./003_MagicStringExamples.js"; 5 | import { format } from "prettier"; 6 | 7 | /** 8 | * @param {import ('vue-service-bay').VueFile} vueFile 9 | */ 10 | const migrate = (vueFile) => { 11 | regexpExamples(vueFile); 12 | astManipulateExamples(vueFile); 13 | magicStringExamples(vueFile); 14 | }; 15 | 16 | const main = async () => { 17 | const files = await getAllVueFiles("./src"); 18 | for (const file of files) { 19 | const vueFile = await parseVueFile(file); 20 | migrate(vueFile); 21 | save(vueFile, (vueFileAsString) => 22 | format(vueFileAsString, { parser: "vue" }) 23 | ); 24 | } 25 | }; 26 | 27 | void main(); 28 | -------------------------------------------------------------------------------- /packages/vue-service-bay/src/languages/template.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "vitest"; 2 | import * as html from "./template.js"; 3 | 4 | describe("html", () => { 5 | test("basic", async () => { 6 | const vueBlock = { 7 | type: "template", 8 | openTag: "", 11 | } as const; 12 | 13 | html.manipulate(vueBlock, (node) => { 14 | if (node.type === "tag" && node.name === "div") { 15 | node.name = "span"; 16 | node.attribs = { ...node.attribs, class: "foo" }; 17 | } 18 | if (node.type === "text") { 19 | node.data = node.data.toUpperCase(); 20 | } 21 | }); 22 | expect(vueBlock.body).toBe( 23 | 'HELLO', 24 | ); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/vue-service-bay/src/languages/script.ts: -------------------------------------------------------------------------------- 1 | import { parse, print } from "recast"; 2 | import * as tsParser from "recast/parsers/typescript.js"; 3 | import type { Node } from "@babel/types"; 4 | import { walk as zimmerframe } from "zimmerframe"; 5 | import { VueBlock } from "../parse.js"; 6 | 7 | const throwIfNotScript = (block: VueBlock) => { 8 | if (!block.openTag.startsWith(" block is supported."); 10 | } 11 | }; 12 | 13 | const _walk = (block: VueBlock, fn: (node: Node) => void): Node => { 14 | throwIfNotScript(block); 15 | 16 | const ast = parse(block.body, { 17 | parser: tsParser, 18 | }) as Node; 19 | zimmerframe(ast, null, { 20 | _(node, { state, next }) { 21 | fn(node); 22 | next(state); 23 | }, 24 | }); 25 | 26 | return ast; 27 | }; 28 | 29 | export const walk = (block: VueBlock, fn: (node: Node) => void) => { 30 | _walk(block, fn); 31 | }; 32 | 33 | export const manipulate = (block: VueBlock, fn: (node: Node) => void) => { 34 | const ast = _walk(block, fn); 35 | block.body = print(ast).code; 36 | }; 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Flyle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/examples/src/App.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 25 | 26 | 32 | 33 | 61 | -------------------------------------------------------------------------------- /packages/examples/src/App.vue.original: -------------------------------------------------------------------------------- 1 | 5 | 6 | 25 | 26 | 32 | 33 | 61 | -------------------------------------------------------------------------------- /packages/vue-service-bay/src/languages/script.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, test, expect } from "vitest"; 2 | import * as typescript from "./script"; 3 | 4 | describe("typescript", () => { 5 | test("javascript", async () => { 6 | const vueBlock = { 7 | type: "script", 8 | openTag: '", 11 | } as const; 12 | 13 | typescript.manipulate( 14 | { 15 | type: "script", 16 | openTag: '", 19 | }, 20 | (node) => { 21 | return node; 22 | }, 23 | ); 24 | expect(vueBlock.body).toBe('console.log("hello");'); 25 | }); 26 | test("typescript", async () => { 27 | const vueBlock = { 28 | type: "script", 29 | openTag: '", 32 | } as const; 33 | 34 | typescript.manipulate(vueBlock, (node) => { 35 | if (node.type === "Identifier" && node.name === "foo") { 36 | node.name = "bar"; 37 | } 38 | return node; 39 | }); 40 | expect(vueBlock.body).toBe("const bar = (str: string) => str;"); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/vue-service-bay/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # vue-service-bay 2 | 3 | ## 0.2.3 4 | 5 | ### Patch Changes 6 | 7 | - [#192](https://github.com/flyle-io/vue-service-bay/pull/192) [`ed0d3e9`](https://github.com/flyle-io/vue-service-bay/commit/ed0d3e98bc173523a546dfad4b0eb84635b6d5f2) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: update deps 8 | 9 | ## 0.2.2 10 | 11 | ### Patch Changes 12 | 13 | - [`722588b`](https://github.com/flyle-io/vue-service-bay/commit/722588b084685ac05cf5cfefd04b63af1510e484) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: remove unnecessary files from npm 14 | 15 | ## 0.2.1 16 | 17 | ### Patch Changes 18 | 19 | - [`2e2863d`](https://github.com/flyle-io/vue-service-bay/commit/2e2863da4fef865ba36a122952a78d53b1453cda) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: fix README 20 | 21 | ## 0.2.0 22 | 23 | ### Minor Changes 24 | 25 | - [`c1b48d9`](https://github.com/flyle-io/vue-service-bay/commit/c1b48d9c8a167b0f3131ad37b10ee7d1e36a5160) Thanks [@baseballyama](https://github.com/baseballyama)! - feat: Added API to receive migration results as strings 26 | 27 | ## 0.1.0 28 | 29 | ### Minor Changes 30 | 31 | - [`2c1a784`](https://github.com/flyle-io/vue-service-bay/commit/2c1a784407e2fbd10380053ceccf8ff66e34f151) Thanks [@baseballyama](https://github.com/baseballyama)! - feat: Initial version of vue-service-bay 32 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: write 10 | issues: write 11 | pull-requests: write 12 | 13 | jobs: 14 | release: 15 | name: Release 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout Repo 19 | uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | - uses: pnpm/action-setup@v4 23 | with: 24 | version: 10 25 | - uses: actions/setup-node@v4 26 | with: 27 | node-version: 22 28 | cache: "pnpm" 29 | 30 | - name: prebuild 31 | run: pnpm install --frozen-lockfile 32 | 33 | - name: build 34 | run: cd packages/vue-service-bay && pnpm build 35 | 36 | - name: Remove src directory 37 | run: rm -rf packages/vue-service-bay/src 38 | 39 | - name: Copy README.md 40 | run: cp README.md packages/vue-service-bay/README.md 41 | 42 | - name: Create Release Pull Request or Publish to npm 43 | id: changesets 44 | uses: changesets/action@v1 45 | with: 46 | version: pnpm update:version 47 | publish: pnpm release 48 | commit: "chore: release vue-service-bay" 49 | title: "chore: release vue-service-bay" 50 | env: 51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 53 | -------------------------------------------------------------------------------- /packages/vue-service-bay/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-service-bay", 3 | "version": "0.2.3", 4 | "description": "Your One-Stop Solution for Vue.js Refactoring", 5 | "main": "./dist/index.js", 6 | "type": "module", 7 | "types": "./dist/index.d.ts", 8 | "exports": { 9 | "./package.json": "./package.json", 10 | ".": { 11 | "types": "./dist/index.d.ts", 12 | "import": "./dist/index.js" 13 | } 14 | }, 15 | "scripts": { 16 | "dev": "tsc -d -w", 17 | "build": "tsc -d", 18 | "type:check": "tsc --noEmit", 19 | "format:check": "prettier --cache --check \"./src/**/*.{js,ts,vue,json}\"", 20 | "format:fix": "prettier --cache --write \"./src/**/*.{js,ts,vue,json}\"", 21 | "publish:check": "publint", 22 | "test:watch": "vitest", 23 | "check:all": "pnpm type:check && pnpm format:check && pnpm publish:check" 24 | }, 25 | "keywords": [ 26 | "vue", 27 | "vue3", 28 | "ast", 29 | "static analysis", 30 | "code generation", 31 | "code refactor" 32 | ], 33 | "author": "baseballyama", 34 | "license": "MIT", 35 | "devDependencies": { 36 | "publint": "0.3.15", 37 | "vitest": "3.0.9" 38 | }, 39 | "dependencies": { 40 | "@babel/types": "7.27.7", 41 | "dom-serializer": "2.0.0", 42 | "domhandler": "5.0.3", 43 | "globby": "14.1.0", 44 | "htmlparser2": "10.0.0", 45 | "magic-string": "0.30.21", 46 | "postcss": "8.5.6", 47 | "postcss-scss": "4.0.9", 48 | "recast": "0.23.11", 49 | "zimmerframe": "1.1.4" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/examples/src/App.vue.magrated: -------------------------------------------------------------------------------- 1 | 5 | 6 | 27 | 28 | 34 | 35 | 68 | -------------------------------------------------------------------------------- /packages/vue-service-bay/src/languages/style.ts: -------------------------------------------------------------------------------- 1 | import postcss, { 2 | Node, 3 | AtRule, 4 | Rule, 5 | Declaration, 6 | Comment, 7 | ChildNode, 8 | } from "postcss"; 9 | import * as postcssScss from "postcss-scss"; 10 | import { VueBlock } from "../parse.js"; 11 | 12 | type InferNode = T extends "atrule" 13 | ? AtRule 14 | : T extends "rule" 15 | ? Rule 16 | : T extends "decl" 17 | ? Declaration 18 | : T extends "comment" 19 | ? Comment 20 | : never; 21 | 22 | export const cssNodeIs = ( 23 | type: T, 24 | node: Node, 25 | ): node is InferNode => { 26 | return node.type === type; 27 | }; 28 | 29 | const throwIfNotStyle = (block: VueBlock) => { 30 | if (!block.openTag.startsWith(" block is supported."); 32 | } 33 | }; 34 | 35 | const _walk = ( 36 | block: VueBlock, 37 | fn: (node: ChildNode) => void, 38 | ): postcss.LazyResult => { 39 | throwIfNotStyle(block); 40 | 41 | const style = block.body; 42 | 43 | const syntax = postcssScss; 44 | 45 | const ast = postcss().process(style, { 46 | syntax, 47 | from: "", 48 | }); 49 | 50 | ast.root.walk((node) => { 51 | fn(node); 52 | }); 53 | 54 | return ast; 55 | }; 56 | 57 | export const walk = (block: VueBlock, fn: (node: ChildNode) => void) => { 58 | _walk(block, fn); 59 | }; 60 | 61 | export const manipulate = ( 62 | block: VueBlock, 63 | fn: (node: ChildNode) => void, 64 | ): void => { 65 | const ast = _walk(block, fn); 66 | block.body = ast.root.toString(); 67 | }; 68 | -------------------------------------------------------------------------------- /packages/examples/migration/001_RegexpExamples.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {import ('vue-service-bay').VueFile} vueFile 3 | */ 4 | export default (vueFile) => { 5 | for (const block of vueFile.blocks) { 6 | if (block.type === "template") { 7 | // ---------------------------------------------------------------------- 8 | //