@sw-tsdk/plugin-connector 3.13.1 → 3.13.2-next.3dfd44a

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +18 -18
  2. package/lib/commands/connector/build.js +168 -44
  3. package/lib/commands/connector/build.js.map +1 -1
  4. package/lib/commands/connector/sign.js +108 -12
  5. package/lib/commands/connector/sign.js.map +1 -1
  6. package/lib/commands/connector/validate.js +110 -10
  7. package/lib/commands/connector/validate.js.map +1 -1
  8. package/lib/commands/migrator/convert.d.ts +3 -0
  9. package/lib/commands/migrator/convert.js +201 -20
  10. package/lib/commands/migrator/convert.js.map +1 -1
  11. package/lib/templates/migrator-runners/plugin_override.txt +76 -4
  12. package/lib/templates/migrator-runners/runner_override.txt +30 -0
  13. package/lib/templates/migrator-runners/script_override.txt +77 -5
  14. package/lib/templates/swimlane/__init__.py +18 -0
  15. package/lib/templates/swimlane/core/__init__.py +0 -0
  16. package/lib/templates/swimlane/core/adapters/__init__.py +10 -0
  17. package/lib/templates/swimlane/core/adapters/app.py +59 -0
  18. package/lib/templates/swimlane/core/adapters/app_revision.py +49 -0
  19. package/lib/templates/swimlane/core/adapters/helper.py +84 -0
  20. package/lib/templates/swimlane/core/adapters/record.py +468 -0
  21. package/lib/templates/swimlane/core/adapters/record_revision.py +43 -0
  22. package/lib/templates/swimlane/core/adapters/report.py +65 -0
  23. package/lib/templates/swimlane/core/adapters/task.py +58 -0
  24. package/lib/templates/swimlane/core/adapters/usergroup.py +183 -0
  25. package/lib/templates/swimlane/core/bulk.py +48 -0
  26. package/lib/templates/swimlane/core/cache.py +165 -0
  27. package/lib/templates/swimlane/core/client.py +466 -0
  28. package/lib/templates/swimlane/core/cursor.py +100 -0
  29. package/lib/templates/swimlane/core/fields/__init__.py +46 -0
  30. package/lib/templates/swimlane/core/fields/attachment.py +82 -0
  31. package/lib/templates/swimlane/core/fields/base/__init__.py +15 -0
  32. package/lib/templates/swimlane/core/fields/base/cursor.py +90 -0
  33. package/lib/templates/swimlane/core/fields/base/field.py +149 -0
  34. package/lib/templates/swimlane/core/fields/base/multiselect.py +116 -0
  35. package/lib/templates/swimlane/core/fields/comment.py +48 -0
  36. package/lib/templates/swimlane/core/fields/datetime.py +112 -0
  37. package/lib/templates/swimlane/core/fields/history.py +28 -0
  38. package/lib/templates/swimlane/core/fields/list.py +266 -0
  39. package/lib/templates/swimlane/core/fields/number.py +38 -0
  40. package/lib/templates/swimlane/core/fields/reference.py +169 -0
  41. package/lib/templates/swimlane/core/fields/text.py +30 -0
  42. package/lib/templates/swimlane/core/fields/tracking.py +10 -0
  43. package/lib/templates/swimlane/core/fields/usergroup.py +137 -0
  44. package/lib/templates/swimlane/core/fields/valueslist.py +70 -0
  45. package/lib/templates/swimlane/core/resolver.py +46 -0
  46. package/lib/templates/swimlane/core/resources/__init__.py +0 -0
  47. package/lib/templates/swimlane/core/resources/app.py +136 -0
  48. package/lib/templates/swimlane/core/resources/app_revision.py +43 -0
  49. package/lib/templates/swimlane/core/resources/attachment.py +64 -0
  50. package/lib/templates/swimlane/core/resources/base.py +55 -0
  51. package/lib/templates/swimlane/core/resources/comment.py +33 -0
  52. package/lib/templates/swimlane/core/resources/record.py +499 -0
  53. package/lib/templates/swimlane/core/resources/record_revision.py +44 -0
  54. package/lib/templates/swimlane/core/resources/report.py +259 -0
  55. package/lib/templates/swimlane/core/resources/revision_base.py +69 -0
  56. package/lib/templates/swimlane/core/resources/task.py +16 -0
  57. package/lib/templates/swimlane/core/resources/usergroup.py +166 -0
  58. package/lib/templates/swimlane/core/search.py +31 -0
  59. package/lib/templates/swimlane/core/wrappedsession.py +12 -0
  60. package/lib/templates/swimlane/exceptions.py +191 -0
  61. package/lib/templates/swimlane/utils/__init__.py +132 -0
  62. package/lib/templates/swimlane/utils/date_validator.py +4 -0
  63. package/lib/templates/swimlane/utils/list_validator.py +7 -0
  64. package/lib/templates/swimlane/utils/str_validator.py +10 -0
  65. package/lib/templates/swimlane/utils/version.py +101 -0
  66. package/lib/transformers/base-transformer.js +61 -14
  67. package/lib/transformers/base-transformer.js.map +1 -1
  68. package/lib/transformers/connector-generator.d.ts +104 -2
  69. package/lib/transformers/connector-generator.js +1234 -51
  70. package/lib/transformers/connector-generator.js.map +1 -1
  71. package/lib/types/migrator-types.d.ts +22 -0
  72. package/lib/types/migrator-types.js.map +1 -1
  73. package/oclif.manifest.json +1 -1
  74. package/package.json +6 -6
