Fixes types for code editor

This commit is contained in:
Steve Ruiz 2021-06-25 13:09:53 +01:00
parent 000d029354
commit 776c0b5f0e
7 changed files with 415 additions and 35 deletions

View file

@ -2,6 +2,181 @@
exports[`selection creates a code control: generated code controls from code 1`] = `Object {}`; exports[`selection creates a code control: generated code controls from code 1`] = `Object {}`;
exports[`selection generates a draw shape: generated draw from code 1`] = `
Array [
Object {
"childIndex": 1,
"id": "test-draw",
"isAspectRatioLocked": false,
"isGenerated": true,
"isHidden": false,
"isLocked": false,
"name": "Test draw",
"parentId": "page1",
"point": Array [
0,
0,
],
"points": Array [
Array [
100,
100,
],
Array [
200,
200,
],
Array [
300,
300,
],
],
"rotation": 0,
"style": Object {
"color": "Red",
"dash": "Dotted",
"isFilled": false,
"size": "Medium",
},
"type": "draw",
},
]
`;
exports[`selection generates a rectangle shape: generated rectangle from code 1`] = `
Array [
Object {
"childIndex": 1,
"id": "test-rectangle",
"isAspectRatioLocked": false,
"isGenerated": true,
"isHidden": false,
"isLocked": false,
"name": "Test Rectangle",
"parentId": "page1",
"point": Array [
100,
100,
],
"radius": 2,
"rotation": 0,
"size": Array [
200,
200,
],
"style": Object {
"color": "Red",
"dash": "Dotted",
"isFilled": false,
"size": "Medium",
},
"type": "rectangle",
},
]
`;
exports[`selection generates an arrow shape: generated draw from code 1`] = `
Array [
Object {
"bend": 0,
"childIndex": 1,
"decorations": Object {
"end": "Arrow",
"middle": null,
"start": null,
},
"handles": Object {
"bend": Object {
"id": "bend",
"index": 2,
"point": Array [
0,
0,
],
},
"end": Object {
"id": "end",
"index": 1,
"point": Array [
0,
0,
],
},
"start": Object {
"id": "start",
"index": 0,
"point": Array [
0,
0,
],
},
},
"id": "test-draw",
"isAspectRatioLocked": false,
"isGenerated": true,
"isHidden": false,
"isLocked": false,
"name": "Test draw",
"parentId": "page1",
"point": Array [
0,
0,
],
"points": Array [
Array [
100,
100,
],
Array [
200,
200,
],
Array [
300,
300,
],
],
"rotation": 0,
"style": Object {
"color": "Red",
"dash": "Dotted",
"isFilled": false,
"size": "Medium",
},
"type": "arrow",
},
]
`;
exports[`selection generates an ellipse shape: generated ellipse from code 1`] = `
Array [
Object {
"childIndex": 1,
"id": "test-ellipse",
"isAspectRatioLocked": false,
"isGenerated": true,
"isHidden": false,
"isLocked": false,
"name": "Test ellipse",
"parentId": "page1",
"point": Array [
100,
100,
],
"radiusX": 100,
"radiusY": 200,
"rotation": 0,
"style": Object {
"color": "Red",
"dash": "Dotted",
"isFilled": false,
"size": "Medium",
},
"type": "ellipse",
},
]
`;
exports[`selection generates shapes: generated rectangle from code 1`] = ` exports[`selection generates shapes: generated rectangle from code 1`] = `
Array [ Array [
Object { Object {

View file

@ -131,5 +131,142 @@ describe('selection', () => {
expect(state.data.document.code[state.data.currentCodeFileId].code).toBe( expect(state.data.document.code[state.data.currentCodeFileId].code).toBe(
code code
) )
state.send('TOGGLED_READ_ONLY').send('SAVED_CODE', { code: '' })
expect(state.data.document.code[state.data.currentCodeFileId].code).toBe('')
})
/* --------------------- Methods -------------------- */
it('moves shape to front', async () => {
null
})
it('moves shape forward', async () => {
null
})
it('moves shape backward', async () => {
null
})
it('moves shape to back', async () => {
null
})
it('rotates a shape', async () => {
null
})
it('rotates a shape by a delta', async () => {
null
})
it('translates a shape', async () => {
null
})
it('translates a shape by a delta', async () => {
null
})
/* --------------------- Shapes --------------------- */
it('generates a rectangle shape', async () => {
state.send('CLEARED_PAGE')
const code = `
const rectangle = new Rectangle({
id: "test-rectangle",
name: 'Test Rectangle',
point: [100, 100],
size: [200, 200],
style: {
size: SizeStyle.Medium,
color: ColorStyle.Red,
dash: DashStyle.Dotted,
},
})
`
const { controls, shapes } = await generateFromCode(state.data, code)
state.send('GENERATED_FROM_CODE', { controls, shapes })
expect(getShapes(state.data)).toMatchSnapshot(
'generated rectangle from code'
)
})
it('changes a rectangle size', async () => {
null
})
it('generates an ellipse shape', async () => {
state.send('CLEARED_PAGE')
const code = `
const ellipse = new Ellipse({
id: 'test-ellipse',
name: 'Test ellipse',
point: [100, 100],
radiusX: 100,
radiusY: 200,
style: {
size: SizeStyle.Medium,
color: ColorStyle.Red,
dash: DashStyle.Dotted,
},
})
`
const { controls, shapes } = await generateFromCode(state.data, code)
state.send('GENERATED_FROM_CODE', { controls, shapes })
expect(getShapes(state.data)).toMatchSnapshot('generated ellipse from code')
})
it('generates a draw shape', async () => {
state.send('CLEARED_PAGE')
const code = `
const ellipse = new Draw({
id: 'test-draw',
name: 'Test draw',
points: [[100, 100], [200,200], [300,300]],
style: {
size: SizeStyle.Medium,
color: ColorStyle.Red,
dash: DashStyle.Dotted,
},
})
`
const { controls, shapes } = await generateFromCode(state.data, code)
state.send('GENERATED_FROM_CODE', { controls, shapes })
expect(getShapes(state.data)).toMatchSnapshot('generated draw from code')
})
it('generates an arrow shape', async () => {
state.send('CLEARED_PAGE')
const code = `
const ellipse = new Arrow({
id: 'test-draw',
name: 'Test draw',
points: [[100, 100], [200,200], [300,300]],
style: {
size: SizeStyle.Medium,
color: ColorStyle.Red,
dash: DashStyle.Dotted,
},
})
`
const { controls, shapes } = await generateFromCode(state.data, code)
state.send('GENERATED_FROM_CODE', { controls, shapes })
expect(getShapes(state.data)).toMatchSnapshot('generated draw from code')
}) })
}) })

