@sambitcreate/parsely-cli 2.2.0 → 2.3.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/dist/cli.js CHANGED
@@ -1,9 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { render } from 'ink';
4
+ import { createRequire } from 'node:module';
4
5
  import { App } from './app.js';
5
6
  import { sanitizeTerminalText } from './utils/helpers.js';
6
7
  import { createSynchronizedWriteProxy, resetDefaultTerminalBackground, shouldUseDisplayPalette, shouldUseSynchronizedOutput, } from './utils/terminal.js';
8
+ const require = createRequire(import.meta.url);
9
+ const { version } = require('../package.json');
7
10
  const ENTER_ALT_SCREEN = '\u001B[?1049h\u001B[2J\u001B[H';
8
11
  const EXIT_ALT_SCREEN = '\u001B[?1049l';
9
12
  // Simple arg parsing – accept an optional recipe URL as the first positional arg
@@ -32,7 +35,7 @@ if (args.includes('--help') || args.includes('-h')) {
32
35
  }
33
36
  // Handle --version / -v
34
37
  if (args.includes('--version') || args.includes('-v')) {
35
- console.log('parsely-cli v2.2.0');
38
+ console.log(`parsely-cli v${version}`);
36
39
  process.exit(0);
37
40
  }
38
41
  async function main() {
@@ -1,4 +1,4 @@
1
- type AppPhase = 'idle' | 'scraping' | 'display' | 'error';
1
+ import { type AppPhase } from '../utils/helpers.js';
2
2
  interface BannerProps {
3
3
  phase: AppPhase;
4
4
  currentUrl?: string;
@@ -1,7 +1,7 @@
1
- export type AppPhase = 'idle' | 'scraping' | 'display' | 'error';
1
+ import type { AppPhase } from '../utils/helpers.js';
2
+ export type { AppPhase };
2
3
  interface FooterProps {
3
4
  phase: AppPhase;
4
5
  width: number;
5
6
  }
6
7
  export declare function Footer({ phase, width }: FooterProps): import("react/jsx-runtime").JSX.Element;
7
- export {};
@@ -5,6 +5,7 @@ import { readFileSync } from 'node:fs';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { URLInput } from './URLInput.js';
7
7
  import { theme } from '../theme.js';
8
+ import { buildOccurrenceKeys } from '../utils/helpers.js';
8
9
  function readLogoSvg() {
9
10
  try {
10
11
  return readFileSync(fileURLToPath(new URL('../../public/parsely-logo.svg', import.meta.url)), 'utf8');
@@ -41,14 +42,6 @@ function stripCommonIndent(lines) {
41
42
  }
42
43
  return lines.map((line) => line.slice(indent));
43
44
  }
44
- function buildOccurrenceKeys(items) {
45
- const counts = new Map();
46
- return items.map((item) => {
47
- const count = (counts.get(item) ?? 0) + 1;
48
- counts.set(item, count);
49
- return `${item}-${count}`;
50
- });
51
- }
52
45
  function buildLandingArt() {
53
46
  const rendered = CFonts.render('Parsely', {
54
47
  font: 'block',
@@ -1,5 +1,5 @@
1
1
  import type { Recipe, ScrapeStatus } from '../services/scraper.js';
2
- type AppPhase = 'idle' | 'scraping' | 'display' | 'error';
2
+ import type { AppPhase } from '../utils/helpers.js';
3
3
  interface PhaseRailProps {
4
4
  phase: AppPhase;
5
5
  status?: ScrapeStatus | null;
@@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
3
3
  import { Box, Text, useInput } from 'ink';
4
4
  import BigText from 'ink-big-text';
5
5
  import { theme } from '../theme.js';
6
- import { formatMinutes, getUrlHost, isoToMinutes } from '../utils/helpers.js';
6
+ import { buildOccurrenceKeys, formatMinutes, getUrlHost, isoToMinutes } from '../utils/helpers.js';
7
7
  import { wrapText } from '../utils/text-layout.js';
8
8
  function extractInstructions(recipe) {
9
9
  const raw = recipe.recipeInstructions;
@@ -33,14 +33,6 @@ function extractInstructions(recipe) {
33
33
  }
34
34
  return steps;
35
35
  }
36
- function buildOccurrenceKeys(items) {
37
- const counts = new Map();
38
- return items.map((item) => {
39
- const count = (counts.get(item) ?? 0) + 1;
40
- counts.set(item, count);
41
- return `${item}-${count}`;
42
- });
43
- }
44
36
  function formatTimeValue(iso) {
45
37
  if (!iso)
46
38
  return 'Not listed';
@@ -101,7 +93,7 @@ function buildCompactHeaderLines(recipe, sourceHost, contentWidth) {
101
93
  '',
102
94
  ];
103
95
  }
104
- function buildCompactBodyLines(recipe, sourceHost, sourceLabel, sourceCopy, contentWidth, ingredients, instructions) {
96
+ function buildCompactBodyLines(sourceHost, sourceLabel, sourceCopy, contentWidth, ingredients, instructions) {
105
97
  const lines = [];
106
98
  lines.push('Ingredients');
107
99
  lines.push(buildRule(contentWidth, contentWidth));
@@ -160,7 +152,7 @@ export function RecipeCard({ recipe, width, height, sourceUrl }) {
160
152
  const constrained = width < 110 || height < 34;
161
153
  const compactContentWidth = Math.max(24, width - 4);
162
154
  const compactHeaderLines = buildCompactHeaderLines(recipe, sourceHost, compactContentWidth);
163
- const compactBodyLines = buildCompactBodyLines(recipe, sourceHost, sourceLabel, sourceCopy, compactContentWidth, ingredients, instructions);
155
+ const compactBodyLines = buildCompactBodyLines(sourceHost, sourceLabel, sourceCopy, compactContentWidth, ingredients, instructions);
164
156
  const compactBodyHeight = Math.max(4, height - compactHeaderLines.length - 2);
165
157
  const maxScroll = Math.max(0, compactBodyLines.length - compactBodyHeight);
166
158
  const visibleBodyLines = compactBodyLines.slice(scrollOffset, scrollOffset + compactBodyHeight);
@@ -10,7 +10,7 @@ const BROWSER_ARGS = [
10
10
  '--disable-blink-features=AutomationControlled',
11
11
  ];
12
12
  const BROWSER_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 ' +
13
- '(KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36';
13
+ '(KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36';
14
14
  const PAGE_TIMEOUT_MS = 20_000;
15
15
  const NETWORK_IDLE_TIMEOUT_MS = 5_000;
16
16
  const AI_TIMEOUT_MS = 30_000;
@@ -190,7 +190,9 @@ async function configurePage(page) {
190
190
  await page.evaluateOnNewDocument(() => {
191
191
  Object.defineProperty(navigator, 'webdriver', { get: () => false });
192
192
  Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
193
- Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3] });
193
+ Object.defineProperty(navigator, 'plugins', {
194
+ get: () => Object.assign([{}, {}, {}], { length: 3, refresh: () => { } }),
195
+ });
194
196
  });
195
197
  }
196
198
  function createTimedSignal(signal, timeoutMs) {
@@ -21,3 +21,5 @@ export declare function getUrlHost(url?: string): string;
21
21
  * Basic URL validation.
22
22
  */
23
23
  export declare function isValidUrl(url: string): boolean;
24
+ export type AppPhase = 'idle' | 'scraping' | 'display' | 'error';
25
+ export declare function buildOccurrenceKeys(items: string[]): string[];
@@ -79,3 +79,11 @@ export function isValidUrl(url) {
79
79
  return false;
80
80
  }
81
81
  }
82
+ export function buildOccurrenceKeys(items) {
83
+ const counts = new Map();
84
+ return items.map((item) => {
85
+ const count = (counts.get(item) ?? 0) + 1;
86
+ counts.set(item, count);
87
+ return `${item}-${count}`;
88
+ });
89
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sambitcreate/parsely-cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "A smart recipe scraper CLI with interactive TUI built on Ink",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
@@ -43,20 +43,20 @@
43
43
  },
44
44
  "homepage": "https://github.com/sambitcreate/parsely-cli#readme",
45
45
  "dependencies": {
46
- "cheerio": "^1.0.0",
47
46
  "cfonts": "^3.1.1",
47
+ "cheerio": "^1.0.0",
48
48
  "dotenv": "^16.4.7",
49
49
  "ink": "^5.1.0",
50
50
  "ink-big-text": "^2.0.0",
51
51
  "ink-spinner": "^5.0.0",
52
52
  "ink-text-input": "^6.0.0",
53
53
  "openai": "^4.82.0",
54
- "puppeteer-core": "^24.2.1",
54
+ "puppeteer-core": "^24.38.0",
55
55
  "react": "^18.3.1"
56
56
  },
57
57
  "devDependencies": {
58
- "@types/react": "^18.3.18",
59
58
  "@types/ink-big-text": "^1.2.4",
59
+ "@types/react": "^18.3.28",
60
60
  "tsx": "^4.19.2",
61
61
  "typescript": "^5.7.3"
62
62
  },