pointfree-docs 0.1.0 ā 0.2.1
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 +67 -7
- package/dist/cli.js +89 -2
- package/dist/commands/get.d.ts +2 -0
- package/dist/commands/get.js +59 -2
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +78 -13
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +59 -19
- package/dist/commands/search.d.ts +1 -0
- package/dist/commands/search.js +27 -4
- package/dist/commands/stats.js +32 -5
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +33 -7
- package/dist/config.d.ts +32 -1
- package/dist/config.js +34 -1
- package/dist/lib/format.d.ts +12 -0
- package/dist/lib/format.js +30 -0
- package/dist/lib/index.d.ts +14 -2
- package/dist/lib/index.js +162 -25
- package/dist/lib/repos.d.ts +32 -0
- package/dist/lib/repos.js +133 -1
- package/package.json +3 -3
package/dist/commands/search.js
CHANGED
|
@@ -3,11 +3,25 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { search as searchIndex, withIndex } from "../lib/index.js";
|
|
6
|
+
import { SOURCE_TYPES } from "../config.js";
|
|
7
|
+
import { getSourceLabel } from "../lib/format.js";
|
|
6
8
|
export function searchCommand(query, options) {
|
|
7
9
|
const limit = options.limit ? parseInt(options.limit, 10) : 10;
|
|
8
|
-
|
|
10
|
+
// Validate source option
|
|
11
|
+
let source = "docs"; // Default to docs only
|
|
12
|
+
if (options.source) {
|
|
13
|
+
if (options.source === "all" || SOURCE_TYPES.includes(options.source)) {
|
|
14
|
+
source = options.source;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
console.log(chalk.red(`Invalid source: ${options.source}`));
|
|
18
|
+
console.log(chalk.gray(`Valid sources: ${SOURCE_TYPES.join(", ")}, all`));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const results = withIndex(() => searchIndex(query, { lib: options.lib, limit, source }));
|
|
9
23
|
if (options.json) {
|
|
10
|
-
console.log(JSON.stringify({ query, results }, null, 2));
|
|
24
|
+
console.log(JSON.stringify({ query, source, results }, null, 2));
|
|
11
25
|
return;
|
|
12
26
|
}
|
|
13
27
|
if (results.length === 0) {
|
|
@@ -15,17 +29,26 @@ export function searchCommand(query, options) {
|
|
|
15
29
|
if (options.lib) {
|
|
16
30
|
console.log(chalk.gray(` (searched in library: ${options.lib})`));
|
|
17
31
|
}
|
|
32
|
+
if (source !== "all") {
|
|
33
|
+
console.log(chalk.gray(` (searched in source: ${source})`));
|
|
34
|
+
console.log(chalk.gray(` Try --source=all to search everything`));
|
|
35
|
+
}
|
|
18
36
|
console.log(chalk.gray(`\nTry a different query or run 'pf-docs list' to see available docs.`));
|
|
19
37
|
return;
|
|
20
38
|
}
|
|
21
|
-
|
|
39
|
+
const sourceLabel = source === "all" ? "all sources" : source;
|
|
40
|
+
console.log(chalk.bold(`\nš Search results for: "${query}" (${sourceLabel})\n`));
|
|
22
41
|
for (let i = 0; i < results.length; i++) {
|
|
23
42
|
const result = results[i];
|
|
24
|
-
|
|
43
|
+
const label = source === "all" ? `${getSourceLabel(result.source)} ` : "";
|
|
44
|
+
console.log(`${label}${chalk.blue(`${i + 1}. ${result.title}`)}`);
|
|
25
45
|
console.log(chalk.gray(` Path: ${result.path}`));
|
|
26
46
|
console.log(chalk.gray(` ${result.snippet}`));
|
|
27
47
|
console.log();
|
|
28
48
|
}
|
|
29
49
|
console.log(chalk.gray(`\nTo view a document: pf-docs get <path>`));
|
|
30
50
|
console.log(chalk.gray(`Example: pf-docs get ${results[0].path}`));
|
|
51
|
+
if (source !== "all") {
|
|
52
|
+
console.log(chalk.gray(`\nTip: Use --source=all to search docs, examples, and episodes together`));
|
|
53
|
+
}
|
|
31
54
|
}
|
package/dist/commands/stats.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { getStats, withIndex } from "../lib/index.js";
|
|
6
|
-
import { LIBRARIES, getLibrary } from "../config.js";
|
|
7
|
-
import { isLibraryCloned } from "../lib/repos.js";
|
|
6
|
+
import { LIBRARIES, getLibrary, EXAMPLES_CONFIG, EPISODES_CONFIG } from "../config.js";
|
|
7
|
+
import { isLibraryCloned, areExamplesCloned, areEpisodesCloned } from "../lib/repos.js";
|
|
8
|
+
import { getSourceName } from "../lib/format.js";
|
|
8
9
|
export function statsCommand(options) {
|
|
9
10
|
const stats = withIndex(() => getStats());
|
|
10
11
|
if (options.json) {
|
|
@@ -12,12 +13,19 @@ export function statsCommand(options) {
|
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
15
|
console.log(chalk.bold("\nš pf-docs Statistics\n"));
|
|
15
|
-
console.log(chalk.blue(`Total indexed
|
|
16
|
+
console.log(chalk.blue(`Total indexed items: ${stats.totalDocs}`));
|
|
16
17
|
console.log();
|
|
17
|
-
|
|
18
|
+
// Show breakdown by source
|
|
19
|
+
console.log(chalk.bold("By source:"));
|
|
20
|
+
for (const [sourceName, count] of Object.entries(stats.bySource)) {
|
|
21
|
+
console.log(` ${getSourceName(sourceName)}: ${count} items`);
|
|
22
|
+
}
|
|
23
|
+
console.log();
|
|
24
|
+
// Show breakdown by library
|
|
25
|
+
console.log(chalk.bold("By library:"));
|
|
18
26
|
for (const [libName, count] of Object.entries(stats.byLibrary)) {
|
|
19
27
|
const libConfig = getLibrary(libName);
|
|
20
|
-
console.log(` ${chalk.green("ā")} ${libName}: ${count}
|
|
28
|
+
console.log(` ${chalk.green("ā")} ${libName}: ${count} items`);
|
|
21
29
|
if (libConfig) {
|
|
22
30
|
console.log(chalk.gray(` ${libConfig.description}`));
|
|
23
31
|
}
|
|
@@ -34,4 +42,23 @@ export function statsCommand(options) {
|
|
|
34
42
|
console.log();
|
|
35
43
|
console.log(chalk.gray(`To add: pf-docs init --libs ${notIndexed[0].shortName}`));
|
|
36
44
|
}
|
|
45
|
+
// Show examples/episodes status
|
|
46
|
+
const extrasNotIndexed = [];
|
|
47
|
+
if (!areExamplesCloned()) {
|
|
48
|
+
extrasNotIndexed.push("examples");
|
|
49
|
+
}
|
|
50
|
+
if (!areEpisodesCloned()) {
|
|
51
|
+
extrasNotIndexed.push("episodes");
|
|
52
|
+
}
|
|
53
|
+
if (extrasNotIndexed.length > 0) {
|
|
54
|
+
console.log(chalk.bold("Additional sources (not indexed):"));
|
|
55
|
+
if (extrasNotIndexed.includes("examples")) {
|
|
56
|
+
console.log(` ${chalk.gray("ā")} examples ā ${EXAMPLES_CONFIG.description}`);
|
|
57
|
+
}
|
|
58
|
+
if (extrasNotIndexed.includes("episodes")) {
|
|
59
|
+
console.log(` ${chalk.gray("ā")} episodes ā ${EPISODES_CONFIG.description}`);
|
|
60
|
+
}
|
|
61
|
+
console.log();
|
|
62
|
+
console.log(chalk.gray(`To add: pf-docs init --examples --episodes`));
|
|
63
|
+
}
|
|
37
64
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { LIBRARIES, getLibrary } from "../config.js";
|
|
6
|
-
import { updateLibrary, isLibraryCloned } from "../lib/repos.js";
|
|
7
|
-
import { indexLibrary, openIndex, closeIndex } from "../lib/index.js";
|
|
6
|
+
import { updateLibrary, updateExamples, updateEpisodes, isLibraryCloned, areExamplesCloned, areEpisodesCloned } from "../lib/repos.js";
|
|
7
|
+
import { indexLibrary, indexExamples, indexEpisodes, openIndex, closeIndex } from "../lib/index.js";
|
|
8
8
|
export async function updateCommand(options) {
|
|
9
9
|
console.log(chalk.bold("\nš Updating Point-Free Documentation\n"));
|
|
10
10
|
// Determine which libraries to update
|
|
@@ -24,27 +24,53 @@ export async function updateCommand(options) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
// Check for examples/episodes
|
|
28
|
+
const shouldUpdateExamples = options.examples && areExamplesCloned();
|
|
29
|
+
const shouldUpdateEpisodes = options.episodes && areEpisodesCloned();
|
|
30
|
+
if (options.examples && !areExamplesCloned()) {
|
|
31
|
+
console.log(chalk.yellow(` ā Examples not initialized. Run 'pf-docs init --examples' first.`));
|
|
32
|
+
}
|
|
33
|
+
if (options.episodes && !areEpisodesCloned()) {
|
|
34
|
+
console.log(chalk.yellow(` ā Episodes not initialized. Run 'pf-docs init --episodes' first.`));
|
|
35
|
+
}
|
|
36
|
+
if (librariesToUpdate.length === 0 && !shouldUpdateExamples && !shouldUpdateEpisodes) {
|
|
37
|
+
console.log(chalk.yellow("Nothing to update. Run 'pf-docs init' first."));
|
|
29
38
|
return;
|
|
30
39
|
}
|
|
31
40
|
// Update repositories
|
|
32
41
|
console.log(chalk.bold("Pulling latest changes..."));
|
|
33
42
|
const updatedLibs = [];
|
|
43
|
+
let examplesUpdated = false;
|
|
44
|
+
let episodesUpdated = false;
|
|
34
45
|
for (const lib of librariesToUpdate) {
|
|
35
46
|
const wasUpdated = await updateLibrary(lib);
|
|
36
47
|
if (wasUpdated) {
|
|
37
48
|
updatedLibs.push(lib);
|
|
38
49
|
}
|
|
39
50
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
if (shouldUpdateExamples) {
|
|
52
|
+
examplesUpdated = await updateExamples();
|
|
53
|
+
}
|
|
54
|
+
if (shouldUpdateEpisodes) {
|
|
55
|
+
episodesUpdated = await updateEpisodes();
|
|
56
|
+
}
|
|
57
|
+
// Re-index updated sources
|
|
58
|
+
const hasUpdates = updatedLibs.length > 0 || examplesUpdated || episodesUpdated;
|
|
59
|
+
if (hasUpdates) {
|
|
60
|
+
console.log(chalk.bold("\nRe-indexing updated sources..."));
|
|
43
61
|
openIndex();
|
|
44
62
|
for (const lib of updatedLibs) {
|
|
45
63
|
const count = indexLibrary(lib);
|
|
46
64
|
console.log(` ā Re-indexed ${lib.shortName}: ${count} documents`);
|
|
47
65
|
}
|
|
66
|
+
if (examplesUpdated) {
|
|
67
|
+
const count = indexExamples();
|
|
68
|
+
console.log(` ā Re-indexed examples: ${count} files`);
|
|
69
|
+
}
|
|
70
|
+
if (episodesUpdated) {
|
|
71
|
+
const count = indexEpisodes();
|
|
72
|
+
console.log(` ā Re-indexed episodes: ${count} files`);
|
|
73
|
+
}
|
|
48
74
|
closeIndex();
|
|
49
75
|
}
|
|
50
76
|
console.log(chalk.green(`\nā
Update complete!\n`));
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Configuration for Point-Free libraries
|
|
2
|
+
* Configuration for Point-Free libraries and example sources
|
|
3
3
|
*/
|
|
4
|
+
/**
|
|
5
|
+
* Source types for documentation
|
|
6
|
+
*/
|
|
7
|
+
export type SourceType = "docs" | "examples" | "episodes";
|
|
4
8
|
export interface LibraryConfig {
|
|
5
9
|
name: string;
|
|
6
10
|
shortName: string;
|
|
@@ -8,11 +12,34 @@ export interface LibraryConfig {
|
|
|
8
12
|
docsPaths: string[];
|
|
9
13
|
description: string;
|
|
10
14
|
}
|
|
15
|
+
export interface ExamplesConfig {
|
|
16
|
+
name: string;
|
|
17
|
+
shortName: string;
|
|
18
|
+
repo: string;
|
|
19
|
+
paths: string[];
|
|
20
|
+
description: string;
|
|
21
|
+
filePatterns: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface EpisodesConfig {
|
|
24
|
+
name: string;
|
|
25
|
+
shortName: string;
|
|
26
|
+
repo: string;
|
|
27
|
+
description: string;
|
|
28
|
+
filePatterns: string[];
|
|
29
|
+
}
|
|
11
30
|
/**
|
|
12
31
|
* All available Point-Free libraries
|
|
13
32
|
* Add or remove libraries here to customize what's indexed
|
|
14
33
|
*/
|
|
15
34
|
export declare const LIBRARIES: LibraryConfig[];
|
|
35
|
+
/**
|
|
36
|
+
* TCA Examples configuration (CaseStudies, SyncUps, etc.)
|
|
37
|
+
*/
|
|
38
|
+
export declare const EXAMPLES_CONFIG: ExamplesConfig;
|
|
39
|
+
/**
|
|
40
|
+
* Episode code samples configuration
|
|
41
|
+
*/
|
|
42
|
+
export declare const EPISODES_CONFIG: EpisodesConfig;
|
|
16
43
|
/**
|
|
17
44
|
* Get library config by short name
|
|
18
45
|
*/
|
|
@@ -21,6 +48,10 @@ export declare function getLibrary(shortName: string): LibraryConfig | undefined
|
|
|
21
48
|
* All library short names
|
|
22
49
|
*/
|
|
23
50
|
export declare const LIBRARY_NAMES: string[];
|
|
51
|
+
/**
|
|
52
|
+
* All valid source types
|
|
53
|
+
*/
|
|
54
|
+
export declare const SOURCE_TYPES: SourceType[];
|
|
24
55
|
export declare const PATHS: {
|
|
25
56
|
dataDir: string;
|
|
26
57
|
reposDir: string;
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Configuration for Point-Free libraries
|
|
2
|
+
* Configuration for Point-Free libraries and example sources
|
|
3
3
|
*/
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
/**
|
|
@@ -100,6 +100,35 @@ export const LIBRARIES = [
|
|
|
100
100
|
description: "Runtime warnings & assertions",
|
|
101
101
|
},
|
|
102
102
|
];
|
|
103
|
+
/**
|
|
104
|
+
* TCA Examples configuration (CaseStudies, SyncUps, etc.)
|
|
105
|
+
*/
|
|
106
|
+
export const EXAMPLES_CONFIG = {
|
|
107
|
+
name: "tca-examples",
|
|
108
|
+
shortName: "examples",
|
|
109
|
+
repo: "pointfreeco/swift-composable-architecture",
|
|
110
|
+
paths: [
|
|
111
|
+
"Examples/CaseStudies",
|
|
112
|
+
"Examples/SyncUps",
|
|
113
|
+
"Examples/Todos",
|
|
114
|
+
"Examples/VoiceMemos",
|
|
115
|
+
"Examples/Search",
|
|
116
|
+
"Examples/TicTacToe",
|
|
117
|
+
"Examples/SpeechRecognition",
|
|
118
|
+
],
|
|
119
|
+
description: "TCA example apps and case studies",
|
|
120
|
+
filePatterns: ["**/*.swift"],
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Episode code samples configuration
|
|
124
|
+
*/
|
|
125
|
+
export const EPISODES_CONFIG = {
|
|
126
|
+
name: "episode-code-samples",
|
|
127
|
+
shortName: "episodes",
|
|
128
|
+
repo: "pointfreeco/episode-code-samples",
|
|
129
|
+
description: "Point-Free episode code samples (350+ episodes)",
|
|
130
|
+
filePatterns: ["**/*.swift", "**/*.playground/**/*.swift"],
|
|
131
|
+
};
|
|
103
132
|
/**
|
|
104
133
|
* Get library config by short name
|
|
105
134
|
*/
|
|
@@ -110,6 +139,10 @@ export function getLibrary(shortName) {
|
|
|
110
139
|
* All library short names
|
|
111
140
|
*/
|
|
112
141
|
export const LIBRARY_NAMES = LIBRARIES.map((lib) => lib.shortName);
|
|
142
|
+
/**
|
|
143
|
+
* All valid source types
|
|
144
|
+
*/
|
|
145
|
+
export const SOURCE_TYPES = ["docs", "examples", "episodes"];
|
|
113
146
|
/**
|
|
114
147
|
* Paths configuration
|
|
115
148
|
*/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
import { SourceType } from "../config.js";
|
|
5
|
+
/**
|
|
6
|
+
* Get source type label with color and brackets for search/list results
|
|
7
|
+
*/
|
|
8
|
+
export declare function getSourceLabel(source: SourceType): string;
|
|
9
|
+
/**
|
|
10
|
+
* Get source type name with color (for stats display)
|
|
11
|
+
*/
|
|
12
|
+
export declare function getSourceName(source: SourceType): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
/**
|
|
6
|
+
* Get source type label with color and brackets for search/list results
|
|
7
|
+
*/
|
|
8
|
+
export function getSourceLabel(source) {
|
|
9
|
+
switch (source) {
|
|
10
|
+
case "docs":
|
|
11
|
+
return chalk.cyan("[DOC]");
|
|
12
|
+
case "examples":
|
|
13
|
+
return chalk.magenta("[EXAMPLE]");
|
|
14
|
+
case "episodes":
|
|
15
|
+
return chalk.yellow("[EPISODE]");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get source type name with color (for stats display)
|
|
20
|
+
*/
|
|
21
|
+
export function getSourceName(source) {
|
|
22
|
+
switch (source) {
|
|
23
|
+
case "docs":
|
|
24
|
+
return chalk.cyan("docs");
|
|
25
|
+
case "examples":
|
|
26
|
+
return chalk.magenta("examples");
|
|
27
|
+
case "episodes":
|
|
28
|
+
return chalk.yellow("episodes");
|
|
29
|
+
}
|
|
30
|
+
}
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* Search index using SQLite FTS5 for full-text search
|
|
3
3
|
*/
|
|
4
4
|
import Database from "better-sqlite3";
|
|
5
|
-
import { LibraryConfig } from "../config.js";
|
|
5
|
+
import { LibraryConfig, SourceType } from "../config.js";
|
|
6
6
|
export interface DocEntry {
|
|
7
7
|
library: string;
|
|
8
8
|
path: string;
|
|
9
9
|
title: string;
|
|
10
|
+
source: SourceType;
|
|
10
11
|
}
|
|
11
12
|
export interface DocWithContent extends DocEntry {
|
|
12
13
|
content: string;
|
|
@@ -14,6 +15,7 @@ export interface DocWithContent extends DocEntry {
|
|
|
14
15
|
export interface IndexStats {
|
|
15
16
|
totalDocs: number;
|
|
16
17
|
byLibrary: Record<string, number>;
|
|
18
|
+
bySource: Record<SourceType, number>;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Initialize or open the search index database
|
|
@@ -23,6 +25,14 @@ export declare function openIndex(): Database.Database;
|
|
|
23
25
|
* Index all documentation files for a library
|
|
24
26
|
*/
|
|
25
27
|
export declare function indexLibrary(lib: LibraryConfig): number;
|
|
28
|
+
/**
|
|
29
|
+
* Index TCA examples (CaseStudies, etc.)
|
|
30
|
+
*/
|
|
31
|
+
export declare function indexExamples(): number;
|
|
32
|
+
/**
|
|
33
|
+
* Index episode code samples
|
|
34
|
+
*/
|
|
35
|
+
export declare function indexEpisodes(): number;
|
|
26
36
|
/**
|
|
27
37
|
* Search the index
|
|
28
38
|
*/
|
|
@@ -32,15 +42,17 @@ export interface SearchResult {
|
|
|
32
42
|
title: string;
|
|
33
43
|
snippet: string;
|
|
34
44
|
score: number;
|
|
45
|
+
source: SourceType;
|
|
35
46
|
}
|
|
36
47
|
export declare function search(query: string, options?: {
|
|
37
48
|
lib?: string;
|
|
38
49
|
limit?: number;
|
|
50
|
+
source?: SourceType | "all";
|
|
39
51
|
}): SearchResult[];
|
|
40
52
|
/**
|
|
41
53
|
* List all indexed documents
|
|
42
54
|
*/
|
|
43
|
-
export declare function listDocs(lib?: string): DocEntry[];
|
|
55
|
+
export declare function listDocs(lib?: string, source?: SourceType | "all"): DocEntry[];
|
|
44
56
|
/**
|
|
45
57
|
* Get a specific document by path
|
|
46
58
|
*/
|