@nshiab/setup-data-project 1.0.28 → 1.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/esm/helpers/ensureAgents.d.ts +1 -1
  2. package/esm/helpers/ensureAgents.d.ts.map +1 -1
  3. package/esm/helpers/ensureAgents.js +34 -13
  4. package/esm/helpers/ensureManagedSection.d.ts +9 -0
  5. package/esm/helpers/ensureManagedSection.d.ts.map +1 -0
  6. package/esm/helpers/ensureManagedSection.js +30 -0
  7. package/esm/helpers/ensureReadme.d.ts +1 -1
  8. package/esm/helpers/ensureReadme.d.ts.map +1 -1
  9. package/esm/helpers/ensureReadme.js +26 -12
  10. package/esm/helpers/gitignoreEntries.d.ts.map +1 -1
  11. package/esm/helpers/gitignoreEntries.js +1 -0
  12. package/esm/helpers/installPackagesAndFetchDocs.d.ts +3 -0
  13. package/esm/helpers/installPackagesAndFetchDocs.d.ts.map +1 -1
  14. package/esm/helpers/installPackagesAndFetchDocs.js +42 -34
  15. package/esm/helpers/packageRegistry.d.ts +1 -0
  16. package/esm/helpers/packageRegistry.d.ts.map +1 -1
  17. package/esm/helpers/packageRegistry.js +4 -0
  18. package/esm/helpers/projectManifest.d.ts +11 -0
  19. package/esm/helpers/projectManifest.d.ts.map +1 -0
  20. package/esm/helpers/projectManifest.js +73 -0
  21. package/esm/helpers/syncPackageDocs.d.ts +2 -0
  22. package/esm/helpers/syncPackageDocs.d.ts.map +1 -0
  23. package/esm/helpers/syncPackageDocs.js +27 -0
  24. package/esm/main.js +19 -14
  25. package/package.json +1 -1
  26. package/script/helpers/ensureAgents.d.ts +1 -1
  27. package/script/helpers/ensureAgents.d.ts.map +1 -1
  28. package/script/helpers/ensureAgents.js +33 -12
  29. package/script/helpers/ensureManagedSection.d.ts +9 -0
  30. package/script/helpers/ensureManagedSection.d.ts.map +1 -0
  31. package/script/helpers/ensureManagedSection.js +33 -0
  32. package/script/helpers/ensureReadme.d.ts +1 -1
  33. package/script/helpers/ensureReadme.d.ts.map +1 -1
  34. package/script/helpers/ensureReadme.js +26 -12
  35. package/script/helpers/gitignoreEntries.d.ts.map +1 -1
  36. package/script/helpers/gitignoreEntries.js +1 -0
  37. package/script/helpers/installPackagesAndFetchDocs.d.ts +3 -0
  38. package/script/helpers/installPackagesAndFetchDocs.d.ts.map +1 -1
  39. package/script/helpers/installPackagesAndFetchDocs.js +42 -33
  40. package/script/helpers/packageRegistry.d.ts +1 -0
  41. package/script/helpers/packageRegistry.d.ts.map +1 -1
  42. package/script/helpers/packageRegistry.js +5 -0
  43. package/script/helpers/projectManifest.d.ts +11 -0
  44. package/script/helpers/projectManifest.d.ts.map +1 -0
  45. package/script/helpers/projectManifest.js +77 -0
  46. package/script/helpers/syncPackageDocs.d.ts +2 -0
  47. package/script/helpers/syncPackageDocs.d.ts.map +1 -0
  48. package/script/helpers/syncPackageDocs.js +30 -0
  49. package/script/main.js +19 -14
  50. package/esm/helpers/getInstalledPackages.d.ts +0 -2
  51. package/esm/helpers/getInstalledPackages.d.ts.map +0 -1
  52. package/esm/helpers/getInstalledPackages.js +0 -29
  53. package/esm/helpers/updateProjectConfig.d.ts +0 -2
  54. package/esm/helpers/updateProjectConfig.d.ts.map +0 -1
  55. package/esm/helpers/updateProjectConfig.js +0 -42
  56. package/script/helpers/getInstalledPackages.d.ts +0 -2
  57. package/script/helpers/getInstalledPackages.d.ts.map +0 -1
  58. package/script/helpers/getInstalledPackages.js +0 -32
  59. package/script/helpers/updateProjectConfig.d.ts +0 -2
  60. package/script/helpers/updateProjectConfig.d.ts.map +0 -1
  61. package/script/helpers/updateProjectConfig.js +0 -45
@@ -1,2 +1,2 @@
1
- export declare function ensureAgents(docsMapping: Record<string, string>, runtime: string): Promise<void>;
1
+ export declare function ensureAgents(docsMapping: Record<string, string>, runtime: string, installedPackages?: string[]): void;
2
2
  //# sourceMappingURL=ensureAgents.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ensureAgents.d.ts","sourceRoot":"","sources":["../../src/helpers/ensureAgents.ts"],"names":[],"mappings":"AAIA,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,OAAO,EAAE,MAAM,iBA2FhB"}
1
+ {"version":3,"file":"ensureAgents.d.ts","sourceRoot":"","sources":["../../src/helpers/ensureAgents.ts"],"names":[],"mappings":"AAOA,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,OAAO,EAAE,MAAM,EACf,iBAAiB,GAAE,MAAM,EAA6B,QAuHvD"}
@@ -1,9 +1,11 @@
1
1
  import { log } from "@clack/prompts";
2
- import { handleFileConflict } from "./handleFileConflict.js";
3
- import { SUPPORTED_PACKAGES } from "./packageRegistry.js";
4
- export async function ensureAgents(docsMapping, runtime) {
2
+ import { ensureManagedSection } from "./ensureManagedSection.js";
3
+ import { getInstalledPackageConfigs, SUPPORTED_PACKAGES, } from "./packageRegistry.js";
4
+ export function ensureAgents(docsMapping, runtime, installedPackages = Object.keys(docsMapping)) {
5
5
  let journalismFunctions = "";
6
6
  let sdaClassesAndMethods = "";
7
+ let sdaDocsPath = "";
8
+ let sdaLibraryName = "";
7
9
  for (const [pkg, doc] of Object.entries(docsMapping)) {
8
10
  const pkgConfig = SUPPORTED_PACKAGES.find((p) => p.value === pkg);
9
11
  const pkgType = pkgConfig?.type || "other";
@@ -21,6 +23,9 @@ export async function ensureAgents(docsMapping, runtime) {
21
23
  .join("\n") + "\n";
22
24
  }
23
25
  else if (pkgType === "sda") {
26
+ const repoName = pkg.split("/")[1];
27
+ sdaDocsPath = `./docs/${repoName}.md`;
28
+ sdaLibraryName = pkgConfig?.label || repoName;
24
29
  sdaClassesAndMethods = doc
25
30
  .split("\n")
26
31
  .filter((line) => line.trim().startsWith("#"))
@@ -45,6 +50,23 @@ export async function ensureAgents(docsMapping, runtime) {
45
50
  const configFile = runtime === "deno" ? "deno.json" : "package.json";
46
51
  const runSda = runtime === "deno" ? "deno task sda" : "npm run sda";
47
52
  const runClean = runtime === "deno" ? "deno task clean" : "npm run clean";
53
+ const installedPackageConfigs = getInstalledPackageConfigs(installedPackages);
54
+ const importExamples = installedPackageConfigs.map((pkg) => {
55
+ const repoName = pkg.value.split("/")[1];
56
+ const identifier = repoName.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
57
+ return `import * as ${identifier} from "${pkg.value}";`;
58
+ });
59
+ let libraryGuidance = "";
60
+ if (installedPackageConfigs.length > 0) {
61
+ const libraryNames = installedPackageConfigs.map((pkg) => `"${pkg.label}"`)
62
+ .join(", ");
63
+ libraryGuidance = `
64
+ Always prioritize the installed ${libraryNames} libraries when relevant. They can be imported directly like this:
65
+ \`\`\`typescript
66
+ ${importExamples.join("\n")}
67
+ \`\`\`
68
+ `;
69
+ }
48
70
  let content = `Always verify if there is a ${configFile} file in the root of the project and familiarize yourself with the scripts available in it and the libraries already installed in the project.
49
71
 
50
72
  Always use "sda" task when available (e.g. \`${runSda}\`).
@@ -62,13 +84,7 @@ If you need to create other TypeScript files, create them in the "sda/helpers" f
62
84
  If you need to download data, always put the files in the "sda/data" folder, which is gitignored.
63
85
 
64
86
  If you need to output data to a file, always put the file in the "sda/output" folder.
65
-
66
- Always prioritize the use of the "journalism" and "simple-data-analysis" libraries when they are installed. These libraries can be used directly like this:
67
- \`\`\`typescript
68
- import { formatDate } from "@nshiab/journalism-format";
69
- import { SimpleDB } from "@nshiab/simple-data-analysis";
70
- \`\`\`
71
- `;
87
+ ${libraryGuidance}`;
72
88
  if (journalismFunctions !== "") {
73
89
  content += `
74
90
  Here are the functions available in the "journalism" libraries. If one of the function might be relevant, read the complete documentation in the "./docs/" folder to properly use it.
@@ -76,11 +92,16 @@ ${journalismFunctions}`;
76
92
  }
77
93
  if (sdaClassesAndMethods !== "") {
78
94
  content += `
79
- Here are the classes and their methods available in the "simple-data-analysis" library. If one of the classes or methods might be relevant, read the complete documentation at "./docs/simple-data-analysis.md" to properly use it. Remember that almost all methods are asynchronous, so you need to use \`await\` when calling them.
95
+ Here are the classes and their methods available in the "${sdaLibraryName}" library. If one of the classes or methods might be relevant, read the complete documentation at "${sdaDocsPath}" to properly use it. Remember that almost all methods are asynchronous, so you need to use \`await\` when calling them.
80
96
  ${sdaClassesAndMethods}`;
81
97
  }
82
- const status = await handleFileConflict("AGENTS.md", content);
83
- if (status === "updated") {
98
+ const status = ensureManagedSection({
99
+ path: "AGENTS.md",
100
+ name: "agents",
101
+ content,
102
+ createContent: (managedSection) => managedSection,
103
+ });
104
+ if (status === "created" || status === "updated") {
84
105
  log.info("Updated AGENTS.md");
85
106
  }
86
107
  }
@@ -0,0 +1,9 @@
1
+ interface ManagedSectionOptions {
2
+ path: string;
3
+ name: string;
4
+ content: string;
5
+ createContent: (section: string) => string;
6
+ }
7
+ export declare function ensureManagedSection(options: ManagedSectionOptions): "created" | "updated" | "unchanged" | "missing-markers";
8
+ export {};
9
+ //# sourceMappingURL=ensureManagedSection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensureManagedSection.d.ts","sourceRoot":"","sources":["../../src/helpers/ensureManagedSection.ts"],"names":[],"mappings":"AAGA,UAAU,qBAAqB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC5C;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,qBAAqB,GAC7B,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,iBAAiB,CAmCzD"}
@@ -0,0 +1,30 @@
1
+ import { log } from "@clack/prompts";
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ export function ensureManagedSection(options) {
4
+ const startMarker = `<!-- setup-data-project:${options.name}:start -->`;
5
+ const endMarker = `<!-- setup-data-project:${options.name}:end -->`;
6
+ const trimmedContent = options.content.trim();
7
+ const section = trimmedContent === ""
8
+ ? `${startMarker}\n${endMarker}`
9
+ : `${startMarker}\n${trimmedContent}\n${endMarker}`;
10
+ if (!existsSync(options.path)) {
11
+ writeFileSync(options.path, options.createContent(section));
12
+ return "created";
13
+ }
14
+ const currentContent = readFileSync(options.path, "utf-8");
15
+ const start = currentContent.indexOf(startMarker);
16
+ const end = currentContent.indexOf(endMarker);
17
+ if (start === -1 || end === -1 || end < start) {
18
+ log.warn(`${options.path} was not updated because its setup-data-project markers ` +
19
+ `were not found. Add ${startMarker} and ${endMarker}, then rerun the ` +
20
+ "script.");
21
+ return "missing-markers";
22
+ }
23
+ const nextContent = currentContent.slice(0, start) + section +
24
+ currentContent.slice(end + endMarker.length);
25
+ if (nextContent === currentContent) {
26
+ return "unchanged";
27
+ }
28
+ writeFileSync(options.path, nextContent);
29
+ return "updated";
30
+ }
@@ -1,2 +1,2 @@
1
- export declare function ensureReadme(runtime: string): Promise<void>;
1
+ export declare function ensureReadme(runtime: string, installedPackages?: string[]): void;
2
2
  //# sourceMappingURL=ensureReadme.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ensureReadme.d.ts","sourceRoot":"","sources":["../../src/helpers/ensureReadme.ts"],"names":[],"mappings":"AAGA,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,iBAmCjD"}
1
+ {"version":3,"file":"ensureReadme.d.ts","sourceRoot":"","sources":["../../src/helpers/ensureReadme.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,iBAAiB,GAAE,MAAM,EAAO,QAwDjC"}
@@ -1,6 +1,7 @@
1
1
  import { log } from "@clack/prompts";
2
- import { handleFileConflict } from "./handleFileConflict.js";
3
- export async function ensureReadme(runtime) {
2
+ import { ensureManagedSection } from "./ensureManagedSection.js";
3
+ import { getInstalledPackageConfigs } from "./packageRegistry.js";
4
+ export function ensureReadme(runtime, installedPackages = []) {
4
5
  let runCommand = "npm run";
5
6
  if (runtime === "deno") {
6
7
  runCommand = "deno task";
@@ -8,13 +9,27 @@ export async function ensureReadme(runtime) {
8
9
  else if (runtime === "bun") {
9
10
  runCommand = "bun run";
10
11
  }
11
- const readmeContent = `This repository has been created with
12
+ const installedPackageConfigs = getInstalledPackageConfigs(installedPackages);
13
+ const hasSda = installedPackageConfigs.some((pkg) => pkg.type === "sda");
14
+ const hasJournalism = installedPackageConfigs.some((pkg) => pkg.type === "journalism");
15
+ const libraryLinks = [
16
+ hasSda
17
+ ? "[simple-data-analysis](https://github.com/nshiab/simple-data-analysis)"
18
+ : "",
19
+ hasJournalism ? "[journalism](https://github.com/nshiab/journalism)" : "",
20
+ ].filter(Boolean);
21
+ const librarySection = libraryLinks.length === 0
22
+ ? ""
23
+ : `It's installing ${libraryLinks.join(" and ")} libraries, with up-to-date
24
+ documentation and AI agent instructions.`;
25
+ const status = ensureManagedSection({
26
+ path: "README.md",
27
+ name: "libraries",
28
+ content: librarySection,
29
+ createContent: (managedSection) => `This repository has been created with
12
30
  [setup-data-project](https://github.com/nshiab/setup-data-project/).
13
31
 
14
- It's installing
15
- [simple-data-analysis](https://github.com/nshiab/simple-data-analysis) and
16
- [journalism](https://github.com/nshiab/journalism) libraries, with up-to-date
17
- documentation and AI agent instructions.
32
+ ${managedSection}
18
33
 
19
34
  Here's the recommended workflow:
20
35
 
@@ -27,12 +42,11 @@ When working on your project, use the following command:
27
42
 
28
43
  - \`${runCommand} sda\` will watch your \`sda/main.ts\` and its dependencies. Everytime
29
44
  you'll save some changes, the data will be reprocessed.
30
- - \`${runCommand} clean\` will remove \`.sda-cache/\`, \`.journalism-cache/\` and \`.tmp/\`,
31
- if present.
45
+ - \`${runCommand} clean\` will remove cache and temporary files, if present.
32
46
 
33
- Have fun!`;
34
- const status = await handleFileConflict("README.md", readmeContent);
35
- if (status === "updated") {
47
+ Have fun!`,
48
+ });
49
+ if (status === "created" || status === "updated") {
36
50
  log.info("Updated README.md");
37
51
  }
38
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gitignoreEntries.d.ts","sourceRoot":"","sources":["../../src/helpers/gitignoreEntries.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,UAQ7B,CAAC"}
1
+ {"version":3,"file":"gitignoreEntries.d.ts","sourceRoot":"","sources":["../../src/helpers/gitignoreEntries.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,UAS7B,CAAC"}
@@ -4,6 +4,7 @@ export const GITIGNORE_ENTRIES = [
4
4
  ".sda-cache",
5
5
  ".journalism-cache",
6
6
  "sda/data",
7
+ "sda/output",
7
8
  ".env",
8
9
  ".DS_Store",
9
10
  ];
@@ -1,6 +1,9 @@
1
1
  export declare const commandRunner: {
2
2
  exec: any;
3
3
  };
4
+ export declare function fetchPackageDocs(pkg: string, options?: {
5
+ silent?: boolean;
6
+ }): Promise<string | undefined>;
4
7
  export declare function installPackagesAndFetchDocs(selectedPackages: string[], options?: {
5
8
  silent?: boolean;
6
9
  }): Promise<string | void>;
@@ -1 +1 @@
1
- {"version":3,"file":"installPackagesAndFetchDocs.d.ts","sourceRoot":"","sources":["../../src/helpers/installPackagesAndFetchDocs.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAEF,wBAAsB,2BAA2B,CAC/C,gBAAgB,EAAE,MAAM,EAAE,EAC1B,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4FxB"}
1
+ {"version":3,"file":"installPackagesAndFetchDocs.d.ts","sourceRoot":"","sources":["../../src/helpers/installPackagesAndFetchDocs.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAEF,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA4C7B;AAED,wBAAsB,2BAA2B,CAC/C,gBAAgB,EAAE,MAAM,EAAE,EAC1B,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4DxB"}
@@ -1,4 +1,4 @@
1
- import { spinner } from "@clack/prompts";
1
+ import { log, spinner } from "@clack/prompts";
2
2
  import * as childProcess from "node:child_process";
3
3
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
4
4
  import { join } from "node:path";
@@ -6,6 +6,44 @@ import { getRuntime } from "./getRuntime.js";
6
6
  export const commandRunner = {
7
7
  exec: childProcess.exec,
8
8
  };
9
+ export async function fetchPackageDocs(pkg, options = {}) {
10
+ if (!existsSync("docs")) {
11
+ mkdirSync("docs");
12
+ }
13
+ const sFetch = spinner();
14
+ if (!options.silent) {
15
+ sFetch.start("Fetching documentation for " + pkg + "...");
16
+ }
17
+ try {
18
+ const repoName = pkg.split("/")[1];
19
+ const url = "https://raw.githubusercontent.com/nshiab/" + repoName +
20
+ "/refs/heads/main/llm.md";
21
+ const response = await fetch(url);
22
+ if (!response.ok) {
23
+ if (!options.silent) {
24
+ sFetch.stop("⚠️ No documentation (llm.md) found for " + pkg + ".");
25
+ }
26
+ log.warn(`Documentation for ${pkg} could not be refreshed. Rerun the script ` +
27
+ "later to try again.");
28
+ return undefined;
29
+ }
30
+ const docContent = await response.text();
31
+ writeFileSync(join("docs", repoName + ".md"), docContent);
32
+ if (!options.silent) {
33
+ sFetch.stop("✅ Documentation for " + pkg + " saved!");
34
+ }
35
+ return docContent;
36
+ }
37
+ catch (error) {
38
+ if (!options.silent) {
39
+ sFetch.stop("❌ Failed to fetch documentation for " + pkg + ".");
40
+ }
41
+ log.warn(`Documentation for ${pkg} could not be refreshed. Rerun the script ` +
42
+ "later to try again.");
43
+ console.error(error);
44
+ return undefined;
45
+ }
46
+ }
9
47
  export async function installPackagesAndFetchDocs(selectedPackages, options = {}) {
10
48
  const runtime = getRuntime();
11
49
  if (Array.isArray(selectedPackages) && selectedPackages.length > 0) {
@@ -52,39 +90,9 @@ export async function installPackagesAndFetchDocs(selectedPackages, options = {}
52
90
  throw error;
53
91
  }
54
92
  }
55
- // Documentation logic
56
- if (pkg === "@observablehq/plot") {
57
- continue;
58
- }
59
- const sFetch = spinner();
60
- try {
61
- if (!options.silent) {
62
- sFetch.start("Fetching documentation for " + pkg + "...");
63
- }
64
- const repoName = pkg.split("/")[1];
65
- const url = "https://raw.githubusercontent.com/nshiab/" + repoName +
66
- "/refs/heads/main/llm.md";
67
- const response = await fetch(url);
68
- if (response.ok) {
69
- const docContent = await response.text();
70
- writeFileSync(join("docs", repoName + ".md"), docContent);
71
- if (!options.silent) {
72
- sFetch.stop("✅ Documentation for " + pkg + " saved!");
73
- }
74
- lastDoc = docContent;
75
- }
76
- else {
77
- if (!options.silent) {
78
- sFetch.stop("⚠️ No documentation (llm.md) found for " + pkg +
79
- ". Skipping doc fetch.");
80
- }
81
- }
82
- }
83
- catch (error) {
84
- if (!options.silent) {
85
- sFetch.stop("❌ Failed to fetch documentation for " + pkg + ".");
86
- }
87
- console.error(error);
93
+ const docContent = await fetchPackageDocs(pkg, options);
94
+ if (docContent !== undefined) {
95
+ lastDoc = docContent;
88
96
  }
89
97
  }
90
98
  return lastDoc;
@@ -5,4 +5,5 @@ export interface PackageConfig {
5
5
  hint?: string;
6
6
  }
7
7
  export declare const SUPPORTED_PACKAGES: PackageConfig[];
8
+ export declare function getInstalledPackageConfigs(installedPackages: string[]): PackageConfig[];
8
9
  //# sourceMappingURL=packageRegistry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageRegistry.d.ts","sourceRoot":"","sources":["../../src/helpers/packageRegistry.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,KAAK,GAAG,YAAY,GAAG,OAAO,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,kBAAkB,EAAE,aAAa,EAwF7C,CAAC"}
1
+ {"version":3,"file":"packageRegistry.d.ts","sourceRoot":"","sources":["../../src/helpers/packageRegistry.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,KAAK,GAAG,YAAY,GAAG,OAAO,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,kBAAkB,EAAE,aAAa,EAwF7C,CAAC;AAEF,wBAAgB,0BAA0B,CACxC,iBAAiB,EAAE,MAAM,EAAE,GAC1B,aAAa,EAAE,CAGjB"}
@@ -78,3 +78,7 @@ export const SUPPORTED_PACKAGES = [
78
78
  hint: "Functions to zip/unzip, sleep, reencode files, create nested directories...",
79
79
  },
80
80
  ];
81
+ export function getInstalledPackageConfigs(installedPackages) {
82
+ const installedSet = new Set(installedPackages);
83
+ return SUPPORTED_PACKAGES.filter((pkg) => installedSet.has(pkg.value));
84
+ }
@@ -0,0 +1,11 @@
1
+ type Runtime = "deno" | "node" | "bun";
2
+ export declare class ProjectManifest {
3
+ #private;
4
+ private constructor();
5
+ static open(runtime: Runtime): ProjectManifest;
6
+ reload(): void;
7
+ getInstalledPackages(): string[];
8
+ updateTasks(tasks: Record<string, string>): void;
9
+ }
10
+ export {};
11
+ //# sourceMappingURL=projectManifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectManifest.d.ts","sourceRoot":"","sources":["../../src/helpers/projectManifest.ts"],"names":[],"mappings":"AAEA,KAAK,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAGvC,qBAAa,eAAe;;IAM1B,OAAO;IAYP,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe;IA6B9C,MAAM,IAAI,IAAI;IAId,oBAAoB,IAAI,MAAM,EAAE;IAgBhC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;CAUjD"}
@@ -0,0 +1,73 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _ProjectManifest_path, _ProjectManifest_taskKey, _ProjectManifest_dependencyKeys, _ProjectManifest_config;
13
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
14
+ export class ProjectManifest {
15
+ constructor(path, taskKey, dependencyKeys, config) {
16
+ _ProjectManifest_path.set(this, void 0);
17
+ _ProjectManifest_taskKey.set(this, void 0);
18
+ _ProjectManifest_dependencyKeys.set(this, void 0);
19
+ _ProjectManifest_config.set(this, void 0);
20
+ __classPrivateFieldSet(this, _ProjectManifest_path, path, "f");
21
+ __classPrivateFieldSet(this, _ProjectManifest_taskKey, taskKey, "f");
22
+ __classPrivateFieldSet(this, _ProjectManifest_dependencyKeys, dependencyKeys, "f");
23
+ __classPrivateFieldSet(this, _ProjectManifest_config, config, "f");
24
+ }
25
+ static open(runtime) {
26
+ if (existsSync("deno.json")) {
27
+ return new ProjectManifest("deno.json", "tasks", ["imports"], readManifest("deno.json"));
28
+ }
29
+ if (existsSync("package.json")) {
30
+ return new ProjectManifest("package.json", "scripts", ["dependencies", "devDependencies"], readManifest("package.json"));
31
+ }
32
+ return runtime === "deno"
33
+ ? new ProjectManifest("deno.json", "tasks", ["imports"], { tasks: {} })
34
+ : new ProjectManifest("package.json", "scripts", ["dependencies", "devDependencies"], { name: "data-project", type: "module", scripts: {} });
35
+ }
36
+ reload() {
37
+ __classPrivateFieldSet(this, _ProjectManifest_config, readManifest(__classPrivateFieldGet(this, _ProjectManifest_path, "f")), "f");
38
+ }
39
+ getInstalledPackages() {
40
+ const installed = [];
41
+ for (const key of __classPrivateFieldGet(this, _ProjectManifest_dependencyKeys, "f")) {
42
+ const dependencies = __classPrivateFieldGet(this, _ProjectManifest_config, "f")[key];
43
+ if (dependencies && typeof dependencies === "object" &&
44
+ !Array.isArray(dependencies)) {
45
+ installed.push(...Object.keys(dependencies));
46
+ }
47
+ }
48
+ return installed;
49
+ }
50
+ updateTasks(tasks) {
51
+ const currentTasks = __classPrivateFieldGet(this, _ProjectManifest_config, "f")[__classPrivateFieldGet(this, _ProjectManifest_taskKey, "f")];
52
+ const existingTasks = currentTasks && typeof currentTasks === "object" &&
53
+ !Array.isArray(currentTasks)
54
+ ? currentTasks
55
+ : {};
56
+ __classPrivateFieldGet(this, _ProjectManifest_config, "f")[__classPrivateFieldGet(this, _ProjectManifest_taskKey, "f")] = { ...existingTasks, ...tasks };
57
+ writeFileSync(__classPrivateFieldGet(this, _ProjectManifest_path, "f"), JSON.stringify(__classPrivateFieldGet(this, _ProjectManifest_config, "f"), null, 2), "utf-8");
58
+ }
59
+ }
60
+ _ProjectManifest_path = new WeakMap(), _ProjectManifest_taskKey = new WeakMap(), _ProjectManifest_dependencyKeys = new WeakMap(), _ProjectManifest_config = new WeakMap();
61
+ function readManifest(path) {
62
+ try {
63
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
64
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
65
+ throw new SyntaxError("the root value must be a JSON object");
66
+ }
67
+ return parsed;
68
+ }
69
+ catch (error) {
70
+ const detail = error instanceof Error ? ` ${error.message}` : "";
71
+ throw new Error(`Failed to parse ${path}.${detail}`, { cause: error });
72
+ }
73
+ }
@@ -0,0 +1,2 @@
1
+ export declare function syncPackageDocs(installedPackages: string[], docsAlreadyRefreshed?: string[]): Promise<Record<string, string>>;
2
+ //# sourceMappingURL=syncPackageDocs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncPackageDocs.d.ts","sourceRoot":"","sources":["../../src/helpers/syncPackageDocs.ts"],"names":[],"mappings":"AAMA,wBAAsB,eAAe,CACnC,iBAAiB,EAAE,MAAM,EAAE,EAC3B,oBAAoB,GAAE,MAAM,EAAO,GAClC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA0BjC"}
@@ -0,0 +1,27 @@
1
+ import { log } from "@clack/prompts";
2
+ import { existsSync, readFileSync, rmSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { fetchPackageDocs } from "./installPackagesAndFetchDocs.js";
5
+ import { SUPPORTED_PACKAGES } from "./packageRegistry.js";
6
+ export async function syncPackageDocs(installedPackages, docsAlreadyRefreshed = []) {
7
+ const installedSet = new Set(installedPackages);
8
+ const refreshedSet = new Set(docsAlreadyRefreshed);
9
+ const docsMapping = {};
10
+ for (const pkg of SUPPORTED_PACKAGES) {
11
+ const docPath = join("docs", pkg.value.split("/")[1] + ".md");
12
+ if (!installedSet.has(pkg.value)) {
13
+ if (existsSync(docPath)) {
14
+ rmSync(docPath);
15
+ log.info(`Removed stale documentation at ${docPath}.`);
16
+ }
17
+ continue;
18
+ }
19
+ if (!existsSync(docPath) && !refreshedSet.has(pkg.value)) {
20
+ await fetchPackageDocs(pkg.value, { silent: true });
21
+ }
22
+ if (existsSync(docPath)) {
23
+ docsMapping[pkg.value] = readFileSync(docPath, "utf-8");
24
+ }
25
+ }
26
+ return docsMapping;
27
+ }
package/esm/main.js CHANGED
@@ -2,9 +2,7 @@
2
2
  import { cancel, intro, isCancel, multiselect, outro, select, spinner, } from "@clack/prompts";
3
3
  import process from "node:process";
4
4
  import { getRuntime } from "./helpers/getRuntime.js";
5
- import { getInstalledPackages } from "./helpers/getInstalledPackages.js";
6
5
  import { PACKAGE_OPTIONS } from "./helpers/packageOptions.js";
7
- import { updateProjectConfig } from "./helpers/updateProjectConfig.js";
8
6
  import { ensureGitignore } from "./helpers/ensureGitignore.js";
9
7
  import { ensureReadme } from "./helpers/ensureReadme.js";
10
8
  import { installPackagesAndFetchDocs } from "./helpers/installPackagesAndFetchDocs.js";
@@ -12,12 +10,16 @@ import { getProjectTasks } from "./helpers/getProjectTasks.js";
12
10
  import { createFolderStructure } from "./helpers/createFolderStructure.js";
13
11
  import { ensureEnvFile } from "./helpers/ensureEnvFile.js";
14
12
  import { ensureAgents } from "./helpers/ensureAgents.js";
13
+ import { getInstalledPackageConfigs } from "./helpers/packageRegistry.js";
14
+ import { ProjectManifest } from "./helpers/projectManifest.js";
15
+ import { syncPackageDocs } from "./helpers/syncPackageDocs.js";
15
16
  async function main() {
16
17
  const runtime = getRuntime();
17
18
  console.log();
18
19
  intro(`Hi! 👋 (Running on ${runtime})`);
19
- updateProjectConfig(getProjectTasks());
20
- const installedPackages = getInstalledPackages();
20
+ const projectManifest = ProjectManifest.open(runtime);
21
+ projectManifest.updateTasks(getProjectTasks());
22
+ const installedPackages = projectManifest.getInstalledPackages();
21
23
  const options = PACKAGE_OPTIONS.map((opt) => ({
22
24
  ...opt,
23
25
  label: installedPackages.includes(opt.value)
@@ -56,15 +58,11 @@ async function main() {
56
58
  packagesToInstall.push(pkg);
57
59
  }
58
60
  }
59
- const docsMapping = {};
60
61
  const sInstall = spinner();
61
62
  sInstall.start("Installing packages and fetching documentation...");
62
63
  for (const pkg of packagesToInstall) {
63
64
  try {
64
- const doc = await installPackagesAndFetchDocs([pkg], { silent: true });
65
- if (typeof doc === "string") {
66
- docsMapping[pkg] = doc;
67
- }
65
+ await installPackagesAndFetchDocs([pkg], { silent: true });
68
66
  }
69
67
  catch (error) {
70
68
  sInstall.stop(`❌ Failed to install ${pkg}.`);
@@ -73,12 +71,19 @@ async function main() {
73
71
  }
74
72
  }
75
73
  sInstall.stop("✅ Packages installed and documentation fetched.");
76
- updateProjectConfig(getProjectTasks());
77
- await createFolderStructure(packagesToInstall);
74
+ projectManifest.reload();
75
+ projectManifest.updateTasks(getProjectTasks());
76
+ const finalInstalledPackages = getInstalledPackageConfigs(projectManifest.getInstalledPackages()).map((pkg) => pkg.value);
77
+ const docsMapping = await syncPackageDocs(finalInstalledPackages, packagesToInstall);
78
+ await createFolderStructure(finalInstalledPackages);
78
79
  ensureGitignore();
79
80
  await ensureEnvFile();
80
- await ensureReadme(runtime);
81
- await ensureAgents(docsMapping, runtime);
81
+ await ensureReadme(runtime, finalInstalledPackages);
82
+ await ensureAgents(docsMapping, runtime, finalInstalledPackages);
82
83
  outro("You are all set! 🙌");
83
84
  }
84
- main().catch(console.error);
85
+ main().catch((error) => {
86
+ const message = error instanceof Error ? error.message : String(error);
87
+ console.error(`❌ Error: ${message}`);
88
+ process.exitCode = 1;
89
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nshiab/setup-data-project",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "description": "Quickly kick off your data project using the simple-data-analysis and journalism libraries.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,2 +1,2 @@
1
- export declare function ensureAgents(docsMapping: Record<string, string>, runtime: string): Promise<void>;
1
+ export declare function ensureAgents(docsMapping: Record<string, string>, runtime: string, installedPackages?: string[]): void;
2
2
  //# sourceMappingURL=ensureAgents.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ensureAgents.d.ts","sourceRoot":"","sources":["../../src/helpers/ensureAgents.ts"],"names":[],"mappings":"AAIA,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,OAAO,EAAE,MAAM,iBA2FhB"}
1
+ {"version":3,"file":"ensureAgents.d.ts","sourceRoot":"","sources":["../../src/helpers/ensureAgents.ts"],"names":[],"mappings":"AAOA,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,OAAO,EAAE,MAAM,EACf,iBAAiB,GAAE,MAAM,EAA6B,QAuHvD"}