From 6d763a7f9dffcfde14d4c2248a1776e156a262ab Mon Sep 17 00:00:00 2001 From: Stefan Zerkalica Date: Sat, 4 Nov 2023 21:58:46 +0300 Subject: [PATCH] $mol_view_tree2_to_dts improved checking --- view/tree2/to/dts/dts.ts | 336 +++++++++++------- view/tree2/to/js/js.ts | 14 +- ...array_channel_of_array_or_object.view.tree | 7 +- view/tree2/to/js/test/ex/array_slot.view.tree | 8 +- .../test/ex/structural_complex_key.view.tree | 8 + view/tree2/to/js/test/js.array.test.ts | 6 +- view/tree2/to/js/test/js.bidi.test.ts | 18 +- view/tree2/to/js/test/js.structural.test.ts | 14 + 8 files changed, 262 insertions(+), 149 deletions(-) create mode 100644 view/tree2/to/js/test/ex/structural_complex_key.view.tree diff --git a/view/tree2/to/dts/dts.ts b/view/tree2/to/dts/dts.ts index a8ccecff9b9..9de5e0d87ab 100644 --- a/view/tree2/to/dts/dts.ts +++ b/view/tree2/to/dts/dts.ts @@ -1,6 +1,16 @@ namespace $ { function name_of(this: $, prop: $mol_tree2) { - return this.$mol_view_tree2_prop_parts(prop).name + const name = prop.type + ? this.$mol_view_tree2_prop_parts(prop).name + : prop.value + + if (! name) { + this.$mol_fail( + $mol_view_tree2_error_str`Required valid prop name at ${prop.span}` + ) + } + + return prop.data(name) } function params_of( this: $, prop: $mol_tree2, ... val: $mol_tree2[] ) { @@ -10,8 +20,8 @@ namespace $ { return prop.struct( 'line', [ prop.data('( '), ... key ? [ - prop.data( 'id' ), - prop.data(': any, '), + prop.data( 'id: ant' ), + prop.data('any, '), ] : [], ... next ? [ prop.data( 'next' ), @@ -23,7 +33,49 @@ namespace $ { ] ) } - + + function param_of(this: $, klass: $mol_tree2, input: $mol_tree2, index = 0) { + return [ + input.data( 'Parameters< ' ), + klass.data( klass.type ), + input.data( '["' ), + name_of.call(this, input ), + input.data( `"] >[${index}]` ), + ] + } + + function return_type_raw(this: $, klass: $mol_tree2, input: $mol_tree2) { + return [ + input.data( 'ReturnType< ' ), + klass, + input.data( '["' ), + input, + input.data( '"] >' ), + ] + } + + function return_type(this: $, klass: $mol_tree2, input: $mol_tree2) { + return return_type_raw.call(this, klass.data( klass.type ), name_of.call(this, input )) + } + + function bind_res( this: $, klass: $mol_tree2, bind: $mol_tree2 ) { + const child = this.$mol_view_tree2_child(bind) + + return return_type.call(this, klass, child) + } + + function primitive_type(input: $mol_tree2) { + let type = 'string' + if (input.type && ( + input.type.match(/[\+\-]*NaN/) + || !Number.isNaN( Number( input.type ) ) + )) type = 'number' + + if (input.type === 'true' || input.type === 'false') type = 'boolean' + + return input.data(type) + } + export function $mol_view_tree2_to_dts(this: $, tree: $mol_tree2) { const descr = $mol_view_tree2_classes( tree ) @@ -32,10 +84,15 @@ namespace $ { for( const klass of descr.kids ) { - const parent = klass.kids[0] + const parent = this.$mol_view_tree2_child(klass) const props = this.$mol_view_tree2_class_props(klass) const aliases = [] as $mol_tree2[] const context = { objects: [] as $mol_tree2[] } + const br = bind_res.bind(this, klass) + const rt = return_type.bind(this, klass) + const rt_parent = return_type.bind(this, parent) + const param_of_method = param_of.bind(this, klass) + types.push( klass.struct( 'line', [ klass.data( 'export class ' ), @@ -48,14 +105,6 @@ namespace $ { const name = name_of.call(this, prop) - const bind_res = ( bind: $mol_tree2 )=> [ - bind.data( 'ReturnType< ' ), - klass.data( klass.type ), - bind.data( '["' ), - bind.kids[0].data( name_of.call(this, bind.kids[0] ) ), - bind.data( '"] >' ), - ] - const val = prop.hack({ 'null': ( val, belt )=> [ val.data( 'any' ) ], @@ -65,127 +114,168 @@ namespace $ { '@': ( locale, belt )=> locale.hack( belt ), - '<=>': bind_res, - '<=': bind_res, - '=>': bind_res, - + '<=>': br, + '<=': br, + '=>': br, + '^': ( ref )=> [ + ref.struct( '...', [ + ref.struct( '()', [ + ref.struct( ref.kids[0]?.type ? 'this' : 'super' ), + ref.struct( '[]', [ + name_of.call(this, ref.kids[0]?.type ? ref.kids[0] : prop), + ] ), + ref.struct( '(,)' ) + ]), + ] ), + ], '': ( input, belt )=> { - if (input.type[0] === '*') return [ - ... input.select('^').kids.map( inherit => - inherit.struct( 'line', [ - inherit.data( 'ReturnType< ' ), - parent.data( parent.type ), - inherit.data( '["' ), - prop.data( name ), - inherit.data( '"] > & ' ), - ] ) - ), - ... input.type.trim().length > 1 || ! input.kids?.length - ? [ - input.data('Record'), - ] - : [ - input.data('Record'), - // input.data('({ '), - // input.struct( 'indent', - // input.kids.map( field => { - // if( field.type === '^' ) return null - // const field_name = field.type.replace(/\?\w*$/, '') - // return field.struct( 'line', [ - // field.data('\''), - // field.data( field_name ), - // field.data('\''), - // field.data( ': ' ), - // ... field.hack( belt ), - // field.data( ',' ), - // ] ) - // } ).filter( this.$mol_guard_defined ) - // ), - // input.data('})'), - ] - - ] + if (input.type[0] === '*') { + return [ + ... input.select('^').kids.map( inherit => + inherit.struct( 'line', [ + ...rt_parent(prop), + inherit.data(' & '), + ] ) + ), + ... input.type.trim().length > 1 || ! input.kids?.length + ? [ + input.data('Record'), + ] + : [ + // input.data('Record'), + input.data('({ '), + input.struct( 'indent', + input.kids.map( field => { + if( field.type === '^' ) return null + const field_name = (field.type || field.value).replace(/\?\w*$/, '') + const child = field.kids[0] - if( input.type[0] === '/' ) return [ - input.data('readonly ('), - input.type.trim().length > 1 ? input.data( input.type.slice(1) ) : input.data('any'), - input.data(')[]'), - ] + return field.struct( 'line', [ + field.data('\''), + field.data( field_name ), + field.data('\''), + field.data( ': ' ), + ...child.type === '<=>' && child.kids[0].type.match(/\?|\*/) + ? [ + params_of.call(this, field, ...param_of_method(child.kids[0], 0) ), + field.data(' => '), + ...field.hack( belt), + ] + : field.hack( belt), + field.data( ',' ), + ] ) + } ).filter( this.$mol_guard_defined ) + ), + input.data('})'), + ] + + ] + } - if( input.type && (input.type.match(/[\+\-]*NaN/) || !Number.isNaN( Number( input.type ) ) ) ) return [ - input.data( 'number'), - ] + if( input.type[0] === '/' ) { + const hacked = [] as $mol_tree2[] + const dupes = new Set() + let is_first = true - if( /^[$A-Z]/.test( input.type ) ) { - - const first = input.kids[0] - if( first && first.type === '/' ) { - + for (const kid of input.kids) { + if (kid.type[0] === '/') hacked.push(...kid.hack(belt)) + else if (kid.type[0] === '*') hacked.push(...kid.hack(belt)) + else if (kid.type === '^' || kid.type === '<=') { + const first = kid.kids[0] ?? prop + if (! is_first) hacked.push(kid.data(' | ')) + is_first = false + hacked.push(...kid.kids[0] ? rt(first) : rt_parent(first)) + if (kid.type === '^') hacked.push(first.data('[number]')) + } else { + const pt = primitive_type(kid) + if (dupes.has(pt.value)) continue + dupes.add(pt.value) + if (! is_first) hacked.push(kid.data(' | ')) + is_first = false + hacked.push(pt) + } + } + + if (hacked.length) { types.push( - first.data( `type ${ input.type }__${ this.$mol_guid() } = $mol_type_enforce< ` ), - first.struct( 'indent', [ - first.struct( 'line', [ - ... input.hack( belt ), - input.data( ',' ), - ] ), - input.data( `Parameters< ${ input.type } >` ), - ] ), + input.struct('line', [ + input.data( `type `), + klass.data(klass.type), + klass.data('__'), + name_of.call(this, prop), + prop.data(` = $mol_type_enforce< ` ), + ]), + input.struct( 'indent', [ + input.struct('line', [ + ...rt(prop), + input.data(','), + ]), + input.struct('line', [ + input.data('readonly('), + ...hacked, + input.data(')[]'), + ]), input.data( '>' ), - ) + ])) + } + + if (input.type.length > 1 && input.kids.length === 0) { + hacked.push(input.data(input.type.slice(1))) + } + + return [ + input.data('readonly ('), + hacked.length ? input.struct('line', hacked) : input.data('any'), + input.data(')[]'), + ] + } + + if( /^[$A-Z]/.test( input.type ) ) { + + for( const over of input.kids ) { - } else { - - for( const over of input.kids ) { + const name = name_of.call(this, over ) + const bind = over.kids[0] + + if( bind.type === '=>' ) { - const name = name_of.call(this, over ) - const bind = over.kids[0] + const pr = bind.kids[0] - if( bind.type === '=>' ) { - - const pr = bind.kids[0] - - const res = [ - bind.data( 'ReturnType< ' ), - klass.data( input.type ), - bind.data( '["' ), - over.data( name ), - bind.data( '"] >' ), - ] - - aliases.push( - pr.struct( 'indent', [ - pr.struct( 'line', [ - pr.data( name_of.call(this, pr ) ), - params_of.call(this, pr, ... res ), - bind.data( ': ' ), - ... res, - ] ), - ] ), - ) - } - - types.push( - over.data( `type ${ input.type }__${ name }_${ this.$mol_guid() } = $mol_type_enforce< ` ), - over.struct( 'indent', [ - over.struct( 'line', [ - ... over.hack( belt ), - input.data( ',' ), - ] ), - over.struct( 'line', [ - input.data( 'ReturnType< ' ), - input.data( input.type ), - input.data( '["' ), - over.data( name ), - input.data( '"] >' ), + const res = return_type_raw.call( + this, + klass.data( input.type ), + name, + ) + + aliases.push( + pr.struct( 'indent', [ + pr.struct( 'line', [ + name_of.call(this, pr ), + params_of.call(this, pr, ... res ), + bind.data( ': ' ), + ... res, ] ), ] ), - input.data( '>' ), ) - } - + + types.push( + over.data( `type ${ input.type }__${ name.value }_${ this.$mol_guid() } = $mol_type_enforce< ` ), + over.struct( 'indent', [ + over.struct( 'line', [ + ... over.hack( belt ), + input.data( ',' ), + ] ), + over.struct( 'line', return_type.call( + this, + input, + over, + ) ), + ] ), + input.data( '>' ), + ) } return [ @@ -195,7 +285,7 @@ namespace $ { } return [ - input.data( input.type || 'string' ), + primitive_type(input) ] }, @@ -204,7 +294,7 @@ namespace $ { return prop.struct( 'indent', [ prop.struct( 'line', [ - prop.data( name ), + name_of.call(this, prop), params_of.call(this, prop, ... val ), prop.data(': '), ... val, diff --git a/view/tree2/to/js/js.ts b/view/tree2/to/js/js.ts index 042b302b188..6976126bd8d 100644 --- a/view/tree2/to/js/js.ts +++ b/view/tree2/to/js/js.ts @@ -18,14 +18,7 @@ namespace $ { } function args_of( this: $, prop: $mol_tree2, bidi = true ) { - - const { key, next } = this.$mol_view_tree2_prop_parts(prop) - - return prop.struct( '(,)', [ - ... key ? [ prop.struct( key.length > 1 ? key.slice(1) : 'id' ) ] : [], - ... ( bidi && next ) ? [ prop.struct( 'next' ) ] : [], - ] ) - + return params_of.call(this, prop, bidi) } function call_of(this: $, bind: $mol_tree2, bidi = true) { @@ -121,7 +114,8 @@ namespace $ { input.kids.map( field => { if( field.type === '^' ) return field.list([ field ]).hack( belt )[0] - const field_name = field.type.replace(/\?\w*$/, '') + const field_name = (field.type || field.value).replace(/\?\w*$/, '') + return field.struct( ':', [ field.data( field_name ), field.kids[0].type === '<=>' @@ -151,7 +145,7 @@ namespace $ { for( const over of input.kids ) { - if( over.type === '/' ) continue + if( over.type?.[0] === '/' ) continue const oname = name_of.call(this, over ) const bind = over.kids[0] diff --git a/view/tree2/to/js/test/ex/array_channel_of_array_or_object.view.tree b/view/tree2/to/js/test/ex/array_channel_of_array_or_object.view.tree index 174c0d063fe..3f9a41456e0 100644 --- a/view/tree2/to/js/test/ex/array_channel_of_array_or_object.view.tree +++ b/view/tree2/to/js/test/ex/array_channel_of_array_or_object.view.tree @@ -1,7 +1,10 @@ $mol_view_tree2_to_js_test_ex_array_channel_of_array_or_object_foo $mol_view complex / - / + /number|string + 1 \test1 - * + 2 + *Record + a 1 str \some nul null diff --git a/view/tree2/to/js/test/ex/array_slot.view.tree b/view/tree2/to/js/test/ex/array_slot.view.tree index 16938246180..66c864a2b0e 100644 --- a/view/tree2/to/js/test/ex/array_slot.view.tree +++ b/view/tree2/to/js/test/ex/array_slot.view.tree @@ -1,9 +1,13 @@ $mol_view_tree2_to_js_test_ex_array_slot_foo $mol_view - foot /string|number - <= foot1 \foot1 + foot /string|number|boolean + 1 + 2 + true + \foot1 ^ insert /string|number <= ins1 \ins1 ^ sub_ins /number <= sub_ins1 1 <= ins2 \ins2 <= foot2 \foot2 + diff --git a/view/tree2/to/js/test/ex/structural_complex_key.view.tree b/view/tree2/to/js/test/ex/structural_complex_key.view.tree new file mode 100644 index 00000000000..c630a16e272 --- /dev/null +++ b/view/tree2/to/js/test/ex/structural_complex_key.view.tree @@ -0,0 +1,8 @@ +$mol_view_tree2_to_js_test_ex_structural_complex_key_foo $mol_view + dictionary * + \raw data key + \1 + \key2 + \2 + key3 + \3 diff --git a/view/tree2/to/js/test/js.array.test.ts b/view/tree2/to/js/test/js.array.test.ts index e28923d7bb6..250659438a1 100644 --- a/view/tree2/to/js/test/js.array.test.ts +++ b/view/tree2/to/js/test/js.array.test.ts @@ -41,7 +41,7 @@ namespace $ { $mol_assert_like( _foo.make({ $ }).complex(), - [ [ 'test1' ], { str: 'some', nul: null } ] + [ [ 1, 'test1', 2 ], { a: 1, str: 'some', nul: null } ] ) }, @@ -65,8 +65,8 @@ namespace $ { 'Array slot' ($) { const _foo = $mol_view_tree2_to_js_test_ex_array_slot_foo const foo = _foo.make({ $ }) - type assert_foot = $mol_type_assert, readonly(string | number)[]> - $mol_assert_like(foo.foot(), [ 'foot1', 'ins1', 1, 'ins2', 'foot2' ]) + type assert_foot = $mol_type_assert, readonly(string | number | boolean)[]> + $mol_assert_like(foo.foot(), [ 1, 2, true, 'foot1', 'ins1', 1, 'ins2', 'foot2' ]) }, 'Array indexed' ($) { diff --git a/view/tree2/to/js/test/js.bidi.test.ts b/view/tree2/to/js/test/js.bidi.test.ts index 154263239c6..a01be30efea 100644 --- a/view/tree2/to/js/test/js.bidi.test.ts +++ b/view/tree2/to/js/test/js.bidi.test.ts @@ -148,15 +148,15 @@ namespace $ { ) }, - 'Bidi bind index from outer scope throws error'( $ ) { - $mol_assert_fail(() => { - $mol_view_tree2_to_js_test_run(` - Foo $mol_view - a!? $mol_view - expanded <=> cell_test_expanded!? null - `) - }) - }, + // 'Bidi bind index from outer scope throws error'( $ ) { + // $mol_assert_fail(() => { + // $mol_view_tree2_to_js_test_run(` + // Foo $mol_view + // a*? $mol_view + // expanded <=> cell_test_expanded*? null + // `) + // }) + // }, 'Bidi bind with default object'( $ ) { const _foo = $mol_view_tree2_to_js_test_ex_bidi_bind_with_default_object_foo diff --git a/view/tree2/to/js/test/js.structural.test.ts b/view/tree2/to/js/test/js.structural.test.ts index 83263f1ede2..52bc3fb24c3 100644 --- a/view/tree2/to/js/test/js.structural.test.ts +++ b/view/tree2/to/js/test/js.structural.test.ts @@ -84,6 +84,20 @@ namespace $ { }, + 'Structural complex key'($) { + const _foo = $mol_view_tree2_to_js_test_ex_structural_complex_key_foo + const foo = _foo.make({ $ }) + + $mol_assert_like( + foo.dictionary(), + { + 'raw data key': '1', + 'key2': '2', + 'key3': '3' + }, + ) + } + }) }