View file

@ -43,7 +43,9 @@ export default function CodeEditor({
const rMonaco = useRef<IMonaco>(null) const rMonaco = useRef<IMonaco>(null)
const handleBeforeMount = useCallback((monaco: Monaco) => { const handleBeforeMount = useCallback((monaco: Monaco) => {
if (monacoRef) monacoRef.current = monaco if (monacoRef) {
monacoRef.current = monaco
}
rMonaco.current = monaco rMonaco.current = monaco
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
@ -52,26 +54,37 @@ export default function CodeEditor({
strict: false, strict: false,
noLib: true, noLib: true,
lib: ['es6'], lib: ['es6'],
target: monaco.languages.typescript.ScriptTarget.ES2015, target: monaco.languages.typescript.ScriptTarget.ES2016,
allowNonTsExtensions: true, allowNonTsExtensions: true,
}) })
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
allowJs: true, allowJs: true,
checkJs: false, checkJs: true,
strict: false, strict: true,
noLib: true, noLib: true,
lib: ['es6'], lib: ['es6'],
target: monaco.languages.typescript.ScriptTarget.ES2015, target: monaco.languages.typescript.ScriptTarget.ES2016,
allowNonTsExtensions: true, allowNonTsExtensions: true,
}) })
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true) monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true)
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true) monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true)
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
noSemanticValidation: false,
noSyntaxValidation: false,
})
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
noSemanticValidation: false,
noSyntaxValidation: false,
})
monaco.languages.typescript.typescriptDefaults.addExtraLib( monaco.languages.typescript.typescriptDefaults.addExtraLib(
typesImport.content typesImport.content
) )
monaco.languages.typescript.javascriptDefaults.addExtraLib( monaco.languages.typescript.javascriptDefaults.addExtraLib(
typesImport.content typesImport.content
) )

View file

@ -1,3 +1,5 @@
/* eslint-disable */
// HEY! DO NOT MODIFY THIS FILE. THE CONTENTS OF THIS FILE // HEY! DO NOT MODIFY THIS FILE. THE CONTENTS OF THIS FILE
// ARE AUTO-GENERATED BY A SCRIPT AT: /scripts/type-gen.js // ARE AUTO-GENERATED BY A SCRIPT AT: /scripts/type-gen.js
// ANY CHANGES WILL BE LOST WHEN THE SCRIPT RUNS AGAIN! // ANY CHANGES WILL BE LOST WHEN THE SCRIPT RUNS AGAIN!
@ -5,7 +7,14 @@
export default { export default {
name: 'types.ts', name: 'types.ts',
content: ` content: `
type Partial<T> = { [P in keyof T]?: T[P]; };
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
@ -141,8 +150,12 @@ interface GroupShape extends BaseShape {
size: number[] size: number[]
} }
type ShapeProps<T extends Shape> = Partial<Omit<T, 'style'>> & { // type DeepPartial<T> = {
style?: Partial<ShapeStyles> // [P in keyof T]?: DeepPartial<T[P]>
// }
type ShapeProps<T extends Shape> = {
[P in keyof T]?: P extends 'style' ? Partial<T[P]> : T[P]
} }
type MutableShape = type MutableShape =
@ -1240,10 +1253,10 @@ interface ShapeUtility<K extends Shape> {
P: number[], P: number[],
side: number side: number
): number[] { ): number[] {
const B = vec.lrp(C, P, 0.5), const B = Vec.lrp(C, P, 0.5),
r1 = vec.dist(C, B), r1 = Vec.dist(C, B),
delta = vec.sub(B, C), delta = Vec.sub(B, C),
d = vec.len(delta) d = Vec.len(delta)
if (!(d <= r + r1 && d >= Math.abs(r - r1))) { if (!(d <= r + r1 && d >= Math.abs(r - r1))) {
return return
@ -1251,11 +1264,11 @@ interface ShapeUtility<K extends Shape> {
const a = (r * r - r1 * r1 + d * d) / (2.0 * d), const a = (r * r - r1 * r1 + d * d) / (2.0 * d),
n = 1 / d, n = 1 / d,
p = vec.add(C, vec.mul(delta, a * n)), p = Vec.add(C, Vec.mul(delta, a * n)),
h = Math.sqrt(r * r - a * a), h = Math.sqrt(r * r - a * a),
k = vec.mul(vec.per(delta), h * n) k = Vec.mul(Vec.per(delta), h * n)
return side === 0 ? vec.add(p, k) : vec.sub(p, k) return side === 0 ? Vec.add(p, k) : Vec.sub(p, k)
} }
/** /**
@ -1274,8 +1287,8 @@ interface ShapeUtility<K extends Shape> {
C1: number[], C1: number[],
r1: number r1: number
): number[][] { ): number[][] {
const a0 = vec.angle(C0, C1) const a0 = Vec.angle(C0, C1)
const d = vec.dist(C0, C1) const d = Vec.dist(C0, C1)
// Circles are overlapping, no tangents // Circles are overlapping, no tangents
if (d < Math.abs(r1 - r0)) return if (d < Math.abs(r1 - r0)) return
@ -1303,8 +1316,8 @@ interface ShapeUtility<K extends Shape> {
r: number, r: number,
P: number[] P: number[]
): number[] { ): number[] {
const v = vec.sub(C, P) const v = Vec.sub(C, P)
return vec.sub(C, vec.mul(vec.div(v, vec.len(v)), r)) return Vec.sub(C, Vec.mul(Vec.div(v, Vec.len(v)), r))
} }
static det( static det(
@ -1433,7 +1446,7 @@ interface ShapeUtility<K extends Shape> {
* @param B * @param B
*/ */
static getSweep(C: number[], A: number[], B: number[]): number { static getSweep(C: number[], A: number[], B: number[]): number {
return Utils.angleDelta(vec.angle(C, A), vec.angle(C, B)) return Utils.angleDelta(Vec.angle(C, A), Vec.angle(C, B))
} }
/** /**
@ -1571,7 +1584,7 @@ interface ShapeUtility<K extends Shape> {
return Array.from(Array(steps)) return Array.from(Array(steps))
.map((_, i) => ease(i / steps)) .map((_, i) => ease(i / steps))
.map((t) => [...vec.lrp(a, b, t), (1 - t) / 2]) .map((t) => [...Vec.lrp(a, b, t), (1 - t) / 2])
} }
static getRayRayIntersection( static getRayRayIntersection(
@ -1580,8 +1593,8 @@ interface ShapeUtility<K extends Shape> {
p1: number[], p1: number[],
n1: number[] n1: number[]
): number[] { ): number[] {
const p0e = vec.add(p0, n0), const p0e = Vec.add(p0, n0),
p1e = vec.add(p1, n1), p1e = Vec.add(p1, n1),
m0 = (p0e[1] - p0[1]) / (p0e[0] - p0[0]), m0 = (p0e[1] - p0[1]) / (p0e[0] - p0[0]),
m1 = (p1e[1] - p1[1]) / (p1e[0] - p1[0]), m1 = (p1e[1] - p1[1]) / (p1e[0] - p1[0]),
b0 = p0[1] - m0 * p0[0], b0 = p0[1] - m0 * p0[0],
@ -2470,6 +2483,20 @@ class VectorControl extends Control<VectorCodeControl> {
} }
declare const controls: {[key:string]: any} = {} const codeShapes = new Set<CodeShape<any>>()
const controls: Record<string, any> = {}
const defaultStyle: ShapeStyles = {
color: ColorStyle.Black,
size: SizeStyle.Medium,
isFilled: false,
dash: DashStyle.Solid,
}
const uniqueId = () => ''
const codeControls = new Set([])
declare function createShape(type: ShapeType, shape: Shape): any
declare function getShapeUtils<T>(shape: T): any
declare function getOrderedShapes(): CodeShape<any>[]
`, `,
} }

View file

@ -27,6 +27,7 @@ async function inlineFileContents(path) {
.replaceAll('/* ----------------- Start Copy Here ---------------- */', '') .replaceAll('/* ----------------- Start Copy Here ---------------- */', '')
.replaceAll('export default', '') .replaceAll('export default', '')
.replaceAll('export ', '') .replaceAll('export ', '')
.replaceAll('vec.', 'Vec.')
} }
async function copyTypesToFile() { async function copyTypesToFile() {
@ -34,15 +35,24 @@ async function copyTypesToFile() {
const content = const content =
` `
// HEY! DO NOT MODIFY THIS FILE. THE CONTENTS OF THIS FILE /* eslint-disable */
// ARE AUTO-GENERATED BY A SCRIPT AT: /scripts/type-gen.js
// ANY CHANGES WILL BE LOST WHEN THE SCRIPT RUNS AGAIN!
export default {` + // HEY! DO NOT MODIFY THIS FILE. THE CONTENTS OF THIS FILE
// ARE AUTO-GENERATED BY A SCRIPT AT: /scripts/type-gen.js
// ANY CHANGES WILL BE LOST WHEN THE SCRIPT RUNS AGAIN!
export default {` +
` `
name: "types.ts", name: "types.ts",
content: \` content: \`
type Partial<T> = { [P in keyof T]?: T[P]; };
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
${await inlineFileContents('/types.ts')} ${await inlineFileContents('/types.ts')}
@ -72,7 +82,21 @@ ${await inlineFileContents('/state/code/rectangle.ts')}
${await inlineFileContents('/state/code/control.ts')} ${await inlineFileContents('/state/code/control.ts')}
declare const controls: {[key:string]: any} = {} const codeShapes = new Set<CodeShape<any>>()
const controls: Record<string, any> = {}
const defaultStyle: ShapeStyles = {
color: ColorStyle.Black,
size: SizeStyle.Medium,
isFilled: false,
dash: DashStyle.Solid,
}
const uniqueId = () => ''
const codeControls = new Set([])
declare function createShape(type: ShapeType, shape: Shape): any
declare function getShapeUtils<T>(shape: T): any
declare function getOrderedShapes(): CodeShape<any>[]
\`}` \`}`
await fs.writeFile( await fs.writeFile(

View file

@ -85,7 +85,7 @@ export function getShapeStyle(
} }
} }
export const defaultStyle = { export const defaultStyle: ShapeStyles = {
color: ColorStyle.Black, color: ColorStyle.Black,
size: SizeStyle.Medium, size: SizeStyle.Medium,
isFilled: false, isFilled: false,

View file

@ -191,8 +191,12 @@ export interface GroupShape extends BaseShape {
size: number[] size: number[]
} }
export type ShapeProps<T extends Shape> = Partial<Omit<T, 'style'>> & { // type DeepPartial<T> = {
style?: Partial<ShapeStyles> // [P in keyof T]?: DeepPartial<T[P]>
// }
export type ShapeProps<T extends Shape> = {
[P in keyof T]?: P extends 'style' ? Partial<T[P]> : T[P]
} }
export type MutableShape = export type MutableShape =