-
-
Notifications
You must be signed in to change notification settings - Fork 90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Why did using a simple computed property name doesn't map properly? #289
Comments
getMemberPathUtil to see if you can come up with a better implementation to support that property.
|
oh I saw this behavior documented here
|
@nartc I'm thinking of supporting the following usages:
Is it worth it or nah? (note that I'm not sure if I'll succeed implementing all of above but I can try) |
@micalevisk That works for me. One question on the 2nd bullet there: what would be your expected return value for |
I expect which is already done
|
Cool. Just want to confirm. Feel free to submit the PR anytime, I'll review it. |
I'm trying one solution locally. This is what I've got so far:
my test suite// all bellow are passing ✅
describe('cases that are allowed', () => {
const cases = [
// ____ input ________ __ output __
, [ s=>s.foo , ['foo'] ]
, [ s=>s.foo.bar , ['foo', 'bar'] ]
, [ s=>s.returnFoo , ['returnFoo'] ]
, [ s=>s.return_foo , ['return_foo'] ]
, [ s=>s[' aaa '] , [' aaa '] ]
, [ s=>s['aaa'] , ['aaa'] ]
, [ s=>s['ab-cd'] , ['ab-cd'] ]
, [ s=>s['ab_cd'] , ['ab_cd'] ]
, [ s=>s['bbb'].bar , ['bbb', 'bar'] ]
, [ s=>s.bbb['bar'] , ['bbb', 'bar'] ]
, [ s=>s['aaa']['ddd'] , ['aaa', 'ddd'] ]
, [ s=>s['aaa'].ccc['ddd'] , ['aaa', 'ccc', 'ddd'] ]
, [ s=>s['.foo.bar'] , ['.foo.bar'] ]
, [ s=>s['foo=>s[bar'] , ['foo=>s[bar'] ]
, [ s=>s["['a']"] , ["['a']"] ]
, [ s=>s['bad[foo]'] , ['bad[foo]'] ]
, [ s=>s.bar['bad[foo]'] , ['bar', 'bad[foo]'] ]
, [ s=>s["'a"] , ["'a"] ]
, [ s=>s['aa']['bo"o'] , ['aa', 'bo\"o'] ]
, [ s=>s['with_sṕéçiâl_chàrs'] , ['with_sṕéçiâl_chàrs'] ]
, [ s=>s['á'] , ['á'] ]
, [ s=>s.á , ['á'] ]
, [ s=>s.good.á , ['good', 'á'] ]
, [ s=>s['good'].á , ['good', 'á'] ]
, [ s=>s.á['good'] , ['á', 'good']
, [ s=>s[''] , [''] ]
, [ s=>s.foo[''] , ['foo', ''] ]
, [ s=>s[''].foo , ['', 'foo'] ]
].map(([fn, expected]) => [fn.toString(), expected])
it('should return the expected path list', () => {
cases.forEach(( [fnSelector, expected] ) => {
assert.deepEqual(getMembers(fnSelector), expected)
})
})
})
describe('cases that are disallowed', () => {
const cases = [
, [ s=>s , null ] // Not a real one tho
, [ s=>s`foo` , null ]
// Known limitations that should be avoided in user land code because
// they will produce wrong outputs and cannot be detected beforehand
, [ s=>s['fo' + 'o'] , ['fo'] ] // expected to be ['foo']
, [ s=>s[true ? 'foo' : 'bar'] , null ] // expected to be ['foo']
, [ s=>s[true && 'foo'] , null ] // expected to be ['foo']
, [ s=>s[Symbol()] , null ] // I'm not sure if we should support this
, [ s=>s[`a`] , null ] // To discourage the use of computed names
].map(([fn, expected]) => [fn.toString(), expected])
it('should return the expected output', () => {
cases.forEach(( [fnSelector, expected] ) => {
assert.deepEqual(getMembers(fnSelector), expected)
})
})
}) my WIP solution/**
* (not the final solution but it works)
* @param {string} fnSelector A serialized and clean arrow function expression.
* @returns {string[]|null}
*/
function getMembers(fnSelector) {
// maybe I'll remove this altogether since from `const re2 = ...` bellow we already generated the right output
const RE_HAS_COMPUTED_PROP = /(^\w+=>\w+\[)|(]$)/;
if (!RE_HAS_COMPUTED_PROP.test(fnSelector)) {
const re1 = /(?<=\.)[^.]+/g;
return fnSelector.match(re1);
}
const re2 = /(?:(?<=\[)(['"]).*?\1)|(?:(?<=\.)[^.\[]+)/g;
const matches = fnSelector.match(re2);
// May be we could optimize this by using `re2.exec`
// instead to prevent doing `.map` and `.match` and `.slice`
if (matches) {
const RE_HAS_QUOTES = /^(['"]).*\1$/;
return matches.map(match =>
match.match(RE_HAS_QUOTES)
? match.slice(1, -1) // drop the first and the last quotes
: match
);
}
return null;
}
/*
// Explanation of RE_HAS_COMPUTED_PROP regex
(
^ # from the beginning of the string
\w+ # followed by 1 or more word character (alphanumeric ASCII and underscore)
=> # followed by the literal "=>"
\w+
[ # followed by the literal "["
| # Or matches with...
\] # any occurrence of the literal "]" that is
$ # in the end of the string
)
// Explanation of re1 regex
(?<= # (begin of positive lookbehind)
\. # matches a literal "." char but without including it in the match result
) # (end of positive lookbehind)
[^.]+ # followed by 1 or more occurrence of any char but "." (dot)
// Explanation of re2 regex
(?: # (begin of non-capturing group)
(?<= # (begin of positive lookbehind)
\[ # matches a literal "[" but without including it in the match result
) # (end of positive lookbehind)
( # (begin capturing group #1)
['"] # match one occurrence of a single or double quotes characters
) # (end capturing group #1)
.*? # followed by 0 or more of any character, but match as few characters as possible (which is 0)
\1 # followed by the result of capture group #1
) # (end of non-capturing group)
| # Or matches with...
(?: # (begin of non-capturing group)
(?<= # (begin of positive lookbehind)
\. # matches a literal "." but without including it in the match result
) # (end of positive lookbehind)
[^.\[]+ # followed by 1 or more occurrences of any character but "." nor "["
) # (end of non-capturing group)
// Explanation of RE_HAS_COMPUTED_PROP regex
^ # from the beginning of the string
( # (begin capturing group #1)
['"] # match one occurrence of a single or double quotes characters
) # (end of capturing group #1)
.* # followed by 0 or more occurrences of any character
\1 # followed by the result of capture group #1
$ # in the end of the string
*/ @nartc any thoughts about this approach? Note that the output of
mapper/packages/core/src/lib/map/map.ts Lines 334 to 335 in c159560
and I've seen that |
* test(core): add empty string and trailing dot paths cases * feat(core): add a partial support for computed property names Computed property names were introduced in ES6. "Partial" in a sense that few computed property name usage are not supported. As well for when using with ES5 functions, not arrow functions. Closes #289 * docs: adjust odd-property name limitations * feat(core): improve `getMembersFromArrowFunctionExpr` to avoid map and match all the away * feat(core): add suport to computed property names for ES5 * docs: remove the ES5 limitation of odd-property name * feat(core): reset the state of the shared regex before Since we are using a constant regex that has the `g` flag in iterator we should make sure that it is in the initial state. See http://speakingjs.com/es5/ch19.html
Hi!
Basically this, for instance:
the later will result in an empty string as prop key
''
I'm trying to create a mapping to
"en-us"
property name. I can circumvent the usage of manual mapping by adding a getter methodget ['en-us'](){ return this['en-us'] }
in the source class, and withSnakeCaseNamingConvention
naming convention.@automapper/*
:v3.5.2
The text was updated successfully, but these errors were encountered: