pi-apexlang 0.2.2 → 0.4.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/README.md +22 -5
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/UPSTREAM.json +2 -2
- package/docs/assets/overview.en.png +0 -0
- package/docs/assets/overview.en.svg +89 -0
- package/docs/assets/overview.uk.png +0 -0
- package/docs/assets/overview.uk.svg +89 -0
- package/docs/en/README.md +41 -0
- package/docs/en/architecture.md +73 -0
- package/docs/en/getting-started.md +77 -0
- package/docs/en/maintenance.md +83 -0
- package/docs/en/tool-reference.md +85 -0
- package/docs/uk/README.md +41 -0
- package/docs/uk/architecture.md +73 -0
- package/docs/uk/getting-started.md +77 -0
- package/docs/uk/maintenance.md +83 -0
- package/docs/uk/tool-reference.md +85 -0
- package/extensions/apexlang/index.ts +19 -10
- package/extensions/lib/apexlang-cli.d.mts +1 -2
- package/extensions/lib/apexlang-cli.mjs +18 -13
- package/extensions/lib/apexlang-local-validate.mjs +83 -0
- package/extensions/lib/apexlang-local-validator.py +116 -0
- package/extensions/lib/apexlang-runtime-validate.mjs +76 -0
- package/package.json +2 -1
- package/skills/apexlang/APEXlang Skills and Workflows.md +325 -0
- package/skills/apexlang/README.md +6 -6
- package/skills/apexlang/RELEASE-NOTES.md +2 -2
- package/skills/apexlang/SKILL.md +24 -19
- package/skills/apexlang/agents/openai.yaml +4 -3
- package/skills/apexlang/assets/apex-generation/components.registry.json +1001 -16
- package/skills/apexlang/assets/apexlang/domains-catalog.json +6 -1
- package/skills/apexlang/assets/component-attributes.json +1924 -180
- package/skills/apexlang/assets/component-policies.json +19 -10
- package/skills/apexlang/assets/contracts/grammar-semantic-rules.json +134 -0
- package/skills/apexlang/assets/contracts/package-layers.json +56 -0
- package/skills/apexlang/assets/contracts/page-construction-packs.json +154 -0
- package/skills/apexlang/assets/contracts/page-patterns.json +119 -0
- package/skills/apexlang/assets/grammar/apexlang.ebnf +11743 -0
- package/skills/apexlang/assets/indexes/font-apex-icon-index.json +1699 -0
- package/skills/apexlang/assets/routing-catalog-main.json +11 -10
- package/skills/apexlang/assets/routing-load-policy.json +35 -9
- package/skills/apexlang/assets/rules-mapping.json +110 -2
- package/skills/apexlang/assets/rules.catalog.json +1298 -0
- package/skills/apexlang/assets/validator-fix-recipes.json +372 -17
- package/skills/apexlang/assets/workspace-intelligence.json +7 -10
- package/skills/apexlang/manifest.json +268 -12
- package/skills/apexlang/references/domains/README.md +1 -1
- package/skills/apexlang/references/domains/page-components/buttons.md +2 -2
- package/skills/apexlang/references/domains/page-components/page-items.md +3 -3
- package/skills/apexlang/references/domains/page-components/regions/region-display-selector/workflow-region-display-selector.md +69 -0
- package/skills/apexlang/references/domains/page-components/regions.md +1 -0
- package/skills/apexlang/references/domains/template-components/comments.md +61 -0
- package/skills/apexlang/references/domains/template-components/registry.md +2 -0
- package/skills/apexlang/references/domains/template-components/templates.md +47 -0
- package/skills/apexlang/references/domains/template-components/timeline.md +51 -0
- package/skills/apexlang/references/ops/one-message-router-contract.md +2 -2
- package/skills/apexlang/references/ops/runtime-gates/01-direct-sqlcl-import.md +1 -1
- package/skills/apexlang/references/ops/runtime-gates/02-direct-sqlcl-validate-gate.md +1 -1
- package/skills/apexlang/references/ops/runtime-gates.md +17 -16
- package/skills/apexlang/references/ops/sqlcl-agents/00-connection-gate.md +7 -7
- package/skills/apexlang/references/ops/sqlcl.md +7 -8
- package/skills/apexlang/references/policies/compiler-prop-map.md +6 -4
- package/skills/apexlang/references/policies/governance/00-governance.md +2 -2
- package/skills/apexlang/references/policies/memory-bank/00-guard/ai.guard.md +126 -922
- package/skills/apexlang/references/policies/memory-bank/20-data/apex.logic.md +3 -3
- package/skills/apexlang/references/policies/memory-bank/20-data/db.connection.md +9 -11
- package/skills/apexlang/references/policies/memory-bank/30-pages/apex.cards-page.md +95 -0
- package/skills/apexlang/references/policies/memory-bank/30-pages/apex.page.md +2 -2
- package/skills/apexlang/references/policies/memory-bank/30-pages/apex.smart-filter-search.md +145 -74
- package/skills/apexlang/references/policies/memory-bank/40-components/apex.region-interactions.md +9 -2
- package/skills/apexlang/references/policies/memory-bank/40-components/apex.region-media.md +6 -5
- package/skills/apexlang/references/policies/memory-bank/systemPatterns.md +9 -1
- package/skills/apexlang/references/workflows/apex-generation/agents/20-agent-draft.md +51 -232
- package/skills/apexlang/references/workflows/apex-generation/agents/30-agent-critique.md +49 -449
- package/skills/apexlang/references/workflows/apex-generation/agents/40-agent-revision.md +38 -238
- package/skills/apexlang/references/workflows/apex-generation/nlu/nlu-routing-test-matrix.md +8 -2
- package/skills/apexlang/references/workflows/apex-generation/nlu/nlu-routing-validation-notes.md +19 -3
- package/skills/apexlang/references/workflows/apex-generation/registry.md +15 -1
- package/skills/apexlang/references/workflows/apex-generation/templates.md +1 -1
- package/skills/apexlang/references/workflows/apex-generation.md +1 -1
- package/skills/apexlang/references/workflows/apexlang/apexlang-execution-model.md +5 -5
- package/skills/apexlang/references/workflows/apexlang/prompt-contracts.md +81 -10
- package/skills/apexlang/references/workflows/apexlang/workflow-create-app-from-fr-and-model.md +18 -7
- package/skills/apexlang/release-notes.json +156 -0
- package/skills/apexlang/runtime/grammar_contract.mjs +1166 -0
- package/skills/apexlang/runtime/internal/python/format_apexlang.py +210 -0
- package/skills/apexlang/runtime/internal/python/validate_apexlang.py +14142 -5843
- package/skills/apexlang/runtime/internal/python/validator_common.py +2 -0
- package/skills/apexlang/runtime/lib/catalogs.mjs +1026 -0
- package/skills/apexlang/runtime/lib/common.mjs +35 -0
- package/skills/apexlang/runtime/runtime.bundle.mjs +457 -57
- package/skills/apexlang/templates/items/combobox/combobox.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/date-picker/date-picker._common.md +1 -1
- package/skills/apexlang/templates/items/date-picker/date-picker.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/file-upload/file-upload._common.md +30 -24
- package/skills/apexlang/templates/items/file-upload/file-upload.compact-template.md +6 -0
- package/skills/apexlang/templates/items/file-upload/file-upload.explicit-defaults.md +23 -8
- package/skills/apexlang/templates/items/file-upload/file-upload.minimal.md +6 -0
- package/skills/apexlang/templates/items/hidden-item/hidden-item._common.md +1 -1
- package/skills/apexlang/templates/items/hidden-item/hidden-item.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/items._common.md +3 -2
- package/skills/apexlang/templates/items/list-manager/list-manager.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/markdown-editor/markdown-editor._common.md +1 -1
- package/skills/apexlang/templates/items/markdown-editor/markdown-editor.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/number-field/number-field._common.md +8 -6
- package/skills/apexlang/templates/items/number-field/number-field.explicit-defaults.md +12 -2
- package/skills/apexlang/templates/items/popup-lov/popup-lov.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/rich-text-editor/rich-text-editor._common.md +1 -1
- package/skills/apexlang/templates/items/rich-text-editor/rich-text-editor.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/select-many/standard.md +1 -1
- package/skills/apexlang/templates/items/shuttle/shuttle.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/switch/switch._common.md +8 -8
- package/skills/apexlang/templates/items/switch/switch.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/text-area/text-area._common.md +2 -3
- package/skills/apexlang/templates/items/text-area/text-area.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/text-area/text-area.required-length.md +1 -3
- package/skills/apexlang/templates/items/text-autocomplete/text-autocomplete.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/text-autocomplete/text-autocomplete.required-length.md +1 -3
- package/skills/apexlang/templates/items/text-field/text-field._common.md +2 -3
- package/skills/apexlang/templates/items/text-field/text-field.explicit-defaults.md +1 -1
- package/skills/apexlang/templates/items/text-field/text-field.required-length.md +1 -3
- package/skills/apexlang/templates/page-examples/faceted-search/faceted-search.example.md +0 -5
- package/skills/apexlang/templates/page-examples/form-page/form-page.example.md +0 -9
- package/skills/apexlang/templates/page-examples/interactive-report-page/interactive-report-page.example.md +2 -2
- package/skills/apexlang/templates/page-examples/login-page/login-page.example.md +0 -8
- package/skills/apexlang/templates/page-examples/task-definition-initiated-tasks-page/task-definition-initiated-tasks-page.example.md +7 -17
- package/skills/apexlang/templates/page-examples/task-definition-my-tasks-page/task-definition-my-tasks-page.example.md +7 -65
- package/skills/apexlang/templates/page-examples/task-definition-task-details/task-definition-task-details.example.md +38 -201
- package/skills/apexlang/templates/region-components/calendar/calendar.custom-styling.md +3 -1
- package/skills/apexlang/templates/region-components/calendar/calendar.faceted-search.md +3 -2
- package/skills/apexlang/templates/region-components/cards/README.md +12 -4
- package/skills/apexlang/templates/region-components/cards/cards._common.md +176 -37
- package/skills/apexlang/templates/region-components/cards/cards._index.md +2 -1
- package/skills/apexlang/templates/region-components/cards/cards.refresh-after-dialog.md +46 -0
- package/skills/apexlang/templates/region-components/cards/cards.refresh-on-change.md +58 -0
- package/skills/apexlang/templates/region-components/cards/cards.rest-source.md +54 -18
- package/skills/apexlang/templates/region-components/cards/cards.standard.md +37 -21
- package/skills/apexlang/templates/region-components/chart/chart._series._common.md +1 -4
- package/skills/apexlang/templates/region-components/chart/chart.pie.md +6 -2
- package/skills/apexlang/templates/region-components/chart/chart.status-meter-gauge.md +1 -1
- package/skills/apexlang/templates/region-components/chart/chart.stock.md +2 -0
- package/skills/apexlang/templates/region-components/chart/features/chart.feature-chart-links.md +9 -7
- package/skills/apexlang/templates/region-components/faceted-search/faceted-search._common.md +1 -14
- package/skills/apexlang/templates/region-components/form/form._items._common.md +1 -5
- package/skills/apexlang/templates/region-components/interactive-report/interactive-report._columns._common.md +2 -6
- package/skills/apexlang/templates/region-components/interactive-report/interactive-report.page-header-actions.md +1 -7
- package/skills/apexlang/templates/region-components/list/README.md +1 -1
- package/skills/apexlang/templates/region-components/list/list._common.md +1 -1
- package/skills/apexlang/templates/region-components/map/map.backgrounds.md +12 -10
- package/skills/apexlang/templates/region-components/map/map.layer.extruded-polygons.md +16 -12
- package/skills/apexlang/templates/region-components/map/map.layer.heat-map.md +10 -7
- package/skills/apexlang/templates/region-components/map/map.layer.lines.md +10 -8
- package/skills/apexlang/templates/region-components/map/map.layer.polygons.md +21 -18
- package/skills/apexlang/templates/region-components/map/map.region.background-custom.md +25 -19
- package/skills/apexlang/templates/region-components/map/map.region.background-shared.md +19 -13
- package/skills/apexlang/templates/region-components/map/map.region.bbox-sql.md +13 -13
- package/skills/apexlang/templates/region-components/map/map.region.bbox-static.md +2 -2
- package/skills/apexlang/templates/region-components/map/map.region.browser-location.md +3 -7
- package/skills/apexlang/templates/region-components/map/map.region.init-position-sql.md +7 -7
- package/skills/apexlang/templates/region-components/region-display-selector/README.md +5 -2
- package/skills/apexlang/templates/region-components/region-display-selector/region-display-selector._common.md +60 -7
- package/skills/apexlang/templates/region-components/region-display-selector/region-display-selector._index.md +4 -1
- package/skills/apexlang/templates/region-components/region-display-selector/region-display-selector.permutations.md +55 -0
- package/skills/apexlang/templates/region-components/region-display-selector/region-display-selector.standard.md +91 -5
- package/skills/apexlang/templates/region-components/smart-filter-search/README.md +6 -2
- package/skills/apexlang/templates/region-components/smart-filter-search/smart-filter-search._common.md +107 -46
- package/skills/apexlang/templates/region-components/smart-filter-search/smart-filter-search._index.md +4 -3
- package/skills/apexlang/templates/region-components/smart-filter-search/smart-filter-search.standard.md +33 -17
- package/skills/apexlang/templates/shared-components/component-settings/component-settings._common.md +1 -0
- package/skills/apexlang/templates/shared-components/component-settings.example.md +1 -0
- package/skills/apexlang/templates/shared-components/email-templates.example.md +1 -1
- package/skills/apexlang/templates/shared-components/rest-data-sources/example_rest_data_source.example.md +40 -46
- package/skills/apexlang/templates/shared-components/task-definitions/action-task.example.md +2 -30
- package/skills/apexlang/templates/shared-components/task-definitions/approve-request.example.md +3 -31
- package/skills/apexlang/templates/template-components/README.md +27 -15
- package/skills/apexlang/templates/template-components/avatar/README.md +56 -0
- package/skills/apexlang/templates/template-components/avatar/avatar._common.md +149 -0
- package/skills/apexlang/templates/template-components/avatar/avatar._index.md +42 -0
- package/skills/apexlang/templates/template-components/{avatar._template_options.md → avatar/avatar._template_options.md} +1 -1
- package/skills/apexlang/templates/template-components/avatar/avatar.report-icon.md +48 -0
- package/skills/apexlang/templates/template-components/avatar/avatar.report-image-url-column.md +62 -0
- package/skills/apexlang/templates/template-components/avatar/avatar.report-initials.md +54 -0
- package/skills/apexlang/templates/template-components/badge/README.md +38 -0
- package/skills/apexlang/templates/template-components/badge/badge._common.md +183 -0
- package/skills/apexlang/templates/template-components/badge/badge._index.md +20 -0
- package/skills/apexlang/templates/template-components/badge/badge.report-link.md +66 -0
- package/skills/apexlang/templates/template-components/badge/badge.report-minimal.md +76 -0
- package/skills/apexlang/templates/template-components/comments/README.md +20 -0
- package/skills/apexlang/templates/template-components/comments/comments._common.md +43 -0
- package/skills/apexlang/templates/template-components/comments/comments._index.md +25 -0
- package/skills/apexlang/templates/template-components/{comments._template_options.md → comments/comments._template_options.md} +2 -1
- package/skills/apexlang/templates/template-components/comments/comments.apex-task-comments.md +77 -0
- package/skills/apexlang/templates/template-components/comments/comments.partial-column.md +120 -0
- package/skills/apexlang/templates/template-components/comments/comments.permutations.md +425 -0
- package/skills/apexlang/templates/template-components/content-row/README.md +1 -1
- package/skills/apexlang/templates/template-components/content-row/content-row._common.md +1 -1
- package/skills/apexlang/templates/template-components/content-row/content-row._index.md +1 -1
- package/skills/apexlang/templates/template-components/content-row/content-row._template_options.md +1 -1
- package/skills/apexlang/templates/template-components/flexbox-container/README.md +9 -0
- package/skills/apexlang/templates/template-components/flexbox-container/flexbox-container._index.md +13 -0
- package/skills/apexlang/templates/template-components/media-list/README.md +100 -0
- package/skills/apexlang/templates/template-components/media-list/media-list._common.md +174 -0
- package/skills/apexlang/templates/template-components/media-list/media-list._index.md +50 -0
- package/skills/apexlang/templates/template-components/{media-list._template_options.md → media-list/media-list._template_options.md} +8 -2
- package/skills/apexlang/templates/template-components/media-list/media-list.partial.md +50 -0
- package/skills/apexlang/templates/template-components/media-list/media-list.report-avatar-badge.md +76 -0
- package/skills/apexlang/templates/template-components/media-list/media-list.report-base.md +71 -0
- package/skills/apexlang/templates/template-components/media-list/media-list.report-grouped.md +40 -0
- package/skills/apexlang/templates/template-components/media-list/media-list.report-layouts.md +50 -0
- package/skills/apexlang/templates/template-components/media-list/media-list.report-link.md +53 -0
- package/skills/apexlang/templates/template-components/metric-card/README.md +19 -4
- package/skills/apexlang/templates/template-components/metric-card/metric-card._common.md +122 -29
- package/skills/apexlang/templates/template-components/metric-card/metric-card._index.md +6 -0
- package/skills/apexlang/templates/template-components/metric-card/metric-card._template_options.md +47 -2
- package/skills/apexlang/templates/template-components/metric-card/metric-card.partial-minimal.md +51 -0
- package/skills/apexlang/templates/template-components/metric-card/metric-card.permutations.md +56 -0
- package/skills/apexlang/templates/template-components/metric-card/metric-card.report-avatar-badge.md +98 -0
- package/skills/apexlang/templates/template-components/metric-card/metric-card.report-grouping-selection.md +131 -0
- package/skills/apexlang/templates/template-components/metric-card/metric-card.report-link.md +66 -0
- package/skills/apexlang/templates/template-components/metric-card/metric-card.report-minimal.md +97 -0
- package/skills/apexlang/templates/template-components/template-components.registry.json +90 -1
- package/skills/apexlang/templates/template-components/timeline/README.md +19 -0
- package/skills/apexlang/templates/template-components/timeline/timeline._common.md +43 -0
- package/skills/apexlang/templates/template-components/timeline/timeline._index.md +24 -0
- package/skills/apexlang/templates/template-components/{timeline._template_options.md → timeline/timeline._template_options.md} +2 -1
- package/skills/apexlang/templates/template-components/timeline/timeline.permutations.md +399 -0
- package/skills/apexlang/templates/template-components/timeline/timeline.report-sample-data.md +168 -0
- package/skills/apexlang/templates/workspace-components/credentials/credentials-for-open-ai.example.md +1 -1
- package/skills/apexlang/templates/workspace-components/generative-ai-services/open-ai.example.md +8 -6
- package/skills/apexlang/tools/apexctl.mjs +167 -4
- package/skills/apexlang/tools/compiler-truth-audit.mjs +95 -63
- package/skills/apexlang/tools/query-valid-props-context.mjs +30 -0
- package/skills/apexlang/tools/query-valid-props-normalize.mjs +1 -0
- package/skills/apexlang/tools/query-valid-props-runtime.mjs +13 -8
- package/skills/apexlang/tools/query-valid-props-semantics.mjs +391 -0
- package/skills/apexlang/tools/query-valid-props-template-components.mjs +15 -1
- package/skills/apexlang/tools/query-valid-props.mjs +198 -216
- /package/skills/apexlang/templates/template-components/{badge._template_options.md → badge/badge._template_options.md} +0 -0
- /package/skills/apexlang/templates/template-components/{flexbox-container._template_options.md → flexbox-container/flexbox-container._template_options.md} +0 -0
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
apexlangToolPath,
|
|
16
16
|
collectFiles,
|
|
17
17
|
ensureDir,
|
|
18
|
+
normalizeApxLineEndings,
|
|
18
19
|
readJson,
|
|
19
20
|
removeDir,
|
|
20
21
|
runCommand,
|
|
@@ -154,12 +155,12 @@ async function cleanupDraftRun(stagingRunRoot) {
|
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
/**
|
|
157
|
-
* Public workspace probe that discovers app, metadata,
|
|
158
|
+
* Public workspace probe that discovers app, metadata, requirements, and DB/runtime prompt context.
|
|
158
159
|
*/
|
|
159
160
|
|
|
160
161
|
|
|
161
162
|
/**
|
|
162
|
-
* Default discovery policy for app roots, metadata files, bounded scans, and
|
|
163
|
+
* Default discovery policy for app roots, metadata files, bounded scans, and discovery-first DB prompts.
|
|
163
164
|
*/
|
|
164
165
|
const DEFAULT_CONFIG = {
|
|
165
166
|
app_discovery: {
|
|
@@ -190,28 +191,26 @@ const DEFAULT_CONFIG = {
|
|
|
190
191
|
allowed_extensions: [".json", ".yaml", ".yml", ".md", ".sql", ".xml"]
|
|
191
192
|
},
|
|
192
193
|
db_prompt_flow: {
|
|
193
|
-
prompt_mode: "
|
|
194
|
+
prompt_mode: "discovery_first_connection_flow",
|
|
194
195
|
interactive_only: true,
|
|
195
196
|
discovery_steps: ["inspect_offline_schema_registry", "scan_saved_sqlcl_connections"],
|
|
196
197
|
metadata_preference: "prefer_authoritative_offline_context",
|
|
197
|
-
required_live_inputs: ["db_connection_name"
|
|
198
|
-
auto_bind_single_saved_connection:
|
|
198
|
+
required_live_inputs: ["db_connection_name"],
|
|
199
|
+
auto_bind_single_saved_connection: true,
|
|
199
200
|
manual_entry: {
|
|
200
201
|
input_name: "db_connection_name",
|
|
201
|
-
|
|
202
|
-
workspace_context_field: "db_context.workspace.name",
|
|
203
|
-
prompt: "Provide db_connection_name and the corresponding APEX workspace name for this workflow."
|
|
202
|
+
prompt: "Provide db_connection_name because no usable saved SQLcl connection could be resolved."
|
|
204
203
|
},
|
|
205
204
|
workspace_prompt: {
|
|
206
205
|
input_name: "apex_workspace_name",
|
|
207
206
|
context_field: "db_context.workspace.name",
|
|
208
|
-
prompt: "
|
|
207
|
+
prompt: "Choose the workspace reported by the active runtime when it cannot resolve a unique workspace."
|
|
209
208
|
},
|
|
210
209
|
multiple_connection_prompt: {
|
|
211
210
|
source: "saved_sqlcl_connections",
|
|
212
211
|
prompt_mode: "select_from_list",
|
|
213
212
|
empty_list_prompt:
|
|
214
|
-
"No saved SQLcl connections were found. Provide db_connection_name
|
|
213
|
+
"No saved SQLcl connections were found. Provide db_connection_name if live DB context is still required, or continue only with authoritative offline metadata."
|
|
215
214
|
},
|
|
216
215
|
offline_override: {
|
|
217
216
|
prompt_mode: "explicit_opt_in",
|
|
@@ -223,7 +222,7 @@ const DEFAULT_CONFIG = {
|
|
|
223
222
|
disables_apex_import: true
|
|
224
223
|
},
|
|
225
224
|
workspace_selection: {
|
|
226
|
-
prompt_mode: "
|
|
225
|
+
prompt_mode: "runtime_ambiguity_or_new_app_only",
|
|
227
226
|
persistence: "session_context_only",
|
|
228
227
|
context_path: "APEXLANG_OUTPUT_ROOT/context-resolution.json",
|
|
229
228
|
context_field: "db_context.workspace",
|
|
@@ -1740,20 +1739,20 @@ function normalizeRuntimeProvider(value = DEFAULT_RUNTIME_PROVIDER) {
|
|
|
1740
1739
|
return DEFAULT_RUNTIME_PROVIDER;
|
|
1741
1740
|
}
|
|
1742
1741
|
|
|
1743
|
-
function decodeHtmlEntities(value = "") {
|
|
1742
|
+
export function decodeHtmlEntities(value = "") {
|
|
1744
1743
|
return String(value)
|
|
1745
1744
|
.replace(/ /gi, " ")
|
|
1746
|
-
.replace(/&/gi, "&")
|
|
1747
1745
|
.replace(/</gi, "<")
|
|
1748
1746
|
.replace(/>/gi, ">")
|
|
1749
1747
|
.replace(/"/gi, "\"")
|
|
1750
|
-
.replace(/'/gi, "'")
|
|
1748
|
+
.replace(/'/gi, "'")
|
|
1749
|
+
.replace(/&/gi, "&");
|
|
1751
1750
|
}
|
|
1752
1751
|
|
|
1753
|
-
function extractTextFromHtml(html = "") {
|
|
1752
|
+
export function extractTextFromHtml(html = "") {
|
|
1754
1753
|
return decodeHtmlEntities(
|
|
1755
1754
|
String(html)
|
|
1756
|
-
.replace(/<script\b[^>]*>[\s\S]*?<\/script
|
|
1755
|
+
.replace(/<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/gi, " ")
|
|
1757
1756
|
.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, " ")
|
|
1758
1757
|
.replace(RUNTIME_TEXT_TAG_STRIP_PATTERN, " ")
|
|
1759
1758
|
.replace(/\s+/g, " ")
|
|
@@ -1802,22 +1801,22 @@ function safeArtifactName(prefix, detail, suffix) {
|
|
|
1802
1801
|
return `${sanitizeArtifactFilePart(prefix)}-${sanitizeArtifactFilePart(detail)}.${suffix}`;
|
|
1803
1802
|
}
|
|
1804
1803
|
|
|
1805
|
-
async function requestRuntimeUrl(targetUrl, { maxRedirects = 5 } = {}) {
|
|
1804
|
+
export async function requestRuntimeUrl(targetUrl, { maxRedirects = 5, requestImpl } = {}) {
|
|
1806
1805
|
const visited = [];
|
|
1807
1806
|
|
|
1808
1807
|
async function execute(currentUrl, redirectsRemaining) {
|
|
1809
1808
|
const parsedUrl = new URL(currentUrl);
|
|
1810
1809
|
const client = parsedUrl.protocol === "https:" ? https : http;
|
|
1811
1810
|
const result = await new Promise((resolve, reject) => {
|
|
1812
|
-
const
|
|
1811
|
+
const request = requestImpl ?? client.request.bind(client);
|
|
1812
|
+
const req = request(
|
|
1813
1813
|
parsedUrl,
|
|
1814
1814
|
{
|
|
1815
1815
|
method: "GET",
|
|
1816
1816
|
headers: {
|
|
1817
1817
|
"user-agent": "apexctl-runtime-verifier/1.0",
|
|
1818
1818
|
accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
1819
|
-
}
|
|
1820
|
-
rejectUnauthorized: false
|
|
1819
|
+
}
|
|
1821
1820
|
},
|
|
1822
1821
|
(res) => {
|
|
1823
1822
|
const chunks = [];
|
|
@@ -2082,7 +2081,8 @@ async function verifyRuntimeUiWithHttpFallback({
|
|
|
2082
2081
|
runtimePageUrl = "",
|
|
2083
2082
|
pageId = "",
|
|
2084
2083
|
artifactDir = DEFAULT_RUNTIME_VERIFY_ARTIFACT_DIR,
|
|
2085
|
-
runCommandImpl
|
|
2084
|
+
runCommandImpl,
|
|
2085
|
+
requestRuntimeUrlImpl = requestRuntimeUrl
|
|
2086
2086
|
}) {
|
|
2087
2087
|
const baseUrlResolution = runtimePageUrl
|
|
2088
2088
|
? { status: "pass", runtimeBaseUrl: "", checkedCandidates: [] }
|
|
@@ -2179,7 +2179,7 @@ async function verifyRuntimeUiWithHttpFallback({
|
|
|
2179
2179
|
}
|
|
2180
2180
|
|
|
2181
2181
|
try {
|
|
2182
|
-
const response = await
|
|
2182
|
+
const response = await requestRuntimeUrlImpl(target.runtimeUrl);
|
|
2183
2183
|
const htmlArtifactPath = path.join(
|
|
2184
2184
|
artifactDir,
|
|
2185
2185
|
safeArtifactName(`runtime-page-${targetsResult.appIdentity.applicationId || "app"}`, String(target.pageId), "html")
|
|
@@ -2271,6 +2271,7 @@ async function verifyRuntimeUiWithHttpFallback({
|
|
|
2271
2271
|
export async function verifyRuntimeUi(options = {}) {
|
|
2272
2272
|
const deps = {
|
|
2273
2273
|
runCommand,
|
|
2274
|
+
requestRuntimeUrl,
|
|
2274
2275
|
verifyRuntimeWithChromeDevtools: null,
|
|
2275
2276
|
...options._deps
|
|
2276
2277
|
};
|
|
@@ -2314,7 +2315,8 @@ export async function verifyRuntimeUi(options = {}) {
|
|
|
2314
2315
|
runtimePageUrl: options.runtimePageUrl,
|
|
2315
2316
|
pageId: options.pageId,
|
|
2316
2317
|
artifactDir,
|
|
2317
|
-
runCommandImpl: deps.runCommand
|
|
2318
|
+
runCommandImpl: deps.runCommand,
|
|
2319
|
+
requestRuntimeUrlImpl: deps.requestRuntimeUrl
|
|
2318
2320
|
});
|
|
2319
2321
|
result.payload.runtime_verification_provider_requested = requestedProvider;
|
|
2320
2322
|
if (requestedProvider === RUNTIME_PROVIDER_CHROME) {
|
|
@@ -3287,6 +3289,9 @@ function buildRoundtripSummary(base) {
|
|
|
3287
3289
|
runtime_verification_retry_required: false,
|
|
3288
3290
|
capability_state: "",
|
|
3289
3291
|
local_validation_policy: "advisory",
|
|
3292
|
+
line_endings_status: "not-run",
|
|
3293
|
+
line_endings_checked_files: 0,
|
|
3294
|
+
line_endings_normalized_files: [],
|
|
3290
3295
|
local_validation_execution_status: "not-run",
|
|
3291
3296
|
local_validation_status: "not-run",
|
|
3292
3297
|
local_validation_entrypoint_requested: LOCAL_VALIDATION_REQUESTED_ENTRYPOINT,
|
|
@@ -3673,6 +3678,14 @@ function componentAttributesPath() {
|
|
|
3673
3678
|
: path.resolve(apexlangToolPath("..", "..", "..", "ai-context", "memory-bank", "component-attributes.json"));
|
|
3674
3679
|
}
|
|
3675
3680
|
|
|
3681
|
+
function grammarContractToolPath() {
|
|
3682
|
+
return apexlangToolPath("public", "grammar_contract.mjs");
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3685
|
+
function apexlangValidatorPath() {
|
|
3686
|
+
return apexlangToolPath("internal", "python", "validate_apexlang.py");
|
|
3687
|
+
}
|
|
3688
|
+
|
|
3676
3689
|
async function readJsonIfExists(filePath) {
|
|
3677
3690
|
try {
|
|
3678
3691
|
return await readJson(filePath);
|
|
@@ -3937,17 +3950,129 @@ async function loadVscodeProblemsEvidence({ vscodeProblemsPath = "", appPath = "
|
|
|
3937
3950
|
};
|
|
3938
3951
|
}
|
|
3939
3952
|
|
|
3940
|
-
function
|
|
3953
|
+
function grammarPropertyContract(definition = "", requiredPaths = new Set(), pathPrefix = "") {
|
|
3954
|
+
const allowedProperties = [];
|
|
3955
|
+
const propertyEnums = {};
|
|
3956
|
+
for (const line of String(definition || "").split(/\r?\n/)) {
|
|
3957
|
+
const propertyMatch = line.match(/"([A-Za-z][A-Za-z0-9]*)"\s*":"\s*<ws>/);
|
|
3958
|
+
if (!propertyMatch) continue;
|
|
3959
|
+
const propertyName = propertyMatch[1];
|
|
3960
|
+
if (!allowedProperties.includes(propertyName)) allowedProperties.push(propertyName);
|
|
3961
|
+
const enumMatch = line.match(/<ws>\s*\(([^)]+)\)/);
|
|
3962
|
+
if (enumMatch) {
|
|
3963
|
+
const values = [...enumMatch[1].matchAll(/"([^"]+)"/g)].map((match) => match[1]);
|
|
3964
|
+
if (values.length) propertyEnums[propertyName] = [...new Set(values)];
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
return {
|
|
3968
|
+
allowedProperties,
|
|
3969
|
+
requiredProperties: allowedProperties.filter((propertyName) => requiredPaths.has(`${pathPrefix}${propertyName}`)),
|
|
3970
|
+
propertyEnums
|
|
3971
|
+
};
|
|
3972
|
+
}
|
|
3973
|
+
|
|
3974
|
+
function grammarChildContract(grammarContract = {}, selector = "region.column") {
|
|
3975
|
+
const resolved = (grammarContract?.compilerContract?.resolvedChildren || [])
|
|
3976
|
+
.find(({ parent, child }) => `${parent}.${child}` === selector);
|
|
3977
|
+
if (!resolved) return null;
|
|
3978
|
+
const productions = new Map((grammarContract.productions || []).map(({ name, definition }) => [name, definition]));
|
|
3979
|
+
const root = resolved.grammarProduction;
|
|
3980
|
+
const requiredPaths = new Set(
|
|
3981
|
+
(grammarContract?.compilerContract?.requiredActiveProperties || [])
|
|
3982
|
+
// Compiler defaults are not optionality. Keep a property required unless
|
|
3983
|
+
// the target-build contract explicitly marks it otherwise.
|
|
3984
|
+
.filter(({ compilerRequired }) => compilerRequired !== false)
|
|
3985
|
+
.map(({ path: propertyPath }) => propertyPath)
|
|
3986
|
+
);
|
|
3987
|
+
const direct = grammarPropertyContract(
|
|
3988
|
+
productions.get(`${root}-direct-property`) || "",
|
|
3989
|
+
requiredPaths,
|
|
3990
|
+
`${selector}.`
|
|
3991
|
+
);
|
|
3992
|
+
const namedDeclaration = resolved.componentIdPolicy === "required-as-name" || direct.allowedProperties.includes("name");
|
|
3993
|
+
if (namedDeclaration) {
|
|
3994
|
+
direct.allowedProperties = direct.allowedProperties.filter((propertyName) => propertyName !== "name");
|
|
3995
|
+
direct.requiredProperties = direct.requiredProperties.filter((propertyName) => propertyName !== "name");
|
|
3996
|
+
delete direct.propertyEnums.name;
|
|
3997
|
+
}
|
|
3998
|
+
|
|
3999
|
+
const childContract = {
|
|
4000
|
+
...direct,
|
|
4001
|
+
allowedBlocks: [],
|
|
4002
|
+
requiredBlocks: [],
|
|
4003
|
+
declarationStyle: namedDeclaration ? "named" : "unnamed",
|
|
4004
|
+
declaration: resolved.declaration,
|
|
4005
|
+
componentIdPolicy: resolved.componentIdPolicy,
|
|
4006
|
+
compilerComponentTypeId: resolved.compilerComponentTypeId,
|
|
4007
|
+
grammarProduction: resolved.grammarProduction,
|
|
4008
|
+
conformance: (grammarContract.compilerContract?.grammarConformance || [])
|
|
4009
|
+
.find((entry) => entry.selector === selector) || null
|
|
4010
|
+
};
|
|
4011
|
+
const groupDefinition = productions.get(`${root}-group-block`) || "";
|
|
4012
|
+
for (const referenceMatch of groupDefinition.matchAll(/<([^>]+)>/g)) {
|
|
4013
|
+
const productionName = referenceMatch[1];
|
|
4014
|
+
const blockDefinition = productions.get(productionName) || "";
|
|
4015
|
+
const blockName = blockDefinition.match(/::=.*?"([A-Za-z][A-Za-z0-9]*)"\s*<ws>\s*"\{"/)?.[1];
|
|
4016
|
+
if (!blockName) continue;
|
|
4017
|
+
const blockContract = grammarPropertyContract(
|
|
4018
|
+
productions.get(`${productionName}-property`) || "",
|
|
4019
|
+
requiredPaths,
|
|
4020
|
+
`${selector}.${blockName}.`
|
|
4021
|
+
);
|
|
4022
|
+
childContract.allowedBlocks.push(blockName);
|
|
4023
|
+
if (blockContract.requiredProperties.length) childContract.requiredBlocks.push(blockName);
|
|
4024
|
+
childContract[blockName] = blockContract;
|
|
4025
|
+
}
|
|
4026
|
+
return childContract;
|
|
4027
|
+
}
|
|
4028
|
+
|
|
4029
|
+
function copyContractNode(node = {}) {
|
|
4030
|
+
const copied = {
|
|
4031
|
+
allowedProperties: node.allowedProperties || [],
|
|
4032
|
+
requiredProperties: node.requiredProperties || [],
|
|
4033
|
+
allowedBlocks: node.allowedBlocks || [],
|
|
4034
|
+
requiredBlocks: node.requiredBlocks || [],
|
|
4035
|
+
propertyEnums: node.propertyEnums || {},
|
|
4036
|
+
childComponents: {}
|
|
4037
|
+
};
|
|
4038
|
+
for (const key of ["grammarRequiredProperties", "compilerRequiredProperties", "compilerDefaultedProperties", "conformance"]) {
|
|
4039
|
+
if (node[key] !== undefined) copied[key] = node[key];
|
|
4040
|
+
}
|
|
4041
|
+
for (const key of ["declarationStyle", "declaration", "componentIdPolicy", "compilerComponentTypeId", "grammarProduction"]) {
|
|
4042
|
+
if (node[key] !== undefined) copied[key] = node[key];
|
|
4043
|
+
}
|
|
4044
|
+
for (const [childName, childNode] of Object.entries(node || {})) {
|
|
4045
|
+
if (!childNode || typeof childNode !== "object" || Array.isArray(childNode)) continue;
|
|
4046
|
+
if (!childNode.allowedProperties && !childNode.requiredProperties && !childNode.allowedBlocks) continue;
|
|
4047
|
+
copied.childComponents[childName] = copyContractNode(childNode);
|
|
4048
|
+
}
|
|
4049
|
+
return copied;
|
|
4050
|
+
}
|
|
4051
|
+
|
|
4052
|
+
export function buildComponentContracts(
|
|
4053
|
+
componentAttributes = {},
|
|
4054
|
+
{ build = "", compilerReport = {}, source = "component-attributes", mediaListGrammarContract = null } = {}
|
|
4055
|
+
) {
|
|
4056
|
+
const resolvedAttributes = structuredClone(componentAttributes || {});
|
|
4057
|
+
const mediaListPolicy = resolvedAttributes?.components?.region?.mediaList || null;
|
|
4058
|
+
const policyBuild = componentAttributes?.compilerProvenance?.buildID || "unknown";
|
|
4059
|
+
const mediaListColumn = mediaListGrammarContract
|
|
4060
|
+
? grammarChildContract(mediaListGrammarContract, "region.column")
|
|
4061
|
+
: null;
|
|
4062
|
+
const mediaListSourceLocations = mediaListGrammarContract?.compilerContract
|
|
4063
|
+
? mediaListGrammarContract.compilerContract.mediaListSourceLocations
|
|
4064
|
+
|| (mediaListGrammarContract.compilerContract.assumptions || [])
|
|
4065
|
+
.map((entry) => /^region\.source\.location=(.+)$/.exec(String(entry))?.[1] || "")
|
|
4066
|
+
.filter(Boolean)
|
|
4067
|
+
: [];
|
|
4068
|
+
if (mediaListColumn && resolvedAttributes?.components?.region?.mediaList) {
|
|
4069
|
+
resolvedAttributes.components.region.mediaList.column = mediaListColumn;
|
|
4070
|
+
}
|
|
3941
4071
|
const components = {};
|
|
3942
|
-
for (const [componentType, families] of Object.entries(
|
|
4072
|
+
for (const [componentType, families] of Object.entries(resolvedAttributes.components || {})) {
|
|
3943
4073
|
components[componentType] = {};
|
|
3944
4074
|
for (const [familyName, contract] of Object.entries(families || {})) {
|
|
3945
|
-
components[componentType][familyName] =
|
|
3946
|
-
allowedBlocks: contract.allowedBlocks || [],
|
|
3947
|
-
requiredBlocks: contract.requiredBlocks || [],
|
|
3948
|
-
propertyEnums: contract.propertyEnums || {},
|
|
3949
|
-
childComponents: {}
|
|
3950
|
-
};
|
|
4075
|
+
components[componentType][familyName] = copyContractNode(contract);
|
|
3951
4076
|
for (const [childName, childContract] of Object.entries(contract || {})) {
|
|
3952
4077
|
if (!childContract || typeof childContract !== "object" || Array.isArray(childContract)) {
|
|
3953
4078
|
continue;
|
|
@@ -3955,30 +4080,210 @@ function buildComponentContracts(componentAttributes = {}, { build = "", compile
|
|
|
3955
4080
|
if (!childContract.allowedProperties && !childContract.requiredProperties && !childContract.allowedBlocks) {
|
|
3956
4081
|
continue;
|
|
3957
4082
|
}
|
|
3958
|
-
components[componentType][familyName].childComponents[childName] =
|
|
3959
|
-
allowedProperties: childContract.allowedProperties || [],
|
|
3960
|
-
requiredProperties: childContract.requiredProperties || [],
|
|
3961
|
-
allowedBlocks: childContract.allowedBlocks || [],
|
|
3962
|
-
requiredBlocks: childContract.requiredBlocks || [],
|
|
3963
|
-
propertyEnums: childContract.propertyEnums || {}
|
|
3964
|
-
};
|
|
4083
|
+
components[componentType][familyName].childComponents[childName] = copyContractNode(childContract);
|
|
3965
4084
|
}
|
|
3966
4085
|
}
|
|
3967
4086
|
}
|
|
3968
4087
|
return {
|
|
3969
4088
|
generated_at: new Date().toISOString(),
|
|
3970
|
-
build:
|
|
4089
|
+
build: mediaListGrammarContract?.compilerContract?.buildID
|
|
4090
|
+
|| build
|
|
4091
|
+
|| compilerReport?.compilerTruth?.buildID
|
|
4092
|
+
|| componentAttributes?.compilerProvenance?.buildID
|
|
4093
|
+
|| "unknown",
|
|
3971
4094
|
source,
|
|
3972
4095
|
warnings_as_errors: true,
|
|
3973
4096
|
valid_component_types: Object.keys(components).sort(),
|
|
3974
4097
|
deprecated_slots: componentAttributes?.deprecatedSlots || componentAttributes?.deprecated_slots || [],
|
|
3975
4098
|
known_warning_as_error_cases: compilerReport?.warningAsErrorCases || componentAttributes?.knownWarningAsErrorCases || [],
|
|
3976
4099
|
compiler_truth_status: compilerReport?.status || "unknown",
|
|
3977
|
-
compiler_provenance:
|
|
4100
|
+
compiler_provenance: mediaListGrammarContract?.compilerContract
|
|
4101
|
+
? {
|
|
4102
|
+
buildID: mediaListGrammarContract.compilerContract.buildID,
|
|
4103
|
+
metadataHash: mediaListGrammarContract.compilerContract.metadataHash,
|
|
4104
|
+
normalizerVersion: mediaListGrammarContract.compilerContract.normalizerVersion,
|
|
4105
|
+
source: mediaListGrammarContract.compilerContract.source
|
|
4106
|
+
}
|
|
4107
|
+
: componentAttributes?.compilerProvenance || null,
|
|
4108
|
+
compiler_resolutions: mediaListColumn
|
|
4109
|
+
? {
|
|
4110
|
+
"region.mediaList.column": {
|
|
4111
|
+
compilerComponentTypeId: mediaListColumn.compilerComponentTypeId,
|
|
4112
|
+
grammarProduction: mediaListColumn.grammarProduction,
|
|
4113
|
+
declarationStyle: mediaListColumn.declarationStyle,
|
|
4114
|
+
declaration: mediaListColumn.declaration,
|
|
4115
|
+
componentIdPolicy: mediaListColumn.componentIdPolicy,
|
|
4116
|
+
assumptions: mediaListGrammarContract.compilerContract.assumptions,
|
|
4117
|
+
conformance: mediaListColumn.conformance || null
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
: {},
|
|
4121
|
+
capability_provenance: mediaListPolicy
|
|
4122
|
+
? {
|
|
4123
|
+
"region.mediaList.column": {
|
|
4124
|
+
source: mediaListColumn ? "compiler-runtime-metadata" : "curated-component-policy",
|
|
4125
|
+
compilerDerived: Boolean(mediaListColumn),
|
|
4126
|
+
build: mediaListColumn
|
|
4127
|
+
? mediaListGrammarContract.compilerContract.buildID
|
|
4128
|
+
: policyBuild,
|
|
4129
|
+
status: mediaListColumn ? "resolved" : "policy_fallback",
|
|
4130
|
+
sourceLocations: mediaListColumn ? mediaListSourceLocations : []
|
|
4131
|
+
},
|
|
4132
|
+
"region.mediaList.settings": {
|
|
4133
|
+
source: "curated-component-policy",
|
|
4134
|
+
compilerDerived: false,
|
|
4135
|
+
build: policyBuild,
|
|
4136
|
+
status: mediaListPolicy.settings ? "available" : "unsupported"
|
|
4137
|
+
},
|
|
4138
|
+
"region.mediaList.plugin-avatar": {
|
|
4139
|
+
source: "curated-component-policy",
|
|
4140
|
+
compilerDerived: false,
|
|
4141
|
+
build: policyBuild,
|
|
4142
|
+
status: mediaListPolicy["plugin-avatar"] ? "available" : "unsupported"
|
|
4143
|
+
},
|
|
4144
|
+
"region.mediaList.plugin-badge": {
|
|
4145
|
+
source: "curated-component-policy",
|
|
4146
|
+
compilerDerived: false,
|
|
4147
|
+
build: policyBuild,
|
|
4148
|
+
status: mediaListPolicy["plugin-badge"] ? "available" : "unsupported"
|
|
4149
|
+
},
|
|
4150
|
+
"region.mediaList.action": {
|
|
4151
|
+
source: "curated-component-policy",
|
|
4152
|
+
compilerDerived: false,
|
|
4153
|
+
build: policyBuild,
|
|
4154
|
+
status: mediaListPolicy.action ? "available" : "unsupported"
|
|
4155
|
+
},
|
|
4156
|
+
"region.mediaList.plugin-grouping": {
|
|
4157
|
+
source: "curated-component-policy",
|
|
4158
|
+
compilerDerived: false,
|
|
4159
|
+
build: policyBuild,
|
|
4160
|
+
status: mediaListPolicy["plugin-grouping"] ? "available" : "unsupported"
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
: {},
|
|
3978
4164
|
components
|
|
3979
4165
|
};
|
|
3980
4166
|
}
|
|
3981
4167
|
|
|
4168
|
+
function apexlangRegionBlocks(text) {
|
|
4169
|
+
const regionPattern = /^([ \t]*)region\b[^\n]*\(\s*$([\s\S]*?)^\1\)\s*$/gm;
|
|
4170
|
+
return [...text.matchAll(regionPattern)].map((match) => match[0]);
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4173
|
+
export function appTextUsesMediaListReport(text) {
|
|
4174
|
+
return appTextMediaListReportSourceLocations(text).length > 0
|
|
4175
|
+
|| apexlangRegionBlocks(text).some((regionBlock) =>
|
|
4176
|
+
/\btype\s*:\s*themeTemplateComponent\/mediaList\b/.test(regionBlock)
|
|
4177
|
+
&& /\bcomponentAppearance\s*\{[\s\S]*?\bdisplay\s*:\s*report\b/.test(regionBlock));
|
|
4178
|
+
}
|
|
4179
|
+
|
|
4180
|
+
export function appTextMediaListReportSourceLocations(text) {
|
|
4181
|
+
return apexlangRegionBlocks(text)
|
|
4182
|
+
.filter((regionBlock) =>
|
|
4183
|
+
/\btype\s*:\s*themeTemplateComponent\/mediaList\b/.test(regionBlock)
|
|
4184
|
+
&& /\bcomponentAppearance\s*\{[\s\S]*?\bdisplay\s*:\s*report\b/.test(regionBlock))
|
|
4185
|
+
.map((regionBlock) => {
|
|
4186
|
+
const match = /\bsource\s*\{[\s\S]*?\blocation\s*:\s*([A-Za-z][A-Za-z0-9_/-]*)/.exec(regionBlock);
|
|
4187
|
+
return match?.[1] || "";
|
|
4188
|
+
});
|
|
4189
|
+
}
|
|
4190
|
+
|
|
4191
|
+
async function appMediaListReportSourceLocations(appPath) {
|
|
4192
|
+
const locations = [];
|
|
4193
|
+
const files = await collectFiles(appPath, (filePath) =>
|
|
4194
|
+
filePath.endsWith(".apx")
|
|
4195
|
+
&& !filePath.split(path.sep).includes("apex-exports"));
|
|
4196
|
+
for (const filePath of files) {
|
|
4197
|
+
const text = await fs.readFile(filePath, "utf8");
|
|
4198
|
+
locations.push(...appTextMediaListReportSourceLocations(text));
|
|
4199
|
+
}
|
|
4200
|
+
return locations;
|
|
4201
|
+
}
|
|
4202
|
+
|
|
4203
|
+
export async function resolveMediaListGrammarContract({
|
|
4204
|
+
appPath = "",
|
|
4205
|
+
compilerOracleHome = "",
|
|
4206
|
+
buildGrammarContractFn = null
|
|
4207
|
+
} = {}) {
|
|
4208
|
+
if (!appPath) return { status: "not_applicable", contract: null };
|
|
4209
|
+
const sourceLocations = await appMediaListReportSourceLocations(appPath);
|
|
4210
|
+
if (sourceLocations.length === 0) return { status: "not_applicable", contract: null };
|
|
4211
|
+
if (sourceLocations.some((location) => !location)) {
|
|
4212
|
+
return {
|
|
4213
|
+
status: "unresolved",
|
|
4214
|
+
contract: null,
|
|
4215
|
+
reason: "Every Media List report region must declare source.location."
|
|
4216
|
+
};
|
|
4217
|
+
}
|
|
4218
|
+
try {
|
|
4219
|
+
const buildGrammarContract = buildGrammarContractFn
|
|
4220
|
+
|| (await import(pathToFileURL(grammarContractToolPath()).href)).buildGrammarContract;
|
|
4221
|
+
const contracts = [];
|
|
4222
|
+
for (const sourceLocation of [...new Set(sourceLocations)].sort()) {
|
|
4223
|
+
const { contract } = await buildGrammarContract({
|
|
4224
|
+
components: ["region"],
|
|
4225
|
+
children: ["region.column"],
|
|
4226
|
+
groups: ["source", "layout", "appearance"],
|
|
4227
|
+
conditions: [
|
|
4228
|
+
"region.type=themeTemplateComponent/mediaList",
|
|
4229
|
+
`region.source.location=${sourceLocation}`
|
|
4230
|
+
],
|
|
4231
|
+
useCache: false,
|
|
4232
|
+
compilerOracleHome
|
|
4233
|
+
});
|
|
4234
|
+
const column = contract?.compilerContract?.resolvedChildren?.find(({ parent, child }) =>
|
|
4235
|
+
parent === "region" && child === "column");
|
|
4236
|
+
if (contract?.compilerContract?.status !== "resolved" || !column) {
|
|
4237
|
+
return {
|
|
4238
|
+
status: "unresolved",
|
|
4239
|
+
contract: null,
|
|
4240
|
+
reason: `Media List region.column did not resolve uniquely for source.location=${sourceLocation}.`
|
|
4241
|
+
};
|
|
4242
|
+
}
|
|
4243
|
+
contracts.push({ sourceLocation, contract, column });
|
|
4244
|
+
}
|
|
4245
|
+
const baselineColumn = JSON.stringify(contracts[0].column);
|
|
4246
|
+
if (contracts.some(({ column }) => JSON.stringify(column) !== baselineColumn)) {
|
|
4247
|
+
return {
|
|
4248
|
+
status: "unresolved",
|
|
4249
|
+
contract: null,
|
|
4250
|
+
reason: "Media List report source locations resolve incompatible region.column contracts."
|
|
4251
|
+
};
|
|
4252
|
+
}
|
|
4253
|
+
const contract = structuredClone(contracts[0].contract);
|
|
4254
|
+
const conformance = contract.compilerContract?.grammarConformance || [];
|
|
4255
|
+
if (conformance.some((entry) => entry.blocking || entry.status === "mismatch")) {
|
|
4256
|
+
const mismatch = conformance.flatMap((entry) => entry.mismatches || [])
|
|
4257
|
+
.map((entry) => entry.path)
|
|
4258
|
+
.sort()
|
|
4259
|
+
.join(", ");
|
|
4260
|
+
return {
|
|
4261
|
+
status: "unresolved",
|
|
4262
|
+
contract: null,
|
|
4263
|
+
reason: `Media List grammar/compiler conformance mismatch${mismatch ? `: ${mismatch}` : "."}`
|
|
4264
|
+
};
|
|
4265
|
+
}
|
|
4266
|
+
contract.compilerContract.mediaListSourceLocations = contracts.map(({ sourceLocation }) => sourceLocation);
|
|
4267
|
+
contract.compilerContract.assumptions = [
|
|
4268
|
+
...(contract.compilerContract.assumptions || []).filter((entry) =>
|
|
4269
|
+
!String(entry).startsWith("region.source.location=")),
|
|
4270
|
+
...contracts.map(({ sourceLocation }) => `region.source.location=${sourceLocation}`)
|
|
4271
|
+
];
|
|
4272
|
+
return { status: "resolved", contract };
|
|
4273
|
+
} catch (error) {
|
|
4274
|
+
return { status: "unavailable", contract: null, reason: error instanceof Error ? error.message : String(error) };
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
|
|
4278
|
+
async function runTargetBuildLocalValidation({ appPath, componentContractPath }) {
|
|
4279
|
+
return runCommand("python3", [
|
|
4280
|
+
apexlangValidatorPath(),
|
|
4281
|
+
"--component-attributes",
|
|
4282
|
+
componentContractPath,
|
|
4283
|
+
appPath
|
|
4284
|
+
], { allowFailure: true, passthrough: false });
|
|
4285
|
+
}
|
|
4286
|
+
|
|
3982
4287
|
function validationArtifactPaths(options = {}) {
|
|
3983
4288
|
const artifactDir = path.resolve(
|
|
3984
4289
|
options.artifactDir ||
|
|
@@ -3997,8 +4302,7 @@ function validationArtifactPaths(options = {}) {
|
|
|
3997
4302
|
}
|
|
3998
4303
|
|
|
3999
4304
|
async function writeValidationArtifacts({ report, problemsPayload, componentContract, paths }) {
|
|
4000
|
-
const
|
|
4001
|
-
const componentContractPath = path.join(paths.componentContractsDir, `${contractBuild}.json`);
|
|
4305
|
+
const componentContractPath = componentContractArtifactPath(componentContract, paths);
|
|
4002
4306
|
report.artifacts.component_contract_path = componentContractPath;
|
|
4003
4307
|
try {
|
|
4004
4308
|
await fs.access(paths.transcriptPath);
|
|
@@ -4011,6 +4315,11 @@ async function writeValidationArtifacts({ report, problemsPayload, componentCont
|
|
|
4011
4315
|
await writeJson(paths.reportPath, report);
|
|
4012
4316
|
}
|
|
4013
4317
|
|
|
4318
|
+
function componentContractArtifactPath(componentContract, paths) {
|
|
4319
|
+
const contractBuild = sanitizeSegment(componentContract.build || "unknown") || "unknown";
|
|
4320
|
+
return path.join(paths.componentContractsDir, `${contractBuild}.json`);
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4014
4323
|
/**
|
|
4015
4324
|
* Run the live validate-only gate and write validation reports for editor and agent feedback.
|
|
4016
4325
|
*/
|
|
@@ -4020,6 +4329,8 @@ export async function runRuntimeValidate(options = {}) {
|
|
|
4020
4329
|
runCommand,
|
|
4021
4330
|
loadVscodeProblemsEvidence,
|
|
4022
4331
|
readJsonIfExists,
|
|
4332
|
+
resolveMediaListGrammarContract,
|
|
4333
|
+
runTargetBuildLocalValidation,
|
|
4023
4334
|
writeValidationArtifacts,
|
|
4024
4335
|
...options._deps
|
|
4025
4336
|
};
|
|
@@ -4048,11 +4359,13 @@ export async function runRuntimeValidate(options = {}) {
|
|
|
4048
4359
|
validation_sources: {
|
|
4049
4360
|
live_validator: { status: "blocked", source: "runtime validate-only roundtrip" },
|
|
4050
4361
|
compiler_truth: { status: "not_run", report_path: paths.compilerTruthReportPath },
|
|
4362
|
+
target_build_contract: { status: "not_run", source: "compiler-runtime-metadata" },
|
|
4051
4363
|
vscode_problems: { status: "not_provided", source: "not_provided", unresolved_count: null }
|
|
4052
4364
|
},
|
|
4053
4365
|
diagnostic_sources: {
|
|
4054
4366
|
local_lint: { status: "not_run", source: "runtime validate-only roundtrip" },
|
|
4055
4367
|
compiler_truth: { status: "not_run", report_path: paths.compilerTruthReportPath },
|
|
4368
|
+
target_build_contract: { status: "not_run", source: "compiler-runtime-metadata" },
|
|
4056
4369
|
vscode_problems: { status: "not_provided", source: "not_provided", unresolved_count: null }
|
|
4057
4370
|
},
|
|
4058
4371
|
problem_count: 0,
|
|
@@ -4134,12 +4447,63 @@ export async function runRuntimeValidate(options = {}) {
|
|
|
4134
4447
|
policy: "advisory_when_live_validation_passes"
|
|
4135
4448
|
};
|
|
4136
4449
|
|
|
4450
|
+
const mediaListResolution = await deps.resolveMediaListGrammarContract({
|
|
4451
|
+
appPath,
|
|
4452
|
+
compilerOracleHome: options.compilerOracleHome || ""
|
|
4453
|
+
});
|
|
4454
|
+
const mediaListGrammarContract = mediaListResolution.contract || null;
|
|
4455
|
+
const grammarBuild = mediaListGrammarContract?.compilerContract?.buildID || "";
|
|
4456
|
+
const compilerBuild = compilerReport?.compilerTruth?.buildID || "";
|
|
4457
|
+
if (mediaListResolution.status !== "not_applicable" && mediaListResolution.status !== "resolved") {
|
|
4458
|
+
report.blocking_reasons.push(
|
|
4459
|
+
`Target-build Media List contract is ${mediaListResolution.status}: ${mediaListResolution.reason || "unknown reason"}`
|
|
4460
|
+
);
|
|
4461
|
+
}
|
|
4462
|
+
if (grammarBuild && compilerBuild && grammarBuild !== compilerBuild) {
|
|
4463
|
+
report.blocking_reasons.push(
|
|
4464
|
+
`Target-build Media List contract build ${grammarBuild} does not match compiler-truth build ${compilerBuild}.`
|
|
4465
|
+
);
|
|
4466
|
+
}
|
|
4467
|
+
if (grammarBuild && report.target_build && grammarBuild !== report.target_build) {
|
|
4468
|
+
report.blocking_reasons.push(
|
|
4469
|
+
`Target-build Media List contract build ${grammarBuild} does not match live runtime build ${report.target_build}.`
|
|
4470
|
+
);
|
|
4471
|
+
}
|
|
4472
|
+
|
|
4137
4473
|
const componentAttributes = (await deps.readJsonIfExists(componentAttributesPath())) || {};
|
|
4138
4474
|
const componentContract = buildComponentContracts(componentAttributes, {
|
|
4139
|
-
build:
|
|
4475
|
+
build: compilerReport?.compilerTruth?.buildID || componentAttributes?.compilerProvenance?.buildID || "",
|
|
4140
4476
|
compilerReport,
|
|
4141
|
-
source:
|
|
4477
|
+
source: mediaListGrammarContract ? "compiler-runtime-metadata+curated-policy" : "curated-component-policy",
|
|
4478
|
+
mediaListGrammarContract
|
|
4142
4479
|
});
|
|
4480
|
+
const componentContractPath = componentContractArtifactPath(componentContract, paths);
|
|
4481
|
+
report.artifacts.component_contract_path = componentContractPath;
|
|
4482
|
+
await writeJson(componentContractPath, componentContract);
|
|
4483
|
+
|
|
4484
|
+
if (mediaListGrammarContract && !report.blocking_reasons.some((reason) => /contract build .* does not match/.test(reason))) {
|
|
4485
|
+
const targetBuildLint = await deps.runTargetBuildLocalValidation({ appPath, componentContractPath });
|
|
4486
|
+
const targetBuildLintStatus = targetBuildLint.code === 0 ? "pass" : "fail";
|
|
4487
|
+
report.validation_sources.target_build_contract = {
|
|
4488
|
+
status: targetBuildLintStatus,
|
|
4489
|
+
source: componentContractPath,
|
|
4490
|
+
compiler_build: componentContract.build,
|
|
4491
|
+
output: cleanOutput(targetBuildLint).slice(0, 4000)
|
|
4492
|
+
};
|
|
4493
|
+
report.diagnostic_sources.target_build_contract = {
|
|
4494
|
+
...report.validation_sources.target_build_contract,
|
|
4495
|
+
policy: "blocking_for_compiler_resolved_components"
|
|
4496
|
+
};
|
|
4497
|
+
if (targetBuildLintStatus !== "pass") {
|
|
4498
|
+
report.blocking_reasons.push("Target-build component contract validation did not pass.");
|
|
4499
|
+
}
|
|
4500
|
+
} else if (mediaListResolution.status === "not_applicable") {
|
|
4501
|
+
report.validation_sources.target_build_contract = {
|
|
4502
|
+
status: "not_applicable",
|
|
4503
|
+
source: "No Media List report component found in the target app."
|
|
4504
|
+
};
|
|
4505
|
+
report.diagnostic_sources.target_build_contract = report.validation_sources.target_build_contract;
|
|
4506
|
+
}
|
|
4143
4507
|
|
|
4144
4508
|
const vscodeEvidence = await deps.loadVscodeProblemsEvidence({
|
|
4145
4509
|
vscodeProblemsPath: options.vscodeProblemsPath || "",
|
|
@@ -4185,7 +4549,7 @@ export async function runRuntimeValidate(options = {}) {
|
|
|
4185
4549
|
report.validation_status =
|
|
4186
4550
|
report.validation_sources.live_validator.status === "pass" &&
|
|
4187
4551
|
problemsPayload.unresolved_count === 0 &&
|
|
4188
|
-
|
|
4552
|
+
report.blocking_reasons.length === 0
|
|
4189
4553
|
? "pass"
|
|
4190
4554
|
: "fail";
|
|
4191
4555
|
report.import_eligibility = report.validation_status === "pass" ? "validate-only-passed" : "blocked";
|
|
@@ -4338,18 +4702,32 @@ function runPathSession({ dbConnectionName, input, labelPrefix = "sql" }) {
|
|
|
4338
4702
|
};
|
|
4339
4703
|
}
|
|
4340
4704
|
|
|
4341
|
-
async function runBuildRootSession({
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4705
|
+
export async function runBuildRootSession({
|
|
4706
|
+
buildRoot,
|
|
4707
|
+
input,
|
|
4708
|
+
label = "apex_sql_build_root",
|
|
4709
|
+
_deps = {}
|
|
4710
|
+
}) {
|
|
4711
|
+
const runInteractiveCommandImpl = _deps.runInteractiveCommand ?? runInteractiveCommand;
|
|
4712
|
+
const tempDirectory = await fs.mkdtemp(path.join(os.tmpdir(), "apexctl-roundtrip-"));
|
|
4713
|
+
const tempScriptPath = path.join(tempDirectory, "session.sql");
|
|
4714
|
+
try {
|
|
4715
|
+
await fs.writeFile(tempScriptPath, `${input}\n`, {
|
|
4716
|
+
encoding: "utf8",
|
|
4717
|
+
mode: 0o600,
|
|
4718
|
+
flag: "wx"
|
|
4719
|
+
});
|
|
4720
|
+
const result = runInteractiveCommandImpl("apex", ["sql", "-s", tempScriptPath], { cwd: buildRoot });
|
|
4721
|
+
return {
|
|
4722
|
+
success: !hasWorkspaceAmbiguity(result) && !hasRuntimeFailure(result),
|
|
4723
|
+
workspaceAmbiguity: hasWorkspaceAmbiguity(result),
|
|
4724
|
+
entrypoint: label,
|
|
4725
|
+
result,
|
|
4726
|
+
transcript: `## ${label}\n${cleanOutput(result)}\n`
|
|
4727
|
+
};
|
|
4728
|
+
} finally {
|
|
4729
|
+
await fs.rm(tempDirectory, { recursive: true, force: true });
|
|
4730
|
+
}
|
|
4353
4731
|
}
|
|
4354
4732
|
|
|
4355
4733
|
function runPathRoundtrip({ appPath, dbConnectionName, workspaceId, includeImport = true }) {
|
|
@@ -4583,6 +4961,7 @@ export async function runRuntimeRoundtrip(options = {}) {
|
|
|
4583
4961
|
resolveRuntimeTargetApplication,
|
|
4584
4962
|
executeSelectedRoundtrip,
|
|
4585
4963
|
resolveWorkspaceIdForRuntime,
|
|
4964
|
+
normalizeApxLineEndings,
|
|
4586
4965
|
verifyRuntimeUi,
|
|
4587
4966
|
writeRoundtripArtifacts,
|
|
4588
4967
|
...options._deps
|
|
@@ -4749,6 +5128,27 @@ export async function runRuntimeRoundtrip(options = {}) {
|
|
|
4749
5128
|
return buildRoundtripResult(0, summary);
|
|
4750
5129
|
}
|
|
4751
5130
|
|
|
5131
|
+
try {
|
|
5132
|
+
const lineEndings = await deps.normalizeApxLineEndings(options.appPath);
|
|
5133
|
+
summary.line_endings_status = lineEndings.status;
|
|
5134
|
+
summary.line_endings_checked_files = lineEndings.checkedFiles;
|
|
5135
|
+
summary.line_endings_normalized_files = lineEndings.normalizedFiles;
|
|
5136
|
+
if (lineEndings.normalizedFiles.length > 0) {
|
|
5137
|
+
summary.notes.push(
|
|
5138
|
+
`Normalized ${lineEndings.normalizedFiles.length} APEXlang source file(s) from CRLF or CR to LF before live validation.`
|
|
5139
|
+
);
|
|
5140
|
+
}
|
|
5141
|
+
} catch (error) {
|
|
5142
|
+
summary.line_endings_status = "fail";
|
|
5143
|
+
summary.runtime_gate_status = "fail";
|
|
5144
|
+
summary.failure_class = "line_endings_normalization_failed";
|
|
5145
|
+
summary.blocking_reason = "APEXLANG_LF_LINE_ENDINGS_REQUIRED_001";
|
|
5146
|
+
summary.recommended_next_action = "Normalize every .apx file to LF before rerunning validation or import.";
|
|
5147
|
+
summary.notes.push(error instanceof Error ? error.message : String(error));
|
|
5148
|
+
await deps.writeRoundtripArtifacts(summary, transcriptParts.join("\n"));
|
|
5149
|
+
return buildRoundtripResult(1, summary);
|
|
5150
|
+
}
|
|
5151
|
+
|
|
4752
5152
|
const localValidationStage = await runTimedStage(
|
|
4753
5153
|
summary,
|
|
4754
5154
|
"local_validate",
|