Skip to content

Commit

Permalink
FEAT: Usage comment prefix (#36)
Browse files Browse the repository at this point in the history
* Added usage comment functionality to core package

* Added usage comment to the generated code

* docs(changeset): Added usage comment prefix

* Updated changeset workflow

* Added ignore paths

* Updated ignore glob

* Removed test commands from figma package

* Disabled fail on error
  • Loading branch information
bring-shrubbery authored Oct 29, 2023
1 parent 0ec8a29 commit 640c289
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 71 deletions.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
"ignore": ["figma-to-swiftui", "tsconfig", "nextjs"]
}
6 changes: 6 additions & 0 deletions .changeset/rotten-trains-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"svg-to-swiftui-core": patch
"figma-to-swiftui": patch
---

Added usage comment prefix
2 changes: 1 addition & 1 deletion .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ jobs:
with:
token: ${{ secrets.CODECOV_TOKEN }}
name: codecov-umbrella
fail_ci_if_error: true
fail_ci_if_error: false
verbose: true
26 changes: 26 additions & 0 deletions packages/figma-to-swiftui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Figma to SwiftUI Converter

## Overview

This plugin lets you export paths from Figma to SwiftUI Shape structure.

## How to use

- Select the vector object that you want to convert.
- Make sure you **select the specific vector path** that you want to convert.
- Open Figma DEV mode.
- Select SwiftUI Code Generator from the language export options.
- Copy code and paste it into your SwiftUI project!

## Links

- Visit Web App version of this converter [here](https://dub.sh/svg-to-swiftui).
- Need help with developing your designs? Visit my development agency [Quassum](https://dub.sh/quassum)!
- Made by [Antoni](https://dub.sh/antoni)

## Community

Wanna suggest some changes or just to say hi? Join our community here:

- [Github Discussions](https://github.com/quassum/SVG-to-SwiftUI/discussions)
- [Quassum Discord](https://discord.gg/VzpZ7np622)
2 changes: 0 additions & 2 deletions packages/figma-to-swiftui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
"scripts": {
"build": "tsup src/index.ts --format iife --target es5",
"clean": "rimraf dist",
"test": "jest",
"coverage": "jest --ci --coverage",
"lint": "eslint ./src/**/*",
"lint:fix": "eslint ./src/**/* --fix",
"format": "prettier --write ./src --loglevel error"
Expand Down
1 change: 1 addition & 0 deletions packages/figma-to-swiftui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ if (figma.editorType === "dev" && figma.mode === "codegen") {

const swiftUI = convert(SVG_TEMPLATE, {
structName: node.name.replace(/\s/g, ""),
usageCommentPrefix: true,
});

return [
Expand Down
115 changes: 73 additions & 42 deletions packages/svg-to-swiftui-core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { ElementNode, parse } from "svg-parser";
import { generateSwiftUIShape } from "./stubs";
import { SwiftUIGeneratorConfig, TranspilerOptions } from "./types";
import {ElementNode, parse} from 'svg-parser';
import {SwiftUIGeneratorConfig, TranspilerOptions} from './types';

import { handleElement } from "./elementHandlers";
import { extractSVGProperties, getSVGElement } from "./utils";
import { DEFAULT_CONFIG } from "./constants";
import {handleElement} from './elementHandlers';
import {extractSVGProperties, getSVGElement} from './utils';
import {DEFAULT_CONFIG} from './constants';
import {
createFunctionTemplate,
createStructTemplate,
createUsageCommentTemplate,
} from './templates';

export * from "./types";
export * from './types';

/**
* This function converts SVG string into SwiftUI
Expand All @@ -15,18 +19,18 @@ export * from "./types";
* @param config Optional configuration object.
*/
export function convert(
rawSVGString: string,
config?: SwiftUIGeneratorConfig,
rawSVGString: string,
config?: SwiftUIGeneratorConfig
): string {
const AST = parse(rawSVGString);
const svgElement = getSVGElement(AST);
if (svgElement) {
return swiftUIGenerator(svgElement, config);
} else {
throw new Error(
"Could not find SVG element, please provide full SVG source!",
);
}
const AST = parse(rawSVGString);
const svgElement = getSVGElement(AST);
if (svgElement) {
return swiftUIGenerator(svgElement, config);
} else {
throw new Error(
'Could not find SVG element, please provide full SVG source!'
);
}
}

/**
Expand All @@ -35,29 +39,56 @@ export function convert(
* @param config Optional configuration object.
*/
function swiftUIGenerator(
svgElement: ElementNode,
config?: SwiftUIGeneratorConfig,
svgElement: ElementNode,
config?: SwiftUIGeneratorConfig
): string {
const svgProperties = extractSVGProperties(svgElement);

// The initial options passed to the first element.
const rootTranspilerOptions: TranspilerOptions = {
...svgProperties,
precision: config?.precision || 10,
lastPathId: 0,
indentationSize: config?.indentationSize || 4,
currentIndentationLevel: 0,
parentStyle: {},
};

// Generate SwiftUI Shape body.
const generatedBody = handleElement(svgElement, rootTranspilerOptions);

// Inject generated body into the Shape struct template.
const fullSwiftUIShape = generateSwiftUIShape(generatedBody, {
...DEFAULT_CONFIG,
...config,
});

return fullSwiftUIShape;
const svgProperties = extractSVGProperties(svgElement);

// The initial options passed to the first element.
const rootTranspilerOptions: TranspilerOptions = {
...svgProperties,
precision: config?.precision || 10,
lastPathId: 0,
indentationSize: config?.indentationSize || 4,
currentIndentationLevel: 0,
parentStyle: {},
};

const configWithDefaults = {
...DEFAULT_CONFIG,
...config,
};

// Generate SwiftUI Shape body.
const generatedBody = handleElement(svgElement, rootTranspilerOptions);

const fullSwiftUIShape = createStructTemplate({
name: configWithDefaults.structName!,
indent: configWithDefaults.indentationSize,
returnType: 'Shape',
body: createFunctionTemplate({
name: 'path',
parameters: [['in rect', 'CGRect']],
returnType: 'Path',
indent: configWithDefaults.indentationSize,
body: [
'var path = Path()',
'let width = rect.size.width',
'let height = rect.size.height',
...generatedBody,
'return path',
],
}),
});

if (config?.usageCommentPrefix) {
const usageComment = createUsageCommentTemplate({
config,
viewBox: svgProperties.viewBox,
});

return [...usageComment, '', ...fullSwiftUIShape].join('\n');
}

return fullSwiftUIShape.join('\n');
}
25 changes: 0 additions & 25 deletions packages/svg-to-swiftui-core/src/stubs.ts

This file was deleted.

63 changes: 63 additions & 0 deletions packages/svg-to-swiftui-core/src/templates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {SwiftUIGeneratorConfig, ViewBoxData} from './types';

export const createUsageCommentTemplate = ({
config,
viewBox,
}: {
config: SwiftUIGeneratorConfig;
viewBox: ViewBoxData;
}) => [
'// To use this shape, just add it to your SwiftUI View:',
`// ${config.structName}().fill().frame(width: ${viewBox.width}, height: ${viewBox.height})`,
];

type ParameterName = string;
type ParameterType = string;

const indentStrings = ({indent, body}: {indent: number; body: string[]}) => {
return body.map(row => `${new Array(indent).fill(' ').join('')}${row}`);
};

const parametersToStrings = (parameters: [ParameterName, ParameterType][]) => {
return parameters.map(([name, type]) => `${name}: ${type}`).join(', ');
};

export const createFunctionTemplate = ({
name,
parameters,
returnType,
body,
indent = 4,
}: {
name: string;
parameters: [ParameterName, ParameterType][];
returnType: string;
body: string[];
indent?: number;
}) => {
const parametersString = parametersToStrings(parameters);

return [
`func ${name}(${parametersString}) -> ${returnType} {`,
...indentStrings({body, indent}),
`}`,
];
};

export const createStructTemplate = ({
name,
returnType,
body,
indent = 4,
}: {
name: string;
returnType: string;
body: string[];
indent?: number;
}) => {
return [
`struct ${name}: ${returnType} {`,
...indentStrings({body, indent}),
`}`,
];
};
3 changes: 3 additions & 0 deletions packages/svg-to-swiftui-core/src/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ test('conversion-1', () => {
test('convert-circle', () => {
const rawSVG = loadContentFile('circle.svg');
const expectedResult = loadContentFile('circle.swift');

const result = convert(rawSVG, {
precision: 2,
structName: 'CircleShape',
});
console.log('expectedResult', expectedResult);
console.log('result', result);
expect(result).toBe(expectedResult);
});

Expand Down
1 change: 1 addition & 0 deletions packages/svg-to-swiftui-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface SwiftUIGeneratorConfig {
structName?: string;
precision?: number;
indentationSize?: number;
usageCommentPrefix?: boolean;
}

export interface TranspilerOptions {
Expand Down

0 comments on commit 640c289

Please sign in to comment.