diff --git a/import-bulk.html b/import-bulk.html
index 11b0fc29..afca8c97 100644
--- a/import-bulk.html
+++ b/import-bulk.html
@@ -102,6 +102,11 @@
Bulk Import
+
+
+ Save as JSON
+
+
Save HTML for Document Authoring
diff --git a/import.html b/import.html
index d081b6ee..0168536b 100644
--- a/import.html
+++ b/import.html
@@ -116,6 +116,11 @@ Workbench
+
+
+ Save as JSON
+
+
Save HTML for Document Authoring
diff --git a/importer-guidelines.md b/importer-guidelines.md
index a33748d4..9dbcf7c3 100644
--- a/importer-guidelines.md
+++ b/importer-guidelines.md
@@ -671,7 +671,24 @@ Every new project has its own collection of new use cases which might be totally
- Linked images are not supported by Online Word thus they will be converted to image + link in Word.
- Reuse the DOM elements from the orignal page, no need to re-create complete DOM structures, especially if the Markdown is what you need. Example: Text in a `div` will become a paragraph, no need to create a `p` tag and replace the `div`. More generally, the DOM can be dirty, as long as the output Markdown looks as expected, it does not matter.
- If you import multiple page "types" for the project, you cannot either handle them in the same `import.js` file or have one `import-.js` file per type (or any filename convention you lie). Use the UI options to point to a different import filename.
-
+
+## JSON import
+
+To import JSON, you need an `import.js` file with the following `transform` method:
+
+```
+export default {
+ transform: ({
+ document, url, html, params,
+ }) => {
+ return {
+ path: `/.json`,
+ json: JSON.stringify(, null, 2)
+ }
+ },
+};
+```
+
## Debugging
If you experience some deep nested Javascript exception, you can run the importer ui in developer mode, JS files will not be minified and obfuscated. Just run in the `/tools/importer/helix-importer-ui` folder:
diff --git a/index.html b/index.html
index 6be6c774..3677e3a7 100644
--- a/index.html
+++ b/index.html
@@ -102,6 +102,7 @@ Authoring Experience Selection
Document Authoring
AEM Authoring
+ JSON
Ok
@@ -123,6 +124,7 @@ Authoring Experience Selection
Document Authoring
AEM Authoring
+ JSON
Reset
diff --git a/js/import/import.preview.js b/js/import/import.preview.js
index f20b81b6..4151ab78 100644
--- a/js/import/import.preview.js
+++ b/js/import/import.preview.js
@@ -19,6 +19,8 @@ const PreviewElements = Object.freeze({
TRANSFORMED_HTML_TEXTAREA: document.getElementById('import-transformed-html'),
MD_SOURCE_TEXTAREA: document.getElementById('import-markdown-source'),
MD_PREVIEW_PANEL: document.getElementById('import-markdown-preview'),
+ // use md preview panel for json
+ JSON_PREVIEW_PANEL: document.getElementById('import-markdown-preview'),
IMPORT_FILE_PICKER_CONTAINER: document.getElementById('import-file-picker-container'),
JCR_PANEL: document.getElementById('import-jcr'),
});
@@ -153,7 +155,9 @@ const setupPreview = (parentSelector) => {
return preview;
};
-const loadPreview = ({ md, html: outputHTML, jcr }) => {
+const loadPreview = ({
+ md, html: outputHTML, jcr, json,
+}) => {
if (outputHTML) {
preview.transformedEditor.setValue(html_beautify(outputHTML.replaceAll(/\s+/g, ' '), {
indent_size: '2',
@@ -181,7 +185,11 @@ const loadPreview = ({ md, html: outputHTML, jcr }) => {
});
} else {
preview.markdownEditor.setValue('No preview available.');
- preview.markdownPreview.innerHTML = 'No preview available.';
+ if (json) {
+ preview.markdownPreview.innerHTML = `${json} `;
+ } else {
+ preview.markdownPreview.innerHTML = 'No preview available.';
+ }
}
};
diff --git a/js/import/import.ui.js b/js/import/import.ui.js
index 7b1301e4..0c5b056d 100644
--- a/js/import/import.ui.js
+++ b/js/import/import.ui.js
@@ -82,14 +82,14 @@ const enableProcessButtons = () => {
const postSuccessfulStep = async (results, originalURL) => {
let error = false;
await asyncForEach(results, async ({
- docx, html, md, jcr, filename, path, report, from,
+ docx, html, md, jcr, json, filename, path, report, from,
}) => {
const data = {
url: originalURL,
path,
};
- if (isSaveLocal && dirHandle && (docx || html || md || jcr)) {
+ if (isSaveLocal && dirHandle && (docx || html || md || jcr || json)) {
const files = [];
// if we were told to ave the doc file, add it to the list
if (config.fields['import-local-docx'] && docx) {
@@ -123,6 +123,10 @@ const postSuccessfulStep = async (results, originalURL) => {
}
}
+ if (config.fields['import-local-json'] && json) {
+ files.push({ type: 'json', filename: path, data: json });
+ }
+
// if we were told to save the JCR package, add it to the list
if (config.fields['import-jcr-package'] && jcr) {
jcrPages.push({
@@ -385,7 +389,7 @@ const startImport = async () => {
disableProcessButtons();
toggleLoadingButton(IMPORT_BUTTON);
- isSaveLocal = config.fields['import-local-docx'] || config.fields['import-local-html'] || config.fields['import-local-md'] || config.fields['import-jcr-package'] || config.fields['import-local-da'];
+ isSaveLocal = config.fields['import-local-docx'] || config.fields['import-local-html'] || config.fields['import-local-md'] || config.fields['import-jcr-package'] || config.fields['import-local-da'] || config.fields['import-local-json'];
if (isSaveLocal && !dirHandle) {
try {
dirHandle = await getDirectoryHandle();
diff --git a/js/shared/json-project.js b/js/shared/json-project.js
new file mode 100644
index 00000000..6dae8631
--- /dev/null
+++ b/js/shared/json-project.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2025 Adobe. All rights reserved.
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License. You may obtain a copy
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+
+/**
+ * @typedef {Object} JsonProjectConfig
+ * @property {string} origin - The base URL to fetch data from.
+ */
+
+/**
+ * Represents a JSON project.
+ */
+const JsonProject = () => {
+ /**
+ * Retrieves the type of the project.
+ * @returns "json" The type of the project ('json').
+ */
+ const getType = () => 'json';
+
+ return {
+ getType,
+ };
+};
+
+export default JsonProject;
diff --git a/js/shared/pollimporter.js b/js/shared/pollimporter.js
index c30d8e22..c2563a26 100644
--- a/js/shared/pollimporter.js
+++ b/js/shared/pollimporter.js
@@ -256,6 +256,14 @@ export default class PollImporter {
this.running = false;
return;
}
+ } else if (projectType === 'json') {
+ const out = await WebImporter.html2json(
+ url,
+ documentClone,
+ this.projectTransform,
+ params,
+ );
+ results = Array.isArray(out) ? out : [out];
} else {
const out = await WebImporter.html2md(
url,
diff --git a/js/shared/project.js b/js/shared/project.js
index 17ac113e..2cc09617 100644
--- a/js/shared/project.js
+++ b/js/shared/project.js
@@ -13,9 +13,10 @@
import DocProject from './doc-project.js';
import XWalkProject from './xwalk-project.js';
+import JsonProject from './json-project.js';
import { LOCAL_STORAGE_KEYS } from './localstorage.js';
/**
- * @typedef {"doc" | "xwalk"} ProjectType
+ * @typedef {"doc" | "xwalk" | "json" } ProjectType
* @description Represents the possible types of a project.
*/
@@ -34,6 +35,7 @@ const Project = async (config) => {
const projectTypeMap = {
doc: DocProject,
xwalk: XWalkProject,
+ json: JsonProject,
};
/**
@@ -202,7 +204,10 @@ const Project = async (config) => {
const updateUI = () => {
const SAVE_AS_DOCX = document.getElementById('import-local-docx');
const DA_FIELD = document.getElementById('import-local-da');
+ const LOCAL_HTML = document.getElementById('import-local-html');
+ const LOCAL_MD = document.getElementById('import-local-md');
const XWALK_FIELDS = document.getElementById('xwalk');
+ const JSON_FIELDS = document.getElementById('json');
const JCR_ASSET_FOLDER = document.getElementById('jcr-asset-folder');
const JCR_SITE_FOLDER = document.getElementById('jcr-site-folder');
@@ -234,6 +239,7 @@ const Project = async (config) => {
if (projectType === 'doc') {
if (XWALK_FIELDS) XWALK_FIELDS.remove();
+ if (JSON_FIELDS) JSON_FIELDS.remove();
config.fields['import-jcr-package'] = false;
@@ -242,6 +248,19 @@ const Project = async (config) => {
if (jcrTab) {
jcrTab.remove();
}
+ } else if (projectType === 'json') {
+ if (XWALK_FIELDS) XWALK_FIELDS.remove();
+ if (SAVE_AS_DOCX) SAVE_AS_DOCX.remove();
+ if (DA_FIELD) DA_FIELD.remove();
+ if (LOCAL_HTML) LOCAL_HTML.remove();
+ if (LOCAL_MD) LOCAL_MD.remove();
+
+ config.fields['import-local-docx'] = false;
+ config.fields['import-local-json'] = true;
+ config.fields['import-jcr-package'] = false;
+ config.fields['import-local-da'] = false;
+ config.fields['import-local-html'] = false;
+ config.fields['import-local-md'] = false;
} else {
if (SAVE_AS_DOCX) SAVE_AS_DOCX.remove();
if (DA_FIELD) DA_FIELD.remove();
diff --git a/modules/importer.js b/modules/importer.js
index f1b2e3dd..71107427 100644
--- a/modules/importer.js
+++ b/modules/importer.js
@@ -25,6 +25,7 @@ import {
html2md,
md2jcr,
rules,
+ html2json,
} from '@adobe/helix-importer';
import docxStylesXML from '../resources/styles.xml';
@@ -83,6 +84,9 @@ const options = {
async function html2mdWrapper(url, document, transformCfg, params) {
return html2md(url, document, transformCfg, options, params);
}
+async function html2jsonWrapper(url, document, transformCfg, params) {
+ return html2json(url, document, transformCfg, options, params);
+}
async function html2docxWrapper(url, document, transformCfg, params) {
return html2docx(url, document, transformCfg, options, params);
@@ -106,6 +110,7 @@ export {
FileUtils,
JCRUtils,
html2mdWrapper as html2md,
+ html2jsonWrapper as html2json,
html2docxWrapper as html2docx,
md2jcrWrapper as md2jcr,
rules,
diff --git a/package.json b/package.json
index 84e3bd78..b47bd978 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,7 @@
},
"dependencies": {
"@adobe/helix-html-pipeline": "6.26.6",
- "@adobe/helix-importer": "3.4.101",
+ "@adobe/helix-importer": "https://github.com/adobe/helix-importer/tree/json",
"@adobe/helix-importer-jcr-packaging": "2.0.10",
"@spectrum-web-components/bundle": "1.7.0",
"@spectrum-web-components/icons-workflow": "1.7.0",