@ffschrattenecker/tm1-mcp-server 6.0.0
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.
- package/CHANGELOG.md +1211 -0
- package/LICENSE +21 -0
- package/NOTICE +34 -0
- package/README.md +276 -0
- package/dist/config.d.ts +35 -0
- package/dist/config.js +238 -0
- package/dist/http-transport.d.ts +8 -0
- package/dist/http-transport.js +132 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +164 -0
- package/dist/lib/callgraph/callGraph.d.ts +124 -0
- package/dist/lib/callgraph/callGraph.js +334 -0
- package/dist/lib/callgraph/choreGraph.d.ts +23 -0
- package/dist/lib/callgraph/choreGraph.js +102 -0
- package/dist/lib/callgraph/dataFlow.d.ts +74 -0
- package/dist/lib/callgraph/dataFlow.js +271 -0
- package/dist/lib/callgraph/datasourceMembership.d.ts +31 -0
- package/dist/lib/callgraph/datasourceMembership.js +142 -0
- package/dist/lib/callgraph/lintTypes.d.ts +28 -0
- package/dist/lib/callgraph/lintTypes.js +2 -0
- package/dist/lib/callgraph/mdxMembers.d.ts +29 -0
- package/dist/lib/callgraph/mdxMembers.js +97 -0
- package/dist/lib/callgraph/referenceIndex.d.ts +179 -0
- package/dist/lib/callgraph/referenceIndex.js +584 -0
- package/dist/lib/callgraph/rulesLinter.d.ts +55 -0
- package/dist/lib/callgraph/rulesLinter.js +776 -0
- package/dist/lib/callgraph/rulesParser.d.ts +26 -0
- package/dist/lib/callgraph/rulesParser.js +71 -0
- package/dist/lib/callgraph/subsetUsage.d.ts +16 -0
- package/dist/lib/callgraph/subsetUsage.js +134 -0
- package/dist/lib/callgraph/tiParser.d.ts +21 -0
- package/dist/lib/callgraph/tiParser.js +672 -0
- package/dist/lib/callgraph/tiSignatures.d.ts +32 -0
- package/dist/lib/callgraph/tiSignatures.js +6185 -0
- package/dist/lib/callgraph/tm1-adapter.d.ts +32 -0
- package/dist/lib/callgraph/tm1-adapter.js +159 -0
- package/dist/lib/callgraph/types.d.ts +53 -0
- package/dist/lib/callgraph/types.js +2 -0
- package/dist/lib/callgraph/variableEnv.d.ts +86 -0
- package/dist/lib/callgraph/variableEnv.js +214 -0
- package/dist/lib/cell-address.d.ts +12 -0
- package/dist/lib/cell-address.js +71 -0
- package/dist/lib/complexity/antipatterns.d.ts +22 -0
- package/dist/lib/complexity/antipatterns.js +302 -0
- package/dist/lib/complexity/comment-classifier.d.ts +24 -0
- package/dist/lib/complexity/comment-classifier.js +43 -0
- package/dist/lib/complexity/cross-process.d.ts +78 -0
- package/dist/lib/complexity/cross-process.js +114 -0
- package/dist/lib/complexity/process-metrics.d.ts +78 -0
- package/dist/lib/complexity/process-metrics.js +278 -0
- package/dist/lib/complexity/rules-metrics.d.ts +31 -0
- package/dist/lib/complexity/rules-metrics.js +99 -0
- package/dist/lib/concurrency.d.ts +11 -0
- package/dist/lib/concurrency.js +27 -0
- package/dist/lib/control-name.d.ts +10 -0
- package/dist/lib/control-name.js +10 -0
- package/dist/lib/coordinate-error.d.ts +3 -0
- package/dist/lib/coordinate-error.js +29 -0
- package/dist/lib/credential-format.d.ts +23 -0
- package/dist/lib/credential-format.js +25 -0
- package/dist/lib/cube-stats/fetcher.d.ts +106 -0
- package/dist/lib/cube-stats/fetcher.js +194 -0
- package/dist/lib/feeders/brackets.d.ts +47 -0
- package/dist/lib/feeders/brackets.js +195 -0
- package/dist/lib/feeders/element-type-cache.d.ts +42 -0
- package/dist/lib/feeders/element-type-cache.js +86 -0
- package/dist/lib/feeders/static-heuristics.d.ts +101 -0
- package/dist/lib/feeders/static-heuristics.js +202 -0
- package/dist/lib/git-process.d.ts +67 -0
- package/dist/lib/git-process.js +243 -0
- package/dist/lib/mask-secrets.d.ts +10 -0
- package/dist/lib/mask-secrets.js +99 -0
- package/dist/lib/mdx.d.ts +3 -0
- package/dist/lib/mdx.js +13 -0
- package/dist/lib/naming/odata-filter.d.ts +15 -0
- package/dist/lib/naming/odata-filter.js +81 -0
- package/dist/lib/naming/rules.d.ts +34 -0
- package/dist/lib/naming/rules.js +215 -0
- package/dist/lib/pro-parser.d.ts +19 -0
- package/dist/lib/pro-parser.js +260 -0
- package/dist/lib/pro-serializer.d.ts +19 -0
- package/dist/lib/pro-serializer.js +170 -0
- package/dist/lib/process-parts-schema.d.ts +45 -0
- package/dist/lib/process-parts-schema.js +46 -0
- package/dist/lib/process-refs.d.ts +88 -0
- package/dist/lib/process-refs.js +441 -0
- package/dist/lib/rules-outline.d.ts +29 -0
- package/dist/lib/rules-outline.js +68 -0
- package/dist/lib/rules-patch.d.ts +6 -0
- package/dist/lib/rules-patch.js +59 -0
- package/dist/lib/safe-regex.d.ts +15 -0
- package/dist/lib/safe-regex.js +37 -0
- package/dist/lib/sample-cells.d.ts +48 -0
- package/dist/lib/sample-cells.js +146 -0
- package/dist/lib/slim-json-schema.d.ts +20 -0
- package/dist/lib/slim-json-schema.js +68 -0
- package/dist/lib/strip-comments.d.ts +23 -0
- package/dist/lib/strip-comments.js +61 -0
- package/dist/lib/tm1-events.d.ts +16 -0
- package/dist/lib/tm1-events.js +29 -0
- package/dist/lib/v12-compat/deprecated-ti.d.ts +17 -0
- package/dist/lib/v12-compat/deprecated-ti.js +257 -0
- package/dist/lib/v12-compat/scanner.d.ts +10 -0
- package/dist/lib/v12-compat/scanner.js +43 -0
- package/dist/lib/variables-ui-data.d.ts +26 -0
- package/dist/lib/variables-ui-data.js +77 -0
- package/dist/load-env.d.ts +2 -0
- package/dist/load-env.js +29 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.js +60 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.js +141 -0
- package/dist/resources/index.d.ts +5 -0
- package/dist/resources/index.js +237 -0
- package/dist/resources/list-handler.d.ts +40 -0
- package/dist/resources/list-handler.js +86 -0
- package/dist/resources/subscriptions.d.ts +19 -0
- package/dist/resources/subscriptions.js +80 -0
- package/dist/schemas/cells.d.ts +17 -0
- package/dist/schemas/cells.js +13 -0
- package/dist/schemas/common.d.ts +16 -0
- package/dist/schemas/common.js +14 -0
- package/dist/schemas/index.d.ts +10 -0
- package/dist/schemas/index.js +23 -0
- package/dist/schemas/metadata.d.ts +70 -0
- package/dist/schemas/metadata.js +47 -0
- package/dist/schemas/monitoring.d.ts +95 -0
- package/dist/schemas/monitoring.js +69 -0
- package/dist/schemas/processes.d.ts +74 -0
- package/dist/schemas/processes.js +66 -0
- package/dist/schemas/scheduling.d.ts +13 -0
- package/dist/schemas/scheduling.js +13 -0
- package/dist/schemas/security.d.ts +19 -0
- package/dist/schemas/security.js +16 -0
- package/dist/schemas/subsets.d.ts +12 -0
- package/dist/schemas/subsets.js +12 -0
- package/dist/schemas/views.d.ts +9 -0
- package/dist/schemas/views.js +9 -0
- package/dist/session-manager.d.ts +79 -0
- package/dist/session-manager.js +281 -0
- package/dist/tm1-client/connection/profile.d.ts +13 -0
- package/dist/tm1-client/connection/profile.js +99 -0
- package/dist/tm1-client/dispatcher.d.ts +5 -0
- package/dist/tm1-client/dispatcher.js +31 -0
- package/dist/tm1-client/http.d.ts +81 -0
- package/dist/tm1-client/http.js +547 -0
- package/dist/tm1-client/services/batch-service.d.ts +123 -0
- package/dist/tm1-client/services/batch-service.js +455 -0
- package/dist/tm1-client/services/cell-service.d.ts +71 -0
- package/dist/tm1-client/services/cell-service.js +333 -0
- package/dist/tm1-client/services/cellset-transform.d.ts +26 -0
- package/dist/tm1-client/services/cellset-transform.js +80 -0
- package/dist/tm1-client/services/chore-service.d.ts +68 -0
- package/dist/tm1-client/services/chore-service.js +179 -0
- package/dist/tm1-client/services/chore-status.d.ts +11 -0
- package/dist/tm1-client/services/chore-status.js +127 -0
- package/dist/tm1-client/services/cube-service.d.ts +134 -0
- package/dist/tm1-client/services/cube-service.js +294 -0
- package/dist/tm1-client/services/dimension-service.d.ts +118 -0
- package/dist/tm1-client/services/dimension-service.js +249 -0
- package/dist/tm1-client/services/element-service.d.ts +245 -0
- package/dist/tm1-client/services/element-service.js +809 -0
- package/dist/tm1-client/services/fallback.d.ts +44 -0
- package/dist/tm1-client/services/fallback.js +72 -0
- package/dist/tm1-client/services/file-service.d.ts +53 -0
- package/dist/tm1-client/services/file-service.js +218 -0
- package/dist/tm1-client/services/hierarchy-service.d.ts +129 -0
- package/dist/tm1-client/services/hierarchy-service.js +332 -0
- package/dist/tm1-client/services/monitoring-service.d.ts +34 -0
- package/dist/tm1-client/services/monitoring-service.js +123 -0
- package/dist/tm1-client/services/odata-page.d.ts +71 -0
- package/dist/tm1-client/services/odata-page.js +87 -0
- package/dist/tm1-client/services/process-service.d.ts +278 -0
- package/dist/tm1-client/services/process-service.js +874 -0
- package/dist/tm1-client/services/process-status.d.ts +21 -0
- package/dist/tm1-client/services/process-status.js +89 -0
- package/dist/tm1-client/services/security-service.d.ts +50 -0
- package/dist/tm1-client/services/security-service.js +93 -0
- package/dist/tm1-client/services/server-service.d.ts +116 -0
- package/dist/tm1-client/services/server-service.js +504 -0
- package/dist/tm1-client/services/subset-service.d.ts +37 -0
- package/dist/tm1-client/services/subset-service.js +122 -0
- package/dist/tm1-client/services/view-service.d.ts +46 -0
- package/dist/tm1-client/services/view-service.js +287 -0
- package/dist/tm1-client.d.ts +56 -0
- package/dist/tm1-client.js +126 -0
- package/dist/tools/analysis/analyze-callgraph.d.ts +28 -0
- package/dist/tools/analysis/analyze-callgraph.js +350 -0
- package/dist/tools/analysis/analyze-chore-graph.d.ts +2 -0
- package/dist/tools/analysis/analyze-chore-graph.js +148 -0
- package/dist/tools/analysis/analyze-object-usage.d.ts +2 -0
- package/dist/tools/analysis/analyze-object-usage.js +143 -0
- package/dist/tools/analysis/audit-complexity.d.ts +2 -0
- package/dist/tools/analysis/audit-complexity.js +255 -0
- package/dist/tools/analysis/audit-feeders.d.ts +2 -0
- package/dist/tools/analysis/audit-feeders.js +417 -0
- package/dist/tools/analysis/audit-naming.d.ts +2 -0
- package/dist/tools/analysis/audit-naming.js +379 -0
- package/dist/tools/analysis/check-v12-readiness.d.ts +2 -0
- package/dist/tools/analysis/check-v12-readiness.js +136 -0
- package/dist/tools/analysis/find-orphan-dimensions.d.ts +2 -0
- package/dist/tools/analysis/find-orphan-dimensions.js +55 -0
- package/dist/tools/analysis/invalidate-callgraph-cache.d.ts +2 -0
- package/dist/tools/analysis/invalidate-callgraph-cache.js +40 -0
- package/dist/tools/analysis/trace-data-flow.d.ts +2 -0
- package/dist/tools/analysis/trace-data-flow.js +138 -0
- package/dist/tools/annotations.d.ts +12 -0
- package/dist/tools/annotations.js +61 -0
- package/dist/tools/celldata/check-feeders.d.ts +2 -0
- package/dist/tools/celldata/check-feeders.js +48 -0
- package/dist/tools/celldata/check-writable-coords.d.ts +2 -0
- package/dist/tools/celldata/check-writable-coords.js +126 -0
- package/dist/tools/celldata/execute-mdx.d.ts +17 -0
- package/dist/tools/celldata/execute-mdx.js +126 -0
- package/dist/tools/celldata/get-cell-value.d.ts +2 -0
- package/dist/tools/celldata/get-cell-value.js +30 -0
- package/dist/tools/celldata/get-view-definition.d.ts +2 -0
- package/dist/tools/celldata/get-view-definition.js +29 -0
- package/dist/tools/celldata/get-view.d.ts +2 -0
- package/dist/tools/celldata/get-view.js +55 -0
- package/dist/tools/celldata/sample-cells.d.ts +2 -0
- package/dist/tools/celldata/sample-cells.js +101 -0
- package/dist/tools/celldata/trace-cell-calculation.d.ts +2 -0
- package/dist/tools/celldata/trace-cell-calculation.js +53 -0
- package/dist/tools/celldata/trace-feeders.d.ts +2 -0
- package/dist/tools/celldata/trace-feeders.js +44 -0
- package/dist/tools/celldata/write-cells.d.ts +2 -0
- package/dist/tools/celldata/write-cells.js +65 -0
- package/dist/tools/confirm.d.ts +10 -0
- package/dist/tools/confirm.js +64 -0
- package/dist/tools/define-tool.d.ts +51 -0
- package/dist/tools/define-tool.js +49 -0
- package/dist/tools/dimension-management/bulk-upsert-elements.d.ts +2 -0
- package/dist/tools/dimension-management/bulk-upsert-elements.js +103 -0
- package/dist/tools/dimension-management/create-dimension.d.ts +2 -0
- package/dist/tools/dimension-management/create-dimension.js +22 -0
- package/dist/tools/dimension-management/create-element-attribute.d.ts +2 -0
- package/dist/tools/dimension-management/create-element-attribute.js +26 -0
- package/dist/tools/dimension-management/create-element.d.ts +2 -0
- package/dist/tools/dimension-management/create-element.js +31 -0
- package/dist/tools/dimension-management/create-hierarchy.d.ts +2 -0
- package/dist/tools/dimension-management/create-hierarchy.js +22 -0
- package/dist/tools/dimension-management/delete-dimension.d.ts +2 -0
- package/dist/tools/dimension-management/delete-dimension.js +25 -0
- package/dist/tools/dimension-management/delete-element.d.ts +2 -0
- package/dist/tools/dimension-management/delete-element.js +26 -0
- package/dist/tools/dimension-management/delete-elements.d.ts +2 -0
- package/dist/tools/dimension-management/delete-elements.js +44 -0
- package/dist/tools/dimension-management/delete-hierarchy.d.ts +2 -0
- package/dist/tools/dimension-management/delete-hierarchy.js +35 -0
- package/dist/tools/dimension-management/get-element-attribute-values.d.ts +2 -0
- package/dist/tools/dimension-management/get-element-attribute-values.js +77 -0
- package/dist/tools/dimension-management/list-element-attributes.d.ts +2 -0
- package/dist/tools/dimension-management/list-element-attributes.js +31 -0
- package/dist/tools/dimension-management/move-element.d.ts +2 -0
- package/dist/tools/dimension-management/move-element.js +28 -0
- package/dist/tools/dimension-management/update-element-attribute-value.d.ts +2 -0
- package/dist/tools/dimension-management/update-element-attribute-value.js +80 -0
- package/dist/tools/dimension-management/update-element.d.ts +2 -0
- package/dist/tools/dimension-management/update-element.js +35 -0
- package/dist/tools/error-format.d.ts +22 -0
- package/dist/tools/error-format.js +130 -0
- package/dist/tools/fileops/delete-file.d.ts +2 -0
- package/dist/tools/fileops/delete-file.js +32 -0
- package/dist/tools/fileops/get-file-content.d.ts +2 -0
- package/dist/tools/fileops/get-file-content.js +76 -0
- package/dist/tools/fileops/list-files.d.ts +2 -0
- package/dist/tools/fileops/list-files.js +43 -0
- package/dist/tools/fileops/search-files.d.ts +2 -0
- package/dist/tools/fileops/search-files.js +76 -0
- package/dist/tools/fileops/upload-file.d.ts +2 -0
- package/dist/tools/fileops/upload-file.js +69 -0
- package/dist/tools/format.d.ts +57 -0
- package/dist/tools/format.js +157 -0
- package/dist/tools/hierarchy.d.ts +6 -0
- package/dist/tools/hierarchy.js +27 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +263 -0
- package/dist/tools/local-file.d.ts +16 -0
- package/dist/tools/local-file.js +88 -0
- package/dist/tools/metadata/get-ancestors.d.ts +2 -0
- package/dist/tools/metadata/get-ancestors.js +36 -0
- package/dist/tools/metadata/get-descendants.d.ts +2 -0
- package/dist/tools/metadata/get-descendants.js +64 -0
- package/dist/tools/metadata/get-hierarchy.d.ts +2 -0
- package/dist/tools/metadata/get-hierarchy.js +130 -0
- package/dist/tools/metadata/list-chores.d.ts +2 -0
- package/dist/tools/metadata/list-chores.js +62 -0
- package/dist/tools/metadata/list-cubes.d.ts +2 -0
- package/dist/tools/metadata/list-cubes.js +128 -0
- package/dist/tools/metadata/list-dimensions.d.ts +2 -0
- package/dist/tools/metadata/list-dimensions.js +131 -0
- package/dist/tools/metadata/list-processes-grouped.d.ts +2 -0
- package/dist/tools/metadata/list-processes-grouped.js +96 -0
- package/dist/tools/metadata/list-processes.d.ts +2 -0
- package/dist/tools/metadata/list-processes.js +108 -0
- package/dist/tools/metadata/resolve-default-members.d.ts +2 -0
- package/dist/tools/metadata/resolve-default-members.js +46 -0
- package/dist/tools/model-building/check-cube-rule.d.ts +2 -0
- package/dist/tools/model-building/check-cube-rule.js +51 -0
- package/dist/tools/model-building/clear-cube.d.ts +2 -0
- package/dist/tools/model-building/clear-cube.js +46 -0
- package/dist/tools/model-building/create-cube.d.ts +2 -0
- package/dist/tools/model-building/create-cube.js +34 -0
- package/dist/tools/model-building/delete-cube.d.ts +2 -0
- package/dist/tools/model-building/delete-cube.js +27 -0
- package/dist/tools/model-building/get-all-cube-rules.d.ts +2 -0
- package/dist/tools/model-building/get-all-cube-rules.js +149 -0
- package/dist/tools/model-building/get-cube-rules.d.ts +2 -0
- package/dist/tools/model-building/get-cube-rules.js +69 -0
- package/dist/tools/model-building/rules-source.d.ts +21 -0
- package/dist/tools/model-building/rules-source.js +49 -0
- package/dist/tools/model-building/search-rules.d.ts +2 -0
- package/dist/tools/model-building/search-rules.js +132 -0
- package/dist/tools/model-building/set-cube-rules.d.ts +2 -0
- package/dist/tools/model-building/set-cube-rules.js +81 -0
- package/dist/tools/model-building/unload-cube.d.ts +2 -0
- package/dist/tools/model-building/unload-cube.js +23 -0
- package/dist/tools/operations/diagnose-process-error.d.ts +2 -0
- package/dist/tools/operations/diagnose-process-error.js +178 -0
- package/dist/tools/operations/error-log-helpers.d.ts +25 -0
- package/dist/tools/operations/error-log-helpers.js +57 -0
- package/dist/tools/operations/get-audit-log.d.ts +2 -0
- package/dist/tools/operations/get-audit-log.js +70 -0
- package/dist/tools/operations/get-cube-stats.d.ts +2 -0
- package/dist/tools/operations/get-cube-stats.js +107 -0
- package/dist/tools/operations/get-error-log-content.d.ts +2 -0
- package/dist/tools/operations/get-error-log-content.js +164 -0
- package/dist/tools/operations/get-jobs.d.ts +3 -0
- package/dist/tools/operations/get-jobs.js +51 -0
- package/dist/tools/operations/get-message-log.d.ts +2 -0
- package/dist/tools/operations/get-message-log.js +63 -0
- package/dist/tools/operations/get-server-info.d.ts +2 -0
- package/dist/tools/operations/get-server-info.js +180 -0
- package/dist/tools/operations/get-server-state.d.ts +2 -0
- package/dist/tools/operations/get-server-state.js +129 -0
- package/dist/tools/operations/get-sessions.d.ts +2 -0
- package/dist/tools/operations/get-sessions.js +76 -0
- package/dist/tools/operations/get-threads.d.ts +3 -0
- package/dist/tools/operations/get-threads.js +50 -0
- package/dist/tools/operations/get-transaction-log.d.ts +2 -0
- package/dist/tools/operations/get-transaction-log.js +63 -0
- package/dist/tools/operations/list-error-logs.d.ts +8 -0
- package/dist/tools/operations/list-error-logs.js +157 -0
- package/dist/tools/operations/save-data.d.ts +2 -0
- package/dist/tools/operations/save-data.js +50 -0
- package/dist/tools/pagination.d.ts +32 -0
- package/dist/tools/pagination.js +116 -0
- package/dist/tools/scheduling/create-chore.d.ts +2 -0
- package/dist/tools/scheduling/create-chore.js +93 -0
- package/dist/tools/scheduling/delete-chore.d.ts +2 -0
- package/dist/tools/scheduling/delete-chore.js +22 -0
- package/dist/tools/scheduling/execute-chore.d.ts +2 -0
- package/dist/tools/scheduling/execute-chore.js +52 -0
- package/dist/tools/scheduling/toggle-chore.d.ts +2 -0
- package/dist/tools/scheduling/toggle-chore.js +22 -0
- package/dist/tools/scheduling/update-chore.d.ts +2 -0
- package/dist/tools/scheduling/update-chore.js +71 -0
- package/dist/tools/schemas/common.d.ts +10 -0
- package/dist/tools/schemas/common.js +23 -0
- package/dist/tools/schemas/items-analysis.d.ts +394 -0
- package/dist/tools/schemas/items-analysis.js +419 -0
- package/dist/tools/schemas/items-cells.d.ts +70 -0
- package/dist/tools/schemas/items-cells.js +65 -0
- package/dist/tools/schemas/items-common.d.ts +18 -0
- package/dist/tools/schemas/items-common.js +39 -0
- package/dist/tools/schemas/items-fileops.d.ts +11 -0
- package/dist/tools/schemas/items-fileops.js +13 -0
- package/dist/tools/schemas/items-metadata.d.ts +262 -0
- package/dist/tools/schemas/items-metadata.js +184 -0
- package/dist/tools/schemas/items-monitoring.d.ts +79 -0
- package/dist/tools/schemas/items-monitoring.js +78 -0
- package/dist/tools/schemas/items-processes.d.ts +279 -0
- package/dist/tools/schemas/items-processes.js +235 -0
- package/dist/tools/schemas/items-scheduling.d.ts +25 -0
- package/dist/tools/schemas/items-scheduling.js +26 -0
- package/dist/tools/schemas/items-security.d.ts +19 -0
- package/dist/tools/schemas/items-security.js +12 -0
- package/dist/tools/schemas/items-subsets.d.ts +2 -0
- package/dist/tools/schemas/items-subsets.js +4 -0
- package/dist/tools/schemas/items-views.d.ts +38 -0
- package/dist/tools/schemas/items-views.js +26 -0
- package/dist/tools/schemas/items.d.ts +12 -0
- package/dist/tools/schemas/items.js +23 -0
- package/dist/tools/schemas/markdown-capable.d.ts +21 -0
- package/dist/tools/schemas/markdown-capable.js +58 -0
- package/dist/tools/schemas/output-schema.d.ts +24 -0
- package/dist/tools/schemas/output-schema.js +25 -0
- package/dist/tools/security/assign-client-group.d.ts +2 -0
- package/dist/tools/security/assign-client-group.js +20 -0
- package/dist/tools/security/create-client.d.ts +2 -0
- package/dist/tools/security/create-client.js +28 -0
- package/dist/tools/security/delete-client.d.ts +2 -0
- package/dist/tools/security/delete-client.js +22 -0
- package/dist/tools/security/get-client.d.ts +2 -0
- package/dist/tools/security/get-client.js +20 -0
- package/dist/tools/security/list-clients.d.ts +2 -0
- package/dist/tools/security/list-clients.js +86 -0
- package/dist/tools/security/list-groups.d.ts +2 -0
- package/dist/tools/security/list-groups.js +43 -0
- package/dist/tools/security/remove-client-group.d.ts +2 -0
- package/dist/tools/security/remove-client-group.js +27 -0
- package/dist/tools/security/update-client.d.ts +2 -0
- package/dist/tools/security/update-client.js +22 -0
- package/dist/tools/subsets/create-subset.d.ts +2 -0
- package/dist/tools/subsets/create-subset.js +44 -0
- package/dist/tools/subsets/delete-subset.d.ts +2 -0
- package/dist/tools/subsets/delete-subset.js +26 -0
- package/dist/tools/subsets/get-subset.d.ts +2 -0
- package/dist/tools/subsets/get-subset.js +29 -0
- package/dist/tools/subsets/list-subsets.d.ts +2 -0
- package/dist/tools/subsets/list-subsets.js +36 -0
- package/dist/tools/subsets/update-subset.d.ts +2 -0
- package/dist/tools/subsets/update-subset.js +33 -0
- package/dist/tools/ti-development/check-process-code.d.ts +2 -0
- package/dist/tools/ti-development/check-process-code.js +96 -0
- package/dist/tools/ti-development/compile-process.d.ts +2 -0
- package/dist/tools/ti-development/compile-process.js +32 -0
- package/dist/tools/ti-development/copy-process.d.ts +2 -0
- package/dist/tools/ti-development/copy-process.js +32 -0
- package/dist/tools/ti-development/delete-process.d.ts +2 -0
- package/dist/tools/ti-development/delete-process.js +26 -0
- package/dist/tools/ti-development/diff-process-with-file.d.ts +2 -0
- package/dist/tools/ti-development/diff-process-with-file.js +208 -0
- package/dist/tools/ti-development/diff-processes.d.ts +2 -0
- package/dist/tools/ti-development/diff-processes.js +312 -0
- package/dist/tools/ti-development/execute-process.d.ts +8 -0
- package/dist/tools/ti-development/execute-process.js +109 -0
- package/dist/tools/ti-development/export-process-to-git.d.ts +2 -0
- package/dist/tools/ti-development/export-process-to-git.js +113 -0
- package/dist/tools/ti-development/export-process-to-pro.d.ts +2 -0
- package/dist/tools/ti-development/export-process-to-pro.js +117 -0
- package/dist/tools/ti-development/get-all-processes-code.d.ts +2 -0
- package/dist/tools/ti-development/get-all-processes-code.js +131 -0
- package/dist/tools/ti-development/get-process-code.d.ts +2 -0
- package/dist/tools/ti-development/get-process-code.js +100 -0
- package/dist/tools/ti-development/get-process-datasource.d.ts +2 -0
- package/dist/tools/ti-development/get-process-datasource.js +20 -0
- package/dist/tools/ti-development/get-process-parameters.d.ts +2 -0
- package/dist/tools/ti-development/get-process-parameters.js +25 -0
- package/dist/tools/ti-development/get-process-variables.d.ts +2 -0
- package/dist/tools/ti-development/get-process-variables.js +38 -0
- package/dist/tools/ti-development/get-process.d.ts +2 -0
- package/dist/tools/ti-development/get-process.js +163 -0
- package/dist/tools/ti-development/import-pro-file.d.ts +2 -0
- package/dist/tools/ti-development/import-pro-file.js +153 -0
- package/dist/tools/ti-development/import-process-from-git.d.ts +2 -0
- package/dist/tools/ti-development/import-process-from-git.js +198 -0
- package/dist/tools/ti-development/install-pro-bundle.d.ts +2 -0
- package/dist/tools/ti-development/install-pro-bundle.js +288 -0
- package/dist/tools/ti-development/preflight.d.ts +39 -0
- package/dist/tools/ti-development/preflight.js +56 -0
- package/dist/tools/ti-development/process-backup.d.ts +29 -0
- package/dist/tools/ti-development/process-backup.js +118 -0
- package/dist/tools/ti-development/search-code.d.ts +2 -0
- package/dist/tools/ti-development/search-code.js +208 -0
- package/dist/tools/ti-development/upsert-process.d.ts +2 -0
- package/dist/tools/ti-development/upsert-process.js +167 -0
- package/dist/tools/ti-development/validate-process-refs.d.ts +2 -0
- package/dist/tools/ti-development/validate-process-refs.js +73 -0
- package/dist/tools/views/create-mdx-view.d.ts +2 -0
- package/dist/tools/views/create-mdx-view.js +21 -0
- package/dist/tools/views/create-native-view.d.ts +2 -0
- package/dist/tools/views/create-native-view.js +81 -0
- package/dist/tools/views/delete-view.d.ts +2 -0
- package/dist/tools/views/delete-view.js +23 -0
- package/dist/tools/views/list-views.d.ts +2 -0
- package/dist/tools/views/list-views.js +32 -0
- package/dist/tools/with-annotations.d.ts +6 -0
- package/dist/tools/with-annotations.js +339 -0
- package/dist/types.d.ts +409 -0
- package/dist/types.js +91 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +18 -0
- package/package.json +107 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
// Cube/dimension reference check for TI code: which object names does the code
|
|
2
|
+
// hand to well-known TI functions, and do they exist on the server?
|
|
3
|
+
//
|
|
4
|
+
// One core for two callers: tm1_validate_process_refs (the read-only
|
|
5
|
+
// validator) and the install tools' preflight (import_pro_file,
|
|
6
|
+
// import_process_from_git, install_pro_bundle, upsert_process), which run it
|
|
7
|
+
// on the EXACT payload they are about to install. Before this was shared, the
|
|
8
|
+
// preflight ran the syntax check only, so a deploy could validate cleanly and
|
|
9
|
+
// still install code that names a cube that does not exist.
|
|
10
|
+
//
|
|
11
|
+
// TM1 lets syntactically valid code reference non-existent objects — the
|
|
12
|
+
// compiler never resolves names — so this catches the gap between compile and
|
|
13
|
+
// runtime. It does NOT flag:
|
|
14
|
+
// - existence probes (CubeExists, DimensionExists, HierarchyExists,
|
|
15
|
+
// SubsetExists, ViewExists): asking whether an object exists is legitimate
|
|
16
|
+
// precisely when it may not;
|
|
17
|
+
// - names the same code creates (CubeCreate / DimensionCreate with a literal
|
|
18
|
+
// or literal-bound name): the `IF(DimensionExists('X') = 0);
|
|
19
|
+
// DimensionCreate('X');` pattern must pass.
|
|
20
|
+
//
|
|
21
|
+
// Element literals are checked too, in the cell functions (CellGetN/S,
|
|
22
|
+
// CellPutN/S, CellIncrementN, CellIsUpdateable, CellPutProportionalSpread) of
|
|
23
|
+
// a cube that exists: each literal (or literal-bound) element argument is
|
|
24
|
+
// looked up in the dimension at its position. Why: a TI cell call with an
|
|
25
|
+
// element that does not exist does not abort the process — verified on
|
|
26
|
+
// 11.8.03500, it ends HasMinorErrors, the rest of the process runs, and the
|
|
27
|
+
// value is simply not written. Rules that keep this free of false positives:
|
|
28
|
+
// - the lookup is TM1's own name resolution (case/space-insensitive,
|
|
29
|
+
// aliases accepted), not a string compare;
|
|
30
|
+
// - TI never passes the Sandboxes dimension (verified: a cell call that
|
|
31
|
+
// included it failed), so positions map onto the cube's other dimensions;
|
|
32
|
+
// - a call whose argument count does not match is skipped, not guessed at;
|
|
33
|
+
// - elements the same code inserts are excused, and a dimension the code
|
|
34
|
+
// inserts into with a computed name excuses every literal in it;
|
|
35
|
+
// - variables (datasource fields, parameters) are not checked — that is
|
|
36
|
+
// what the element is in most data-tab calls — and do not make the report
|
|
37
|
+
// partial.
|
|
38
|
+
// Existence probes (DimIx, ElementIndex) are deliberately not element checks.
|
|
39
|
+
import { buildProcessEnv } from "./callgraph/variableEnv.js";
|
|
40
|
+
import { mapSettledWithConcurrency } from "./concurrency.js";
|
|
41
|
+
export const TABS = ["prolog", "metadata", "data", "epilog"];
|
|
42
|
+
// Distinct element lookups per report. Past it, the remaining literals are
|
|
43
|
+
// counted as unchecked (partial) rather than turning one validation into
|
|
44
|
+
// hundreds of requests.
|
|
45
|
+
const ELEMENT_LOOKUP_MAX = 200;
|
|
46
|
+
const SANDBOX_DIMENSION = "sandboxes";
|
|
47
|
+
const CUBE_ARG1_FNS = "CellGetN|CellGetS|CellIsUpdateable|ViewCreate|ViewDestroy|ViewZeroOut|CubeClearData|SubsetCreatebyMDX|ViewSubsetAssign|DBR|DBS|DBSS|CubeProcessFeeders|CubeUnload|CubeLockOverride|CubeSetLogChanges";
|
|
48
|
+
const DIM_ARG1_FNS = "SubsetCreate|SubsetDestroy|DimensionElementInsertDirect|DimensionElementComponentAdd|DimensionElementDelete|DimensionElementPrincipalName|DimSiz|DimNm|DimIx|DType|ElementType|ElementLevel|ElementWeight|HierarchyName|AttrS|AttrN";
|
|
49
|
+
const CREATE_CUBE_FNS = "CubeCreate";
|
|
50
|
+
const CREATE_DIM_FNS = "DimensionCreate";
|
|
51
|
+
const litRe = (fns) => new RegExp(`\\b(${fns})\\s*\\(\\s*'([^']+)'`, "gi");
|
|
52
|
+
// Arg-1 passed as a bare identifier (sCube = 'x'; CellGetN(sCube, ...)) —
|
|
53
|
+
// resolved through the per-process variable env; unresolvable identifiers
|
|
54
|
+
// (params, datasource vars, reassigned or computed values) are counted as
|
|
55
|
+
// unchecked.
|
|
56
|
+
const identRe = (fns) => new RegExp(`\\b(${fns})\\s*\\(\\s*([A-Za-z_]\\w*)\\s*[,)]`, "gi");
|
|
57
|
+
const CUBE_FN_RE = litRe(CUBE_ARG1_FNS);
|
|
58
|
+
const DIM_FN_RE = litRe(DIM_ARG1_FNS);
|
|
59
|
+
const CUBE_FN_IDENT_RE = identRe(CUBE_ARG1_FNS);
|
|
60
|
+
const DIM_FN_IDENT_RE = identRe(DIM_ARG1_FNS);
|
|
61
|
+
const CUBE_CREATE_RE = litRe(CREATE_CUBE_FNS);
|
|
62
|
+
const DIM_CREATE_RE = litRe(CREATE_DIM_FNS);
|
|
63
|
+
const CUBE_CREATE_IDENT_RE = identRe(CREATE_CUBE_FNS);
|
|
64
|
+
const DIM_CREATE_IDENT_RE = identRe(CREATE_DIM_FNS);
|
|
65
|
+
// CellPutN/CellPutS/CellIncrementN/CellPutProportionalSpread take the value as
|
|
66
|
+
// arg 1 and the cube as arg 2; AttrPutS/AttrPutN/ElementSecurityPut take the
|
|
67
|
+
// dimension as arg 2. The value arg is an arbitrary expression (nested calls,
|
|
68
|
+
// '|'-concat, multi-line), so these are resolved with a paren/quote walker
|
|
69
|
+
// (secondArgText) instead of a regex skip.
|
|
70
|
+
const CUBE_ARG2_FN_RE = /\b(?:CellPutN|CellPutS|CellIncrementN|CellPutProportionalSpread)\s*\(/gi;
|
|
71
|
+
const DIM_ARG2_FN_RE = /\b(?:AttrPutS|AttrPutN|ElementSecurityPut)\s*\(/gi;
|
|
72
|
+
// Cap the argument walk so a pathological unterminated call cannot scan the
|
|
73
|
+
// whole remaining tab.
|
|
74
|
+
const ARG_SCAN_MAX_CHARS = 2000;
|
|
75
|
+
// Walk the argument list starting after `(` at openParen, tracking paren depth
|
|
76
|
+
// and TI string state ('' is the quote escape), and return the raw text of
|
|
77
|
+
// every top-level argument, or null for an unterminated call. Newlines are
|
|
78
|
+
// ordinary whitespace, so multi-line calls resolve too; TI strings cannot span
|
|
79
|
+
// lines, so an open string is closed at end-of-line to resync.
|
|
80
|
+
function callArgs(text, openParen) {
|
|
81
|
+
let depth = 0;
|
|
82
|
+
let inStr = false;
|
|
83
|
+
const args = [];
|
|
84
|
+
let argStart = openParen + 1;
|
|
85
|
+
const end = Math.min(text.length, openParen + 1 + ARG_SCAN_MAX_CHARS);
|
|
86
|
+
for (let i = openParen + 1; i < end; i++) {
|
|
87
|
+
const ch = text[i];
|
|
88
|
+
if (inStr) {
|
|
89
|
+
if (ch === "'") {
|
|
90
|
+
if (text[i + 1] === "'") {
|
|
91
|
+
i++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
inStr = false;
|
|
95
|
+
}
|
|
96
|
+
else if (ch === "\n") {
|
|
97
|
+
inStr = false;
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (ch === "'") {
|
|
102
|
+
inStr = true;
|
|
103
|
+
}
|
|
104
|
+
else if (ch === "(") {
|
|
105
|
+
depth++;
|
|
106
|
+
}
|
|
107
|
+
else if (ch === ")") {
|
|
108
|
+
if (depth === 0) {
|
|
109
|
+
args.push(text.slice(argStart, i));
|
|
110
|
+
return args;
|
|
111
|
+
}
|
|
112
|
+
depth--;
|
|
113
|
+
}
|
|
114
|
+
else if (ch === "," && depth === 0) {
|
|
115
|
+
args.push(text.slice(argStart, i));
|
|
116
|
+
argStart = i + 1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
function secondArgText(text, openParen) {
|
|
122
|
+
return callArgs(text, openParen)?.[1] ?? null;
|
|
123
|
+
}
|
|
124
|
+
function quotedLiteral(argText) {
|
|
125
|
+
const m = /^\s*'((?:[^']|'')+)'\s*$/.exec(argText);
|
|
126
|
+
return m ? m[1].replace(/''/g, "'") : null;
|
|
127
|
+
}
|
|
128
|
+
// Resolve a bare identifier through the process env: only a variable bound to
|
|
129
|
+
// exactly one string literal counts; params, datasource vars, and dynamic
|
|
130
|
+
// bindings return null (unresolvable at parse time).
|
|
131
|
+
function identLiteral(argText, env) {
|
|
132
|
+
const m = /^\s*([A-Za-z_]\w*)\s*$/.exec(argText);
|
|
133
|
+
if (!m)
|
|
134
|
+
return null;
|
|
135
|
+
const binding = env.vars.get(m[1].toLowerCase());
|
|
136
|
+
return binding?.kind === "literal" ? binding.value : null;
|
|
137
|
+
}
|
|
138
|
+
function scanCode(code, tab, regex, into, scanner, resolveName) {
|
|
139
|
+
const lines = code.split(/\r?\n/);
|
|
140
|
+
for (let i = 0; i < lines.length; i++) {
|
|
141
|
+
const ln = lines[i];
|
|
142
|
+
if (/^\s*#/.test(ln))
|
|
143
|
+
continue;
|
|
144
|
+
regex.lastIndex = 0;
|
|
145
|
+
let m;
|
|
146
|
+
while ((m = regex.exec(ln)) !== null) {
|
|
147
|
+
const name = resolveName ? resolveName(m[2]) : m[2];
|
|
148
|
+
if (!name) {
|
|
149
|
+
scanner.unresolvable++;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (!into.has(name))
|
|
153
|
+
into.set(name, { tab, line: i + 1, context: ln.trim().slice(0, 200) });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Arg-2 variant of scanCode: matches the function name across the whole tab
|
|
158
|
+
// (comment lines blanked, so multi-line calls survive) and resolves the second
|
|
159
|
+
// argument with the paren/quote walker.
|
|
160
|
+
function scanArg2(code, tab, fnRe, env, into, scanner) {
|
|
161
|
+
const lines = code.split(/\r?\n/).map((ln) => (/^\s*#/.test(ln) ? "" : ln));
|
|
162
|
+
const text = lines.join("\n");
|
|
163
|
+
fnRe.lastIndex = 0;
|
|
164
|
+
let m;
|
|
165
|
+
while ((m = fnRe.exec(text)) !== null) {
|
|
166
|
+
// The pattern ends with '(' — its index is the end of the match.
|
|
167
|
+
const argText = secondArgText(text, m.index + m[0].length - 1);
|
|
168
|
+
if (argText === null)
|
|
169
|
+
continue;
|
|
170
|
+
const name = quotedLiteral(argText) ?? identLiteral(argText, env);
|
|
171
|
+
if (!name) {
|
|
172
|
+
scanner.unresolvable++;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (into.has(name))
|
|
176
|
+
continue;
|
|
177
|
+
const line = text.slice(0, m.index).split("\n").length;
|
|
178
|
+
into.set(name, {
|
|
179
|
+
tab,
|
|
180
|
+
line,
|
|
181
|
+
context: lines[line - 1].trim().slice(0, 200),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Cell functions and the position of their cube argument; the element
|
|
186
|
+
// arguments follow it, one per (non-Sandboxes) cube dimension.
|
|
187
|
+
const CELL_FN_RE = /\b(CellGetN|CellGetS|CellIsUpdateable|CellPutN|CellPutS|CellIncrementN|CellPutProportionalSpread)\s*\(/gi;
|
|
188
|
+
const CELL_CUBE_ARG = {
|
|
189
|
+
cellgetn: 0,
|
|
190
|
+
cellgets: 0,
|
|
191
|
+
cellisupdateable: 0,
|
|
192
|
+
cellputn: 1,
|
|
193
|
+
cellputs: 1,
|
|
194
|
+
cellincrementn: 1,
|
|
195
|
+
cellputproportionalspread: 1,
|
|
196
|
+
};
|
|
197
|
+
// Element inserts: [dimension arg, element arg].
|
|
198
|
+
const INSERT_FN_RE = /\b(DimensionElementInsert|DimensionElementInsertDirect|HierarchyElementInsert)\s*\(/gi;
|
|
199
|
+
const INSERT_ARGS = {
|
|
200
|
+
dimensionelementinsert: [0, 2],
|
|
201
|
+
dimensionelementinsertdirect: [0, 2],
|
|
202
|
+
hierarchyelementinsert: [0, 3],
|
|
203
|
+
};
|
|
204
|
+
/** TM1 compares names ignoring case and spaces. */
|
|
205
|
+
export const tm1Key = (s) => s.toLowerCase().replace(/\s+/g, "");
|
|
206
|
+
function forEachCall(code, fnRe, fn) {
|
|
207
|
+
const lines = code.split(/\r?\n/).map((ln) => (/^\s*#/.test(ln) ? "" : ln));
|
|
208
|
+
const text = lines.join("\n");
|
|
209
|
+
fnRe.lastIndex = 0;
|
|
210
|
+
let m;
|
|
211
|
+
while ((m = fnRe.exec(text)) !== null) {
|
|
212
|
+
const args = callArgs(text, m.index + m[0].length - 1);
|
|
213
|
+
if (args === null)
|
|
214
|
+
continue;
|
|
215
|
+
const line = text.slice(0, m.index).split("\n").length;
|
|
216
|
+
fn(m[1].toLowerCase(), args, line, lines[line - 1].trim().slice(0, 200));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function scanCellCalls(code, tab, env, into) {
|
|
220
|
+
forEachCall(code, CELL_FN_RE, (fn, args, line, context) => {
|
|
221
|
+
const cubeIdx = CELL_CUBE_ARG[fn];
|
|
222
|
+
const cubeArg = args[cubeIdx];
|
|
223
|
+
if (cubeArg === undefined)
|
|
224
|
+
return;
|
|
225
|
+
const cube = quotedLiteral(cubeArg) ?? identLiteral(cubeArg, env);
|
|
226
|
+
// An unresolvable cube is already counted by the cube scan.
|
|
227
|
+
if (!cube)
|
|
228
|
+
return;
|
|
229
|
+
into.push({
|
|
230
|
+
cube,
|
|
231
|
+
elements: args
|
|
232
|
+
.slice(cubeIdx + 1)
|
|
233
|
+
.map((a) => quotedLiteral(a) ?? identLiteral(a, env)),
|
|
234
|
+
tab,
|
|
235
|
+
line,
|
|
236
|
+
context,
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
function scanInserts(code, env, into) {
|
|
241
|
+
forEachCall(code, INSERT_FN_RE, (fn, args) => {
|
|
242
|
+
const [dimIdx, elIdx] = INSERT_ARGS[fn];
|
|
243
|
+
const dimArg = args[dimIdx];
|
|
244
|
+
const elArg = args[elIdx];
|
|
245
|
+
if (dimArg === undefined || elArg === undefined)
|
|
246
|
+
return;
|
|
247
|
+
const dim = quotedLiteral(dimArg) ?? identLiteral(dimArg, env);
|
|
248
|
+
if (!dim) {
|
|
249
|
+
into.dynamicAnyDim = true;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const el = quotedLiteral(elArg) ?? identLiteral(elArg, env);
|
|
253
|
+
const k = tm1Key(dim);
|
|
254
|
+
if (!el) {
|
|
255
|
+
into.dynamicDims.add(k);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (!into.literal.has(k))
|
|
259
|
+
into.literal.set(k, new Set());
|
|
260
|
+
into.literal.get(k).add(tm1Key(el));
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/** Parse-time half: collect the references, no server round-trip. */
|
|
264
|
+
export function scanProcessRefs(code) {
|
|
265
|
+
// Variable env across all tabs in runtime order: a prolog assignment
|
|
266
|
+
// like sCube = 'Sales'; makes CellGetN(sCube, ...) resolvable. Params
|
|
267
|
+
// are unknown here (only code is scanned), so param-fed identifiers
|
|
268
|
+
// stay unresolvable — conservative.
|
|
269
|
+
const env = buildProcessEnv(TABS.map((t) => code[t] ?? "").join("\n"), []);
|
|
270
|
+
const resolveIdent = (raw) => identLiteral(raw, env);
|
|
271
|
+
const scanner = { unresolvable: 0 };
|
|
272
|
+
const cubeRefs = new Map();
|
|
273
|
+
const dimRefs = new Map();
|
|
274
|
+
const createdCubes = new Map();
|
|
275
|
+
const createdDims = new Map();
|
|
276
|
+
// Created names are collected with their own counter: an unresolvable
|
|
277
|
+
// create name hides nothing, it just cannot excuse a reference.
|
|
278
|
+
const ignore = { unresolvable: 0 };
|
|
279
|
+
const tabsChecked = [];
|
|
280
|
+
const cellCalls = [];
|
|
281
|
+
const inserts = {
|
|
282
|
+
literal: new Map(),
|
|
283
|
+
dynamicDims: new Set(),
|
|
284
|
+
dynamicAnyDim: false,
|
|
285
|
+
};
|
|
286
|
+
for (const tab of TABS) {
|
|
287
|
+
const c = code[tab];
|
|
288
|
+
if (!c || c.trim() === "")
|
|
289
|
+
continue;
|
|
290
|
+
tabsChecked.push(tab);
|
|
291
|
+
scanCode(c, tab, CUBE_FN_RE, cubeRefs, scanner);
|
|
292
|
+
scanCode(c, tab, CUBE_FN_IDENT_RE, cubeRefs, scanner, resolveIdent);
|
|
293
|
+
scanArg2(c, tab, CUBE_ARG2_FN_RE, env, cubeRefs, scanner);
|
|
294
|
+
scanCode(c, tab, DIM_FN_RE, dimRefs, scanner);
|
|
295
|
+
scanCode(c, tab, DIM_FN_IDENT_RE, dimRefs, scanner, resolveIdent);
|
|
296
|
+
scanArg2(c, tab, DIM_ARG2_FN_RE, env, dimRefs, scanner);
|
|
297
|
+
scanCode(c, tab, CUBE_CREATE_RE, createdCubes, ignore);
|
|
298
|
+
scanCode(c, tab, CUBE_CREATE_IDENT_RE, createdCubes, ignore, resolveIdent);
|
|
299
|
+
scanCode(c, tab, DIM_CREATE_RE, createdDims, ignore);
|
|
300
|
+
scanCode(c, tab, DIM_CREATE_IDENT_RE, createdDims, ignore, resolveIdent);
|
|
301
|
+
scanCellCalls(c, tab, env, cellCalls);
|
|
302
|
+
scanInserts(c, env, inserts);
|
|
303
|
+
}
|
|
304
|
+
const lower = (m) => new Set([...m.keys()].map((k) => k.toLowerCase()));
|
|
305
|
+
return {
|
|
306
|
+
cubeRefs,
|
|
307
|
+
dimRefs,
|
|
308
|
+
createdCubes: lower(createdCubes),
|
|
309
|
+
createdDims: lower(createdDims),
|
|
310
|
+
tabsChecked,
|
|
311
|
+
unresolvableArgs: scanner.unresolvable,
|
|
312
|
+
cellCalls,
|
|
313
|
+
inserts,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
/** Scan the code and resolve every reference against the server's catalogue. */
|
|
317
|
+
export async function checkProcessRefs(catalogue, code, opts = {}) {
|
|
318
|
+
const includeControl = opts.includeControl ?? true;
|
|
319
|
+
const scan = scanProcessRefs(code);
|
|
320
|
+
const [cubes, dims] = await Promise.all([
|
|
321
|
+
catalogue.cubes.list(),
|
|
322
|
+
catalogue.dimensions.list(),
|
|
323
|
+
]);
|
|
324
|
+
const known = (items) => new Set(items
|
|
325
|
+
.filter((o) => includeControl || !o.name.startsWith("}"))
|
|
326
|
+
.map((o) => o.name.toLowerCase()));
|
|
327
|
+
const cubeNames = known(cubes);
|
|
328
|
+
const dimNames = known(dims);
|
|
329
|
+
const issues = [];
|
|
330
|
+
for (const [name, info] of scan.cubeRefs) {
|
|
331
|
+
const k = name.toLowerCase();
|
|
332
|
+
if (!cubeNames.has(k) && !scan.createdCubes.has(k))
|
|
333
|
+
issues.push({ kind: "cube", name, ...info });
|
|
334
|
+
}
|
|
335
|
+
for (const [name, info] of scan.dimRefs) {
|
|
336
|
+
const k = name.toLowerCase();
|
|
337
|
+
if (!dimNames.has(k) && !scan.createdDims.has(k))
|
|
338
|
+
issues.push({ kind: "dimension", name, ...info });
|
|
339
|
+
}
|
|
340
|
+
const elementCheck = await checkElementRefs(catalogue, scan, cubeNames);
|
|
341
|
+
issues.push(...elementCheck.issues);
|
|
342
|
+
const unresolvableArgs = scan.unresolvableArgs + elementCheck.overflow;
|
|
343
|
+
return {
|
|
344
|
+
cubeRefsScanned: scan.cubeRefs.size,
|
|
345
|
+
dimensionRefsScanned: scan.dimRefs.size,
|
|
346
|
+
elementRefsScanned: elementCheck.scanned,
|
|
347
|
+
unresolved: issues.length,
|
|
348
|
+
issues,
|
|
349
|
+
tabsChecked: scan.tabsChecked,
|
|
350
|
+
unresolvableArgs,
|
|
351
|
+
partial: unresolvableArgs > 0,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
async function checkElementRefs(catalogue, scan, cubeNames) {
|
|
355
|
+
// Called as methods: the real catalogue is TM1Client, whose services use
|
|
356
|
+
// `this`, so detaching them would lose it.
|
|
357
|
+
const cubesSvc = catalogue.cubes;
|
|
358
|
+
const elements = catalogue.elements;
|
|
359
|
+
if (!cubesSvc.getDimensionNames || !elements || scan.inserts.dynamicAnyDim) {
|
|
360
|
+
return { issues: [], scanned: 0, overflow: 0 };
|
|
361
|
+
}
|
|
362
|
+
// Only cubes that exist and that the code does not create: a missing cube
|
|
363
|
+
// is already an issue, and a created one has no dimensions to ask about.
|
|
364
|
+
const cubes = [
|
|
365
|
+
...new Set(scan.cellCalls
|
|
366
|
+
.map((c) => c.cube)
|
|
367
|
+
.filter((c) => cubeNames.has(c.toLowerCase()) &&
|
|
368
|
+
!scan.createdCubes.has(c.toLowerCase()))),
|
|
369
|
+
];
|
|
370
|
+
const dimsOf = new Map();
|
|
371
|
+
await Promise.all(cubes.map(async (c) => {
|
|
372
|
+
const all = await cubesSvc.getDimensionNames(c);
|
|
373
|
+
// TI's cell functions never take the Sandboxes dimension.
|
|
374
|
+
dimsOf.set(c.toLowerCase(), all.filter((d) => d.toLowerCase() !== SANDBOX_DIMENSION));
|
|
375
|
+
}));
|
|
376
|
+
// Distinct (dimension, element) pairs, first occurrence kept for the report.
|
|
377
|
+
const pending = new Map();
|
|
378
|
+
for (const call of scan.cellCalls) {
|
|
379
|
+
const dims = dimsOf.get(call.cube.toLowerCase());
|
|
380
|
+
if (!dims || dims.length !== call.elements.length)
|
|
381
|
+
continue;
|
|
382
|
+
call.elements.forEach((el, i) => {
|
|
383
|
+
if (el === null)
|
|
384
|
+
return;
|
|
385
|
+
const dim = dims[i];
|
|
386
|
+
const dk = tm1Key(dim);
|
|
387
|
+
if (scan.inserts.dynamicDims.has(dk))
|
|
388
|
+
return;
|
|
389
|
+
if (scan.inserts.literal.get(dk)?.has(tm1Key(el)))
|
|
390
|
+
return;
|
|
391
|
+
const key = `${dk}\u0000${tm1Key(el)}`;
|
|
392
|
+
if (!pending.has(key))
|
|
393
|
+
pending.set(key, { dim, el, call });
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
const todo = [...pending.values()];
|
|
397
|
+
const checked = todo.slice(0, ELEMENT_LOOKUP_MAX);
|
|
398
|
+
const settled = await mapSettledWithConcurrency(checked, 8, ({ dim, el }) => resolvesInTi(elements, dim, el));
|
|
399
|
+
// A lookup that failed for any reason other than "not found" (auth,
|
|
400
|
+
// transport, denial) must surface, not read as a missing element.
|
|
401
|
+
const found = settled.map((r) => {
|
|
402
|
+
if (r.status === "rejected")
|
|
403
|
+
throw r.reason;
|
|
404
|
+
return r.value;
|
|
405
|
+
});
|
|
406
|
+
const issues = [];
|
|
407
|
+
checked.forEach(({ dim, el, call }, i) => {
|
|
408
|
+
if (!found[i])
|
|
409
|
+
issues.push({
|
|
410
|
+
kind: "element",
|
|
411
|
+
name: el,
|
|
412
|
+
dimension: dim,
|
|
413
|
+
tab: call.tab,
|
|
414
|
+
line: call.line,
|
|
415
|
+
context: call.context,
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
return {
|
|
419
|
+
issues,
|
|
420
|
+
scanned: checked.length,
|
|
421
|
+
overflow: todo.length - checked.length,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
// TI addresses an alternate hierarchy as 'Hierarchy:Element'. A colon can also
|
|
425
|
+
// be part of a plain element name, so both readings are tried.
|
|
426
|
+
async function resolvesInTi(elements, dim, el) {
|
|
427
|
+
const colon = el.indexOf(":");
|
|
428
|
+
if (colon > 0) {
|
|
429
|
+
const hier = el.slice(0, colon);
|
|
430
|
+
const member = el.slice(colon + 1);
|
|
431
|
+
try {
|
|
432
|
+
if (await elements.exists(dim, hier, member))
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
// Not a hierarchy of this dimension — fall through to the plain name.
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return elements.exists(dim, dim, el);
|
|
440
|
+
}
|
|
441
|
+
//# sourceMappingURL=process-refs.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Upper bound on outline entries; a rule file of 5000 one-line comments must not become a 5000-entry outline. */
|
|
2
|
+
export declare const OUTLINE_MAX_ENTRIES = 200;
|
|
3
|
+
export interface OutlineEntry {
|
|
4
|
+
/** 1-based line number. */
|
|
5
|
+
line: number;
|
|
6
|
+
text: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function splitLines(text: string): string[];
|
|
9
|
+
/**
|
|
10
|
+
* Section markers: the rule directives (SKIPCHECK, FEEDERS, FEEDSTRINGS,
|
|
11
|
+
* UNDEFVALS) and the first worded line of every comment block — a run of
|
|
12
|
+
* consecutive `#` lines is how rule files label what follows. Decoration-only
|
|
13
|
+
* lines are skipped in favor of the block's first line with words in it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function outlineRules(text: string): {
|
|
16
|
+
outline: OutlineEntry[];
|
|
17
|
+
truncated: boolean;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Lines `from`..`to` (1-based, inclusive), clamped to the text. Returns the
|
|
21
|
+
* slice verbatim — no line-number prefixes — so it can be quoted back into a
|
|
22
|
+
* `find` string for a rules patch.
|
|
23
|
+
*/
|
|
24
|
+
export declare function sliceLines(text: string, from: number, to: number): {
|
|
25
|
+
text: string;
|
|
26
|
+
from: number;
|
|
27
|
+
to: number;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=rules-outline.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Navigation over a cube's rule text without shipping all of it: an outline of
|
|
2
|
+
// section markers, and line-range slices. A 130 KB rule file overflowed the
|
|
3
|
+
// client's result cap three times in recorded usage; the outline plus one or
|
|
4
|
+
// two slices is what an edit actually needs.
|
|
5
|
+
/** Upper bound on outline entries; a rule file of 5000 one-line comments must not become a 5000-entry outline. */
|
|
6
|
+
export const OUTLINE_MAX_ENTRIES = 200;
|
|
7
|
+
const OUTLINE_TEXT_MAX = 100;
|
|
8
|
+
const DIRECTIVE = /^\s*(SKIPCHECK|FEEDERS|FEEDSTRINGS|UNDEFVALS)\s*;/i;
|
|
9
|
+
// A comment line that carries no words: `####`, `# =====`, `#-----`.
|
|
10
|
+
const DECORATION = /^\s*#[\s#=\-*~_+.]*$/;
|
|
11
|
+
export function splitLines(text) {
|
|
12
|
+
return text.split(/\r?\n/);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Section markers: the rule directives (SKIPCHECK, FEEDERS, FEEDSTRINGS,
|
|
16
|
+
* UNDEFVALS) and the first worded line of every comment block — a run of
|
|
17
|
+
* consecutive `#` lines is how rule files label what follows. Decoration-only
|
|
18
|
+
* lines are skipped in favor of the block's first line with words in it.
|
|
19
|
+
*/
|
|
20
|
+
export function outlineRules(text) {
|
|
21
|
+
const lines = splitLines(text);
|
|
22
|
+
const outline = [];
|
|
23
|
+
let inBlock = false;
|
|
24
|
+
let blockLabelled = false;
|
|
25
|
+
let truncated = false;
|
|
26
|
+
const push = (i) => {
|
|
27
|
+
if (outline.length >= OUTLINE_MAX_ENTRIES) {
|
|
28
|
+
truncated = true;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const t = lines[i].trim();
|
|
32
|
+
outline.push({
|
|
33
|
+
line: i + 1,
|
|
34
|
+
text: t.length > OUTLINE_TEXT_MAX ? `${t.slice(0, OUTLINE_TEXT_MAX)}…` : t,
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
for (let i = 0; i < lines.length; i++) {
|
|
38
|
+
const line = lines[i];
|
|
39
|
+
const isComment = /^\s*#/.test(line);
|
|
40
|
+
if (!isComment) {
|
|
41
|
+
inBlock = false;
|
|
42
|
+
if (DIRECTIVE.test(line))
|
|
43
|
+
push(i);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (!inBlock) {
|
|
47
|
+
inBlock = true;
|
|
48
|
+
blockLabelled = false;
|
|
49
|
+
}
|
|
50
|
+
if (!blockLabelled && !DECORATION.test(line)) {
|
|
51
|
+
push(i);
|
|
52
|
+
blockLabelled = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { outline, truncated };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Lines `from`..`to` (1-based, inclusive), clamped to the text. Returns the
|
|
59
|
+
* slice verbatim — no line-number prefixes — so it can be quoted back into a
|
|
60
|
+
* `find` string for a rules patch.
|
|
61
|
+
*/
|
|
62
|
+
export function sliceLines(text, from, to) {
|
|
63
|
+
const lines = splitLines(text);
|
|
64
|
+
const start = Math.max(1, Math.min(from, lines.length));
|
|
65
|
+
const end = Math.max(start, Math.min(to, lines.length));
|
|
66
|
+
return { text: lines.slice(start - 1, end).join("\n"), from: start, to: end };
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=rules-outline.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Find/replace patching of a cube's rule text, so a one-line change to a
|
|
2
|
+
// 16 KB rule file does not mean shipping all 16 KB back through a tool call.
|
|
3
|
+
//
|
|
4
|
+
// Every `find` must occur exactly once in the text as it stands when that edit
|
|
5
|
+
// runs (edits apply in order). Zero matches means the caller's picture of the
|
|
6
|
+
// file is stale; two or more means the edit is ambiguous — both are rejected
|
|
7
|
+
// with the count, and nothing is written, because the patch is applied in
|
|
8
|
+
// memory first.
|
|
9
|
+
//
|
|
10
|
+
// Line endings: TM1 stores rules with CRLF, while a caller quoting a
|
|
11
|
+
// get_cube_rules slice sends LF. Matching runs on LF-normalized text, and the
|
|
12
|
+
// result is written back with the line ending the stored text used.
|
|
13
|
+
import { TM1Error, TM1ErrorCode } from "../types.js";
|
|
14
|
+
function lineOf(text, index) {
|
|
15
|
+
let line = 1;
|
|
16
|
+
for (let i = 0; i < index; i++)
|
|
17
|
+
if (text.charCodeAt(i) === 10)
|
|
18
|
+
line++;
|
|
19
|
+
return line;
|
|
20
|
+
}
|
|
21
|
+
export function applyRulesPatch(current, edits) {
|
|
22
|
+
const crlf = current.includes("\r\n");
|
|
23
|
+
let text = current.replace(/\r\n/g, "\n");
|
|
24
|
+
edits.forEach((edit, i) => {
|
|
25
|
+
const find = edit.find.replace(/\r\n/g, "\n");
|
|
26
|
+
if (find === "") {
|
|
27
|
+
throw new TM1Error({
|
|
28
|
+
code: TM1ErrorCode.VALIDATION_ERROR,
|
|
29
|
+
message: `edits[${i}].find is empty.`,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const at = [];
|
|
33
|
+
for (let p = text.indexOf(find); p !== -1; p = text.indexOf(find, p + 1))
|
|
34
|
+
at.push(p);
|
|
35
|
+
if (at.length !== 1) {
|
|
36
|
+
const where = at.length > 1
|
|
37
|
+
? ` at lines ${at
|
|
38
|
+
.slice(0, 10)
|
|
39
|
+
.map((p) => lineOf(text, p))
|
|
40
|
+
.join(", ")}${at.length > 10 ? ", …" : ""}`
|
|
41
|
+
: "";
|
|
42
|
+
throw new TM1Error({
|
|
43
|
+
code: TM1ErrorCode.VALIDATION_ERROR,
|
|
44
|
+
message: `edits[${i}].find matches ${at.length} times${where}; it must match exactly once. Nothing was written.`,
|
|
45
|
+
hint: at.length === 0
|
|
46
|
+
? "Re-read the current text with tm1_get_cube_rules (lineRange) and quote it verbatim — earlier edits in the same call apply first."
|
|
47
|
+
: "Extend find with neighbouring lines until it is unique.",
|
|
48
|
+
details: JSON.stringify({ edit: i, matches: at.length }),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const p = at[0];
|
|
52
|
+
text =
|
|
53
|
+
text.slice(0, p) +
|
|
54
|
+
edit.replace.replace(/\r\n/g, "\n") +
|
|
55
|
+
text.slice(p + find.length);
|
|
56
|
+
});
|
|
57
|
+
return crlf ? text.replace(/\n/g, "\r\n") : text;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=rules-patch.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile a user-supplied regex behind a ReDoS guard.
|
|
3
|
+
*
|
|
4
|
+
* Every `new RegExp(<user/LLM input>)` site must route through this helper:
|
|
5
|
+
* `safe-regex` rejects catastrophic-backtracking patterns (e.g. `(a+)+$`) before
|
|
6
|
+
* the pattern is ever constructed, so a malicious caller cannot freeze the Node
|
|
7
|
+
* event loop and DoS the server. Invalid patterns are normalized to a
|
|
8
|
+
* VALIDATION_ERROR instead of surfacing as a raw SyntaxError.
|
|
9
|
+
*
|
|
10
|
+
* @param pattern user-supplied regex source
|
|
11
|
+
* @param flags optional RegExp flags (e.g. "i", "gi")
|
|
12
|
+
* @param label human label for error messages (e.g. "nameRegex"); defaults to "regex"
|
|
13
|
+
*/
|
|
14
|
+
export declare function compileUserRegex(pattern: string, flags?: string, label?: string): RegExp;
|
|
15
|
+
//# sourceMappingURL=safe-regex.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import safeRegex from "safe-regex";
|
|
2
|
+
import { TM1Error, TM1ErrorCode } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Compile a user-supplied regex behind a ReDoS guard.
|
|
5
|
+
*
|
|
6
|
+
* Every `new RegExp(<user/LLM input>)` site must route through this helper:
|
|
7
|
+
* `safe-regex` rejects catastrophic-backtracking patterns (e.g. `(a+)+$`) before
|
|
8
|
+
* the pattern is ever constructed, so a malicious caller cannot freeze the Node
|
|
9
|
+
* event loop and DoS the server. Invalid patterns are normalized to a
|
|
10
|
+
* VALIDATION_ERROR instead of surfacing as a raw SyntaxError.
|
|
11
|
+
*
|
|
12
|
+
* @param pattern user-supplied regex source
|
|
13
|
+
* @param flags optional RegExp flags (e.g. "i", "gi")
|
|
14
|
+
* @param label human label for error messages (e.g. "nameRegex"); defaults to "regex"
|
|
15
|
+
*/
|
|
16
|
+
export function compileUserRegex(pattern, flags, label = "regex") {
|
|
17
|
+
if (!safeRegex(pattern)) {
|
|
18
|
+
throw new TM1Error({
|
|
19
|
+
code: TM1ErrorCode.VALIDATION_ERROR,
|
|
20
|
+
message: `${label} rejected: pattern risks catastrophic backtracking (ReDoS).`,
|
|
21
|
+
details: pattern,
|
|
22
|
+
hint: "Avoid nested unbounded quantifiers like (a+)+ or (.*)* — simplify or anchor the pattern.",
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return new RegExp(pattern, flags);
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
throw new TM1Error({
|
|
30
|
+
code: TM1ErrorCode.VALIDATION_ERROR,
|
|
31
|
+
message: `Invalid ${label}: ${e.message}`,
|
|
32
|
+
details: pattern,
|
|
33
|
+
hint: "Pattern must be a valid JavaScript regex. Escape backslashes and balance brackets/parens.",
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=safe-regex.js.map
|