@@ -0,0 +1,191 @@
1
+ """Custom exceptions and errors"""
2
+
3
+ from difflib import get_close_matches
4
+
5
+ from requests import HTTPError
6
+
7
+
8
+ class SwimlaneException(Exception):
9
+ """Base exception for Swimlane errors"""
10
+
11
+
12
+ class UnknownField(SwimlaneException, KeyError):
13
+ """Raised anytime access is attempted to a field that does not exist on an App or Record
14
+
15
+ Attributes:
16
+ app (App): App with the unknown field requested
17
+ field_name (str): Name of the field that was requested
18
+ similar_field_names (list(str)): List of strings of fields on app that are potentially similar to field_name
19
+ """
20
+
21
+ def __init__(self, app, field_name, field_pool):
22
+ self.app = app
23
+ self.field_name = field_name
24
+ self.similar_field_names = get_close_matches(self.field_name, field_pool, 3)
25
+
26
+ message = "{!r} has no field '{}'".format(self.app, self.field_name)
27
+
28
+ if self.similar_field_names:
29
+ message += '. Similar fields: ' + ', '.join([repr(f) for f in self.similar_field_names])
30
+
31
+ super(UnknownField, self).__init__(message)
32
+
33
+
34
+ class ValidationError(SwimlaneException, ValueError):
35
+ """Raised when record's field data is invalid
36
+
37
+ Attributes:
38
+ record (Record): Record in context of validation failure
39
+ failure (str): Reason for record failure
40
+ """
41
+
42
+ def __init__(self, record, failure):
43
+ self.record = record
44
+ self.failure = failure
45
+
46
+ super(ValidationError, self).__init__(
47
+ 'Validation failed for {!r}. Reason: {}'.format(self.record, self.failure)
48
+ )
49
+
50
+
51
+ class _InvalidSwimlaneVersion(SwimlaneException, NotImplementedError):
52
+ """Base class raised when connecting to unsupported versions of Swimlane
53
+
54
+ Attributes:
55
+ swimlane (Swimlane): Swimlane client failing the version check
56
+ min_version (str): Minimum version specified on version range
57
+ max_version (str): Maximum version specified on version range
58
+ """
59
+
60
+ def __init__(self, swimlane, min_version, max_version):
61
+ self.swimlane = swimlane
62
+ self.min_version = min_version
63
+ self.max_version = max_version
64
+
65
+ super(_InvalidSwimlaneVersion, self).__init__(self._get_message())
66
+
67
+ def _get_range_string(self):
68
+ if self.min_version and self.max_version:
69
+ range_string = '>= {}, < {}'.format(self.min_version, self.max_version)
70
+ elif self.min_version:
71
+ range_string = '>= {}'.format(self.min_version)
72
+ else:
73
+ range_string = '<= {}'.format(self.max_version)
74
+
75
+ return range_string
76
+
77
+ def _get_message(self):
78
+ return 'Swimlane version {}, must be {}'.format(
79
+ self.swimlane.version,
80
+ self._get_range_string()
81
+ )
82
+
83
+
84
+ class InvalidSwimlaneBuildVersion(_InvalidSwimlaneVersion):
85
+ """Raised when method connected to Swimlane with build version outside a required range"""
86
+
87
+ def _get_message(self):
88
+ return 'Swimlane build version {}, must be {}'.format(
89
+ self.swimlane.build_version,
90
+ self._get_range_string()
91
+ )
92
+
93
+
94
+ class InvalidSwimlaneProductVersion(_InvalidSwimlaneVersion):
95
+ """Raised when method connected to Swimlane with product version outside a required range"""
96
+
97
+ def _get_message(self):
98
+ return 'Swimlane product version {}, must be {}'.format(
99
+ self.swimlane.product_version,
100
+ self._get_range_string()
101
+ )
102
+
103
+
104
+ class SwimlaneHTTP400Error(SwimlaneException, HTTPError):
105
+ """Exception raised when receiving a 400 response with additional context
106
+
107
+ Attributes:
108
+ code (int): Swimlane error code
109
+ name (str): Human-readable Swimlane error name
110
+ argument (str): Optional argument included with error or None
111
+ http_error (HTTPError): Source requests.HTTPError caught and used to generate this exception
112
+ """
113
+
114
+ codes = {
115
+ -1: 'Unknown',
116
+ 1000: 'PasswordExpired',
117
+ 1001: 'DuplicateUserName',
118
+ 1002: 'InvalidUserNameOrPassword',
119
+ 1003: 'ConfirmPasswordDoesNotMatch',
120
+ 1004: 'PasswordDoesNotMeetComplexityRequirements',
121
+ 1005: 'PasswordResetRequired',
122
+ 1006: 'NewPasswordCannotMatchCurrent',
123
+ 1007: 'InvalidUser',
124
+ 1051: 'DuplicateGroupName',
125
+ 1061: 'DuplicateRoleName',
126
+ 2000: 'DuplicateFieldName',
127
+ 2001: 'FieldNameEmpty',
128
+ 2002: 'InvalidApplicationExportFile',
129
+ 2003: 'ApplicationNotFound',
130
+ 2004: 'InvalidCalculation',
131
+ 2005: 'DuplicateApplicationName',
132
+ 2006: 'DuplicateAppletName',
133
+ 2007: 'DuplicateAppletAcronym',
134
+ 2008: 'DuplicateApplicationAcronym',
135
+ 2011: 'SectionNameTooLong',
136
+ 3000: 'DuplicateFieldValue',
137
+ 3001: 'InvalidDateField',
138
+ 3002: 'RecordNotFound',
139
+ 3003: 'FieldNotFound',
140
+ 3006: 'MaxAttachmentSize',
141
+ 4000: 'BadStatsGroup',
142
+ 4001: 'BadFilter',
143
+ 5000: 'AppLimitExceeded',
144
+ 5001: 'UserLimitExceeded',
145
+ 5002: 'NewServerInstall',
146
+ 5003: 'UnableToConnectToActiveDirectory',
147
+ 5004: 'UnableToRetrieveStoredValue',
148
+ 5005: 'UnableToConnectToMongoDb',
149
+ 5006: 'UnableToConnectToSmtp',
150
+ 5007: 'SwimlaneAlreadyInitialized',
151
+ 5008: 'ModelValidationError',
152
+ 5009: 'UpgradeInProcess',
153
+ 5010: 'RequiredFieldMissing',
154
+ 5011: 'UnableToRetrieveEncryptionKey',
155
+ 5012: 'PathNotFound',
156
+ 5013: 'WrongType',
157
+ 5014: 'ModificationError',
158
+ 5015: 'DatabaseError',
159
+ 5016: 'NetworkError',
160
+ 5017: 'InvalidOnThisOS',
161
+ 6000: 'ConnectionDataNotProvided',
162
+ 7000: 'RegexNotDefined',
163
+ 7001: 'AssetNotFound',
164
+ 9000: 'BadThreatIntelConnector',
165
+ 9001: 'NoThreatIntel',
166
+ 9002: 'ThreatIntelTypeNotSupportedByThisProvider',
167
+ 10000: 'DuplicateTaskName',
168
+ 10001: 'TaskNotFound',
169
+ 17001: 'DuplicateAssetName',
170
+ 19001: 'HangfireError'
171
+ }
172
+
173
+ def __init__(self, http_error):
174
+ self.http_error = http_error
175
+
176
+ try:
177
+ error_content = self.http_error.response.json()
178
+ except ValueError:
179
+ error_content = {'Argument': None, 'ErrorCode': '-1'}
180
+
181
+ self.code = int(error_content.get('ErrorCode', -1))
182
+ self.argument = error_content.get('Argument')
183
+ self.name = self.codes.get(self.code, self.codes[-1])
184
+
185
+ message = '{}:{}'.format(self.name, self.code)
186
+ if self.argument is not None:
187
+ message = '{message} ({argument})'.format(message=message, argument=self.argument)
188
+
189
+ super(SwimlaneHTTP400Error, self).__init__(
190
+ '{message}: Bad Request for url: {url}'.format(message=message, url=self.http_error.response.url)
191
+ )
@@ -0,0 +1,132 @@
1
+ """Utility functions"""
2
+ from __future__ import absolute_import
3
+
4
+ import importlib
5
+ import pkgutil
6
+ import random
7
+ import string
8
+ import functools
9
+
10
+
11
+ def random_string(length, source=string.ascii_letters + string.digits):
12
+ """Return random string of characters from source of specified length
13
+
14
+ Args:
15
+ length (int): Length of the returned string
16
+ source (str): String of characters to use as options for randomly selected characters. Defaults to alphanumeric
17
+
18
+ Returns:
19
+ str: String of length number of characters composed of source characters
20
+ """
21
+ return ''.join(random.choice(source) for _ in range(length))
22
+
23
+
24
+ def get_recursive_subclasses(cls):
25
+ """Return list of all subclasses for a class, including subclasses of direct subclasses"""
26
+ return cls.__subclasses__() + [g for s in cls.__subclasses__() for g in get_recursive_subclasses(s)]
27
+
28
+
29
+ def import_submodules(package):
30
+ """Return list of imported module instances from beneath root_package"""
31
+
32
+ if isinstance(package, str):
33
+ package = importlib.import_module(package)
34
+
35
+ results = {}
36
+
37
+ for _, full_name, is_pkg in pkgutil.walk_packages(package.__path__, package.__name__ + '.'):
38
+ results[full_name] = importlib.import_module(full_name)
39
+
40
+ if is_pkg:
41
+ results.update(import_submodules(full_name))
42
+
43
+ return results
44
+
45
+
46
+ def one_of_keyword_only(*valid_keywords):
47
+ """Decorator to help make one-and-only-one keyword-only argument functions more reusable
48
+
49
+ Notes:
50
+ Decorated function should take 2 arguments, the first for the key, the second the value
51
+
52
+ Examples:
53
+
54
+ ::
55
+
56
+ @one_of_keyword_only('a', 'b', 'c')
57
+ def func(key, value):
58
+ if key == 'a':
59
+ ...
60
+ elif key == 'b':
61
+ ...
62
+ else:
63
+ # key = 'c'
64
+ ...
65
+
66
+ ...
67
+
68
+ func(a=1)
69
+ func(b=2)
70
+ func(c=3)
71
+
72
+ try:
73
+ func(d=4)
74
+ except TypeError:
75
+ ...
76
+
77
+ try:
78
+ func(a=1, b=2)
79
+ except TypeError:
80
+ ...
81
+
82
+ Args:
83
+ *valid_keywords (str): All allowed keyword argument names
84
+
85
+ Raises:
86
+ TypeError: On decorated call, if 0 or 2+ arguments are provided or kwargs contains a key not in valid_keywords
87
+ """
88
+
89
+ def decorator(func):
90
+
91
+ @functools.wraps(func)
92
+ def wrapper(*args, **kwargs):
93
+ sentinel = object()
94
+ values = {}
95
+
96
+ for key in valid_keywords:
97
+ kwarg_value = kwargs.pop(key, sentinel)
98
+ if kwarg_value is not sentinel:
99
+ values[key] = kwarg_value
100
+
101
+ if kwargs:
102
+ raise TypeError('Unexpected arguments: {}'.format(kwargs))
103
+
104
+ if not values:
105
+ raise TypeError('Must provide one of {} as keyword argument'.format(', '.join(valid_keywords)))
106
+
107
+ if len(values) > 1:
108
+ raise TypeError('Must provide only one of {} as keyword argument. Received {}'.format(
109
+ ', '.join(valid_keywords),
110
+ values
111
+ ))
112
+
113
+ return func(*(args + values.popitem()))
114
+
115
+ return wrapper
116
+
117
+ return decorator
118
+
119
+
120
+ def validate_type(field, value):
121
+ """Type validation for filters and fields from bulk_modify, bulk_delete and filter"""
122
+ accepted_values_to_check = (int, str, float, list, bool, tuple)
123
+ should_check_value_type = not value == None and type(value) in accepted_values_to_check
124
+ if should_check_value_type:
125
+ value_list = value if isinstance(value, list) else [value]
126
+ for v in value_list:
127
+ wrong_type = not any(
128
+ [isinstance(v, field_type) for field_type in field.supported_types]
129
+ ) if len(field.supported_types) > 0 else False
130
+
131
+ if wrong_type:
132
+ raise ValueError('Value must be one of {}'.format(", ".join([str(f) for f in field.supported_types])))
@@ -0,0 +1,4 @@
1
+ import datetime
2
+
3
+ def is_datetime(value):
4
+ return isinstance(value, datetime.datetime)
@@ -0,0 +1,7 @@
1
+ def validate_str_list(value, key):
2
+ if not value or not isinstance(value, list):
3
+ raise ValueError('{} must be a non-empty list value'.format(key))
4
+
5
+ for i in value:
6
+ if not isinstance(i, str) or i.strip() == '':
7
+ raise ValueError('{} must contain non-empty string values'.format(key))
@@ -0,0 +1,10 @@
1
+ def validate_str(value, key):
2
+ if not isinstance(value, str):
3
+ raise ValueError('{} must be a string value.'.format(key))
4
+ if value.strip() == '':
5
+ raise ValueError('{} must not be an empty string value.'.format(key))
6
+
7
+ def validate_str_format(value, key):
8
+ not_allowed = "@#$%^&*()"
9
+ if any(ch in not_allowed for ch in value):
10
+ raise ValueError('{} is not of the proper format.'.format(key))
@@ -0,0 +1,101 @@
1
+ import functools
2
+ import re
3
+
4
+ from pkg_resources import get_distribution, DistributionNotFound
5
+
6
+ from swimlane.exceptions import InvalidSwimlaneBuildVersion
7
+
8
+
9
+ def compare_versions(version_a, version_b, zerofill=False):
10
+ """Return direction of version relative to provided version sections
11
+
12
+ Args:
13
+ version_a (str): First version to compare
14
+ version_b (str): Second version to compare
15
+ zerofill (bool): If True, treat any missing version sections as 0, otherwise ignore section. Defaults to False
16
+
17
+ Returns:
18
+ int: 0 if equal, -1 if a > b, 1 if a < b
19
+
20
+ Examples:
21
+
22
+ If a is equal to b, return 0
23
+ If a is greater than b, return -1
24
+ If a is less than b, return 1
25
+
26
+ >>> compare_versions('2', '2') == 0
27
+ >>> compare_versions('2', '1') == -1
28
+ >>> compare_versions('2', '3') == 1
29
+
30
+ If zerofill is False (default), sections not included in both versions are ignored during comparison
31
+
32
+ >>> compare_versions('2.13.2', '2.13') == 0
33
+ >>> compare_versions('2.13.2-1234', '3') == 1
34
+
35
+ If zerofill is True, any sections in one version not included in other version are set to 0
36
+
37
+ >>> compare_versions('2.13.2', '2.13', True) == -1
38
+ >>> compare_versions('2.13.2-1234', '2.13.2', True) == -1
39
+ >>> compare_versions('2.13.2', '2.13.2', True) == 0
40
+ """
41
+ a_sections = list((int(match) for match in re.findall(r'\d+', version_a)))
42
+ b_sections = list((int(match) for match in re.findall(r'\d+', version_b)))
43
+
44
+ if zerofill:
45
+ max_sections = max([len(a_sections), len(b_sections)])
46
+
47
+ a_sections += [0 for _ in range(max(max_sections - len(a_sections), 0))]
48
+ b_sections += [0 for _ in range(max(max_sections - len(b_sections), 0))]
49
+
50
+ else:
51
+ min_sections = min([len(a_sections), len(b_sections)])
52
+
53
+ a_sections = a_sections[:min_sections]
54
+ b_sections = b_sections[:min_sections]
55
+
56
+ return (b_sections > a_sections) - (b_sections < a_sections)
57
+
58
+
59
+ def requires_swimlane_version(min_version=None, max_version=None):
60
+ """Decorator for SwimlaneResolver methods verifying Swimlane server build version is within a given inclusive range
61
+
62
+ Raises:
63
+ InvalidVersion: Raised before decorated method call if Swimlane server version is out of provided range
64
+ ValueError: If neither min_version or max_version were provided, or if those values conflict (2.15 < 2.14)
65
+ """
66
+
67
+ if min_version is None and max_version is None:
68
+ raise ValueError('Must provide either min_version, max_version, or both')
69
+
70
+ if min_version and max_version and compare_versions(min_version, max_version) < 0:
71
+ raise ValueError('min_version must be <= max_version ({}, {})'.format(min_version, max_version))
72
+
73
+ def decorator(func):
74
+
75
+ @functools.wraps(func)
76
+ def wrapper(self, *args, **kwargs):
77
+ swimlane = self._swimlane
78
+
79
+ if min_version and compare_versions(min_version, swimlane.build_version, True) < 0:
80
+ raise InvalidSwimlaneBuildVersion(swimlane, min_version, max_version)
81
+
82
+ if max_version and compare_versions(swimlane.build_version, max_version, True) < 0:
83
+ raise InvalidSwimlaneBuildVersion(swimlane, min_version, max_version)
84
+
85
+ return func(self, *args, **kwargs)
86
+
87
+ return wrapper
88
+
89
+ return decorator
90
+
91
+
92
+ def get_package_version():
93
+ """Get swimlane package version
94
+
95
+ Returns:
96
+ str: Installed swimlane lib package version, or 0.0.0.dev if not fully installed
97
+ """
98
+ try:
99
+ return get_distribution(__name__.split('.')[0]).version
100
+ except DistributionNotFound:
101
+ return '0.0.0.dev'
@@ -13,21 +13,63 @@ class BaseTransformer {
13
13
  }
14
14
  return name;
15
15
  };
16
- const inputs = (jsonFileContent?.InputMapping ?? []).map((input) => ({
17
- ...input,
18
- Key: typeof input.Key === 'string' ?
19
- input.Key.replaceAll(' ', '_') :
20
- input.Key,
21
- }));
16
+ // Infer JSON Schema type from a literal value (from InputMapping Value or Example)
17
+ const inferValueType = (value) => {
18
+ if (value === undefined || value === null)
19
+ return 'string';
20
+ if (typeof value === 'number')
21
+ return 'number';
22
+ if (typeof value === 'boolean')
23
+ return 'boolean';
24
+ if (Array.isArray(value))
25
+ return 'array';
26
+ return 'string';
27
+ };
28
+ // Separate credentials and asset inputs from regular inputs
29
+ const assetParameters = [];
30
+ const regularInputs = [];
31
+ for (const input of jsonFileContent?.InputMapping ?? []) {
32
+ const inputType = (input.type || input.Type || '').toLowerCase();
33
+ if (inputType === 'credentials' || inputType === 'asset') {
34
+ assetParameters.push({
35
+ Key: input.Key,
36
+ Type: inputType,
37
+ Example: input.Example,
38
+ SubValue: input.subValue || input.SubValue,
39
+ });
40
+ }
41
+ else {
42
+ // Infer ValueType from Value first, then from first Example
43
+ const sample = input.Value !== undefined && input.Value !== null ?
44
+ input.Value :
45
+ (Array.isArray(input.Example) && input.Example.length > 0 ? input.Example[0] : (input.Example ?? undefined));
46
+ const valueType = inferValueType(sample);
47
+ regularInputs.push({
48
+ ...input,
49
+ Key: input.Key,
50
+ Title: input.Key,
51
+ ValueType: valueType,
52
+ });
53
+ }
54
+ }
22
55
  const outputs = (jsonFileContent?.Outputs ?? [])
23
- .flatMap((output) => output.Mappings ?? [])
24
- .map((mapping) => ({
56
+ .flatMap((outputBlock) => (outputBlock.Mappings ?? []).map((mapping) => ({
25
57
  Key: typeof mapping.Key === 'string' ? mapping.Key.replaceAll(' ', '_') : mapping.Key,
26
58
  Title: mapping.Key,
27
59
  ValueType: 'string',
28
60
  Example: mapping.Example || [],
29
61
  Description: '',
30
- }));
62
+ // Preserve mapping metadata for output date conversion (Value = application field id)
63
+ Value: mapping.Value,
64
+ DataFormat: mapping.DataFormat ?? mapping.dataFormat,
65
+ UnixEpochUnit: mapping.UnixEpochUnit ?? mapping.unixEpochUnit,
66
+ customDataFormat: mapping.customDataFormat ?? mapping.CustomDataFormat,
67
+ // Application id of the output block (e.g. InsertUpdateRecordOutput.ApplicationId); used to resolve field type
68
+ ApplicationId: outputBlock.ApplicationId ?? outputBlock.applicationId,
69
+ })));
70
+ // Extract task ID from common locations in the task JSON
71
+ const taskId = jsonFileContent?._id || jsonFileContent?.$id || jsonFileContent?.Id || jsonFileContent?.id || '';
72
+ const taskApplicationId = jsonFileContent?.ApplicationId ?? jsonFileContent?.applicationId;
31
73
  return {
32
74
  description: jsonFileContent?.Action?.Descriptor?.Description,
33
75
  family: jsonFileContent?.Action?.Descriptor?.Family,
@@ -37,17 +79,22 @@ class BaseTransformer {
37
79
  script: jsonFileContent?.Action?.Script,
38
80
  exportName: truncateIfNeeded(jsonFileContent?.Name, 'exportName'),
39
81
  exportUid: truncateIfNeeded(jsonFileContent?.Uid.replaceAll('-', '_'), 'exportUid'),
82
+ taskId,
83
+ taskApplicationId: typeof taskApplicationId === 'string' ? taskApplicationId : undefined,
40
84
  forkedName: truncateIfNeeded(jsonFileContent?.Action?.ForkedFromPackage, 'forkedName'),
41
- inputs,
85
+ inputs: regularInputs,
42
86
  outputs,
87
+ assetParameters,
43
88
  author: jsonFileContent?.CreatedByUser?.Author,
44
89
  };
45
90
  }
46
91
  scriptIsValid(script) {
47
- const containsMongoImports = script.includes('from pymongo import MongoClient' || 'import pymongo');
48
- const containsSwimlaneDriver = script.includes('from swimlane import Swimlane' || 'from swimlane import SwimlaneClient' || 'import Swimlane');
49
- const containsInternalConfig = script.includes('sw_context.config');
50
- return !(containsMongoImports || containsSwimlaneDriver || containsInternalConfig);
92
+ const containsMongoImports = script.includes('from pymongo import MongoClient') || script.includes('import pymongo');
93
+ // Note: These checks are currently disabled but kept for future use
94
+ // const containsSwimlaneDriver = script.includes('from swimlane import Swimlane') || script.includes('from swimlane import SwimlaneClient') || script.includes('import Swimlane')
95
+ // const containsInternalConfig = script.includes('sw_context.config')
96
+ // return !(containsMongoImports || containsSwimlaneDriver || containsInternalConfig)
97
+ return !containsMongoImports;
51
98
  }
52
99
  }
53
100
  exports.BaseTransformer = BaseTransformer;
@@ -1 +1 @@
1
- {"version":3,"file":"base-transformer.js","sourceRoot":"","sources":["../../src/transformers/base-transformer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base-transformer.js","sourceRoot":"","sources":["../../src/transformers/base-transformer.ts"],"names":[],"mappings":";;;AAEA,MAAsB,eAAe;IAEzB,iBAAiB,CAAC,eAAoB;QAC9C,MAAM,UAAU,GAAG,EAAE,CAAA;QAErB,MAAM,gBAAgB,GAAG,CAAC,IAAwB,EAAE,KAAa,EAAU,EAAE;YAC3E,IAAI,CAAC,IAAI;gBAAE,OAAO,EAAE,CAAA;YACpB,IAAI,IAAI,CAAC,MAAM,GAAG,UAAU,EAAE;gBAC5B,OAAO,CAAC,IAAI,CAAC,YAAY,KAAK,YAAY,UAAU,gDAAgD,IAAI,EAAE,CAAC,CAAA;gBAC3G,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAA;aAC9C;YAED,OAAO,IAAI,CAAA;QACb,CAAC,CAAA;QAED,mFAAmF;QACnF,MAAM,cAAc,GAAG,CAAC,KAAc,EAAU,EAAE;YAChD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,QAAQ,CAAA;YAC1D,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,QAAQ,CAAA;YAC9C,IAAI,OAAO,KAAK,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAA;YAChD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,OAAO,CAAA;YACxC,OAAO,QAAQ,CAAA;QACjB,CAAC,CAAA;QAED,4DAA4D;QAC5D,MAAM,eAAe,GAAsE,EAAE,CAAA;QAC7F,MAAM,aAAa,GAAU,EAAE,CAAA;QAE/B,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,YAAY,IAAI,EAAE,EAAE;YACvD,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAA;YAChE,IAAI,SAAS,KAAK,aAAa,IAAI,SAAS,KAAK,OAAO,EAAE;gBACxD,eAAe,CAAC,IAAI,CAAC;oBACnB,GAAG,EAAE,KAAK,CAAC,GAAG;oBACd,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ;iBAC3C,CAAC,CAAA;aACH;iBAAM;gBACL,4DAA4D;gBAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;oBAChE,KAAK,CAAC,KAAK,CAAC,CAAC;oBACb,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,SAAS,CAAC,CAAC,CAAA;gBAC9G,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;gBACxC,aAAa,CAAC,IAAI,CAAC;oBACjB,GAAG,KAAK;oBACR,GAAG,EAAE,KAAK,CAAC,GAAG;oBACd,KAAK,EAAE,KAAK,CAAC,GAAG;oBAChB,SAAS,EAAE,SAAS;iBACrB,CAAC,CAAA;aACH;SACF;QAED,MAAM,OAAO,GAAG,CAAC,eAAe,EAAE,OAAO,IAAI,EAAE,CAAC;aAC/C,OAAO,CAAC,CAAC,WAAgB,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAY,EAAE,EAAE,CAAC,CAAC;YACjF,GAAG,EAAE,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG;YACrF,KAAK,EAAE,OAAO,CAAC,GAAG;YAClB,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;YAC9B,WAAW,EAAE,EAAE;YACf,sFAAsF;YACtF,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU;YACpD,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa;YAC7D,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC,gBAAgB;YACtE,+GAA+G;YAC/G,aAAa,EAAE,WAAW,CAAC,aAAa,IAAI,WAAW,CAAC,aAAa;SACtE,CAAC,CAAC,CAAC,CAAA;QAEJ,yDAAyD;QACzD,MAAM,MAAM,GAAG,eAAe,EAAE,GAAG,IAAI,eAAe,EAAE,GAAG,IAAI,eAAe,EAAE,EAAE,IAAI,eAAe,EAAE,EAAE,IAAI,EAAE,CAAA;QAC/G,MAAM,iBAAiB,GAAG,eAAe,EAAE,aAAa,IAAI,eAAe,EAAE,aAAa,CAAA;QAE1F,OAAO;YACL,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW;YAC7D,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;YACnD,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW;YAC7D,aAAa,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa;YACjE,UAAU,EAAE,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,CAAC;YACrF,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM;YACvC,UAAU,EAAE,gBAAgB,CAAC,eAAe,EAAE,IAAI,EAAE,YAAY,CAAC;YACjE,SAAS,EAAE,gBAAgB,CAAC,eAAe,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,WAAW,CAAC;YACnF,MAAM;YACN,iBAAiB,EAAE,OAAO,iBAAiB,KAAK,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS;YACxF,UAAU,EAAE,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,iBAAiB,EAAE,YAAY,CAAC;YACtF,MAAM,EAAE,aAAa;YACrB,OAAO;YACP,eAAe;YACf,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM;SAC/C,CAAA;IACH,CAAC;IAEM,aAAa,CAAC,MAAc;QACjC,MAAM,oBAAoB,GAAG,MAAM,CAAC,QAAQ,CAAC,iCAAiC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAA;QACpH,oEAAoE;QACpE,kLAAkL;QAClL,sEAAsE;QACtE,qFAAqF;QACrF,OAAO,CAAC,oBAAoB,CAAA;IAC9B,CAAC;CACF;AAnGD,0CAmGC"}