@jxsuite/import 0.42.4 → 0.43.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxsuite/import",
3
- "version": "0.42.4",
3
+ "version": "0.43.0",
4
4
  "description": "Clone a live website into a Jx project",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,9 +35,9 @@
35
35
  "import": "bun run src/cli.ts"
36
36
  },
37
37
  "dependencies": {
38
- "@jxsuite/markup": "^1.0.4",
39
- "@jxsuite/protocol": "^6.2.2",
40
- "@jxsuite/schema": "^5.2.0",
38
+ "@jxsuite/markup": "^1.0.6",
39
+ "@jxsuite/protocol": "^6.2.4",
40
+ "@jxsuite/schema": "^5.4.0",
41
41
  "pixelmatch": "^8.0.0",
42
42
  "pngjs": "^7.0.0",
43
43
  "puppeteer-core": "^25.12.0"
@@ -49,6 +49,6 @@
49
49
  "happy-dom": "^21.0.3"
50
50
  },
51
51
  "optionalDependencies": {
52
- "@jxsuite/compiler": "^8.2.0"
52
+ "@jxsuite/compiler": "^8.4.0"
53
53
  }
54
54
  }
package/src/cli.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  MIN_BREAKPOINT_WIDTH,
11
11
  } from "./breakpoint-plan.ts";
12
12
  import type { BreakpointPolicy, BreakpointRounding } from "./breakpoint-plan.ts";
13
+ import { NEW_PROJECT_FILE_NAME } from "@jxsuite/schema/project-file";
13
14
 
14
15
  function usage(): never {
15
16
  console.log(`Usage: jx-import <url> [options]
@@ -246,7 +247,7 @@ async function main(siteUrl: string) {
246
247
 
247
248
  console.log(`\nDone! Open in Studio:`);
248
249
  console.log(
249
- ` http://localhost:3000/packages/studio/index.html?project=${outDir}/project.json`,
250
+ ` http://localhost:3000/packages/studio/index.html?project=${outDir}/${NEW_PROJECT_FILE_NAME}`,
250
251
  );
251
252
  } catch (error) {
252
253
  console.error(`Error: ${error instanceof Error ? error.message : error}`);
package/src/emit.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { isString } from "@jxsuite/schema/guards";
2
- import type { JxElement, JxHeadEntry } from "@jxsuite/schema/types";
2
+ import type { JxElement, JxHeadEntry, ProjectConfig } from "@jxsuite/schema/types";
3
3
  import { componentize } from "./componentize.ts";
4
4
  import { stripClasses } from "./strip-classes.ts";
5
5
  import type { ComponentizeOptions, ComponentizeResult } from "./componentize.ts";
6
6
  import type { ImportIo } from "./io.ts";
7
+ import { NEW_PROJECT_FILE_NAME, serializeProjectFile } from "@jxsuite/schema/project-file";
7
8
 
8
9
  /**
9
10
  * The `$media` key the base width lives under — a number of CSS pixels, not a query.
@@ -250,9 +251,11 @@ export async function emitMultiPageProject({
250
251
  });
251
252
  }
252
253
 
253
- const projectText = `${JSON.stringify(projectJson, null, 2)}\n`;
254
- await io.write("project.json", projectText);
255
- files.push("project.json");
254
+ /* SAFETY: every ProjectConfig member is optional, and this project's shape is what the import
255
+ emits; `jx validate` holds it to the per-project schema. */
256
+ const projectText = serializeProjectFile(projectJson as ProjectConfig, null);
257
+ await io.write(NEW_PROJECT_FILE_NAME, projectText);
258
+ files.push(NEW_PROJECT_FILE_NAME);
256
259
 
257
260
  /*
258
261
  * Classes go here, at the last possible moment, and that placement is the whole design.
package/src/run.ts CHANGED
@@ -18,6 +18,7 @@ import type { BreakpointPolicy } from "./breakpoint-plan.ts";
18
18
  import type { ImportPhase, ImportProgressEvent } from "./pipeline.ts";
19
19
  import type { VerifyOptions } from "./verify.ts";
20
20
  import type { Browser } from "puppeteer-core";
21
+ import { NEW_PROJECT_FILE_NAME, serializeProjectFile } from "@jxsuite/schema/project-file";
21
22
 
22
23
  export type { ImportPhase, ImportProgressEvent } from "./pipeline.ts";
23
24
 
@@ -117,7 +118,6 @@ export interface ImportSiteResult {
117
118
  const DEFAULT_AI_MODEL = "gpt-4o-mini";
118
119
 
119
120
  /** The one file the seed writes, and the only thing the empty-directory guard tolerates. */
120
- const PROJECT_FILE = "project.json";
121
121
 
122
122
  /** A placeholder project name from the URL, replaced by the page title at emit. */
123
123
  function seedName(url: string): string {
@@ -150,7 +150,7 @@ export async function importSite(
150
150
  given a `project.json` before the browser launches, so a host can open the project and watch the
151
151
  rest of the run arrive in its file tree — and a guard that could not tell that seed from a
152
152
  stranger's files would refuse every import at its second statement. */
153
- if (existsSync(outDir) && readdirSync(outDir).some((entry) => entry !== PROJECT_FILE)) {
153
+ if (existsSync(outDir) && readdirSync(outDir).some((entry) => entry !== NEW_PROJECT_FILE_NAME)) {
154
154
  throw new Error(`Directory "${outDir}" is not empty`);
155
155
  }
156
156
 
@@ -234,7 +234,7 @@ export async function importSite(
234
234
  async function seedProject(): Promise<void> {
235
235
  await mkdir(outDir, { recursive: true });
236
236
  const seed = { name: seedName(url), imports: {}, images: { optimize: false } };
237
- await writeFile(join(outDir, PROJECT_FILE), `${JSON.stringify(seed, null, 2)}\n`);
237
+ await writeFile(join(outDir, NEW_PROJECT_FILE_NAME), serializeProjectFile(seed, null));
238
238
  onProgress?.({
239
239
  message: `Created ${outDir}`,
240
240
  phase: "seed",