Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ea3ffe5

Browse files
committedApr 26, 2025·
🐛 setup deno package
0 parents  commit ea3ffe5

File tree

10 files changed

+3715
-0
lines changed

10 files changed

+3715
-0
lines changed
 

‎.github/workflows/ci.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CI
2+
on:
3+
push:
4+
branches:
5+
- main
6+
- master
7+
tags:
8+
- '!*' # Do not execute on tags
9+
env:
10+
NAME: ${{vars.NAME}}
11+
EMAIL: ${{vars.EMAIL}}
12+
NPM_TOKEN: ${{secrets.NPM_TOKEN}}
13+
GITHUB_TOKEN: ${{secrets.GH_TOKEN}}
14+
FORCE_COLOR: 1
15+
16+
17+
jobs:
18+
test:
19+
strategy:
20+
matrix:
21+
platform: [ubuntu-latest, windows-latest, macOS-latest]
22+
name: Test on ${{matrix.platform}}
23+
runs-on: ${{matrix.platform}}
24+
steps:
25+
- uses: actions/checkout@v4
26+
- uses: denoland/setup-deno@v2
27+
with:
28+
deno-version: v2.x
29+
- run: deno test
30+
31+
32+
publish:
33+
name: Publish package
34+
needs: [test]
35+
runs-on: ubuntu-latest
36+
permissions:
37+
contents: write
38+
id-token: write
39+
steps:
40+
- uses: actions/checkout@v4
41+
- run: npx jsr publish

‎.github/workflows/pr.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: PR
2+
on: [pull_request]
3+
env:
4+
FORCE_COLOR: 1
5+
6+
7+
jobs:
8+
test:
9+
strategy:
10+
matrix:
11+
platform: [ubuntu-latest, windows-latest, macOS-latest]
12+
name: Test on ${{matrix.platform}}
13+
runs-on: ${{matrix.platform}}
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: denoland/setup-deno@v2
17+
with:
18+
deno-version: v2.x
19+
- run: deno test

‎.gitignore

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Generated files
2+
.build/
3+
*.d.ts
4+
*.map
5+
6+
# Logs
7+
logs
8+
*.log
9+
10+
11+
*.orig
12+
*.pyc
13+
*.swp
14+
.env
15+
16+
/.cargo_home/
17+
/.idea/
18+
/.vs/
19+
/.vscode/
20+
gclient_config.py_entries
21+
/target/
22+
/std/hash/_wasm/target
23+
/tests/wpt/runner/manifest.json
24+
/third_party/
25+
/tests/napi/node_modules
26+
/tests/napi/build
27+
/tests/napi/third_party_tests/node_modules
28+
29+
# MacOS generated files
30+
.DS_Store
31+
.DS_Store?
32+
33+
# Flamegraphs
34+
/flamebench*.svg
35+
/flamegraph*.svg
36+
37+
# WPT generated cert files
38+
/tests/wpt/runner/certs/index.txt*
39+
/tests/wpt/runner/certs/serial*
40+
41+
/ext/websocket/autobahn/reports
42+
43+
# JUnit files produced by deno test --junit
44+
junit.xml
45+
46+
# Jupyter files
47+
.ipynb_checkpoints/
48+
Untitled*.ipynb
49+
50+
# playwright browser binary cache
51+
/.ms-playwright

‎LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018-25 Subhajit Sahu
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎README.md

Lines changed: 317 additions & 0 deletions
Large diffs are not rendered by default.

‎build.ts

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
4+
/**
5+
* Reads a wiki file and extracts:
6+
* - functionName: detected from the first code block (assuming signature like "function foo(")
7+
* - example: the content of the second fenced code block (if exists), or fallback to first
8+
*/
9+
function parseWikiFile(filePath: string): { functionName: string, example: string } | null {
10+
const content = fs.readFileSync(filePath, 'utf8');
11+
12+
// Regex to match fenced code blocks (optionally with "javascript" after the backticks)
13+
const codeBlockRegex = /```(?:javascript)?\s*([\s\S]*?)\s*```/g;
14+
const blocks: string[] = [];
15+
let match: RegExpExecArray | null;
16+
17+
while ((match = codeBlockRegex.exec(content)) !== null) {
18+
blocks.push(match[1].trim());
19+
}
20+
21+
if (blocks.length === 0) {
22+
console.warn(`No code blocks found in ${filePath}`);
23+
return null;
24+
}
25+
26+
// Determine function name from the first code block that contains a function declaration.
27+
const functionSigRegex = /function\s+(\w+)\s*\(/;
28+
let functionName = "";
29+
for (const block of blocks) {
30+
const m = block.match(functionSigRegex);
31+
if (m && m[1]) {
32+
functionName = m[1];
33+
break;
34+
}
35+
}
36+
if (!functionName) {
37+
console.warn(`Could not determine function name in ${filePath}`);
38+
return null;
39+
}
40+
41+
// Use second code block as the example if available, otherwise use the first.
42+
const example = blocks.length >= 2 ? blocks[1] : blocks[0];
43+
return { functionName, example };
44+
}
45+
46+
/**
47+
* Scans a folder for .md files and creates a mapping from functionName to example content.
48+
*/
49+
function getWikiExamples(wikiFolder: string): Map<string, string> {
50+
const wikiExamples = new Map<string, string>();
51+
const files = fs.readdirSync(wikiFolder).filter(file => file.endsWith('.md'));
52+
53+
for (const file of files) {
54+
const fullPath = path.join(wikiFolder, file);
55+
const parsed = parseWikiFile(fullPath);
56+
if (parsed) {
57+
wikiExamples.set(parsed.functionName, parsed.example);
58+
console.log(`Mapped function "${parsed.functionName}" from ${file}`);
59+
}
60+
}
61+
return wikiExamples;
62+
}
63+
64+
/**
65+
* Updates the JSDoc comment preceding a function declaration with a new @example tag.
66+
* If an @example tag is already present, it is replaced; otherwise it is added.
67+
*
68+
* @param tsCode The TypeScript source file content.
69+
* @param funcName The function name to update.
70+
* @param example The example string to insert.
71+
* @returns The updated source code.
72+
*/
73+
function updateFunctionJsDoc(tsCode: string, funcName: string, example: string): string {
74+
// This regex finds a JSDoc block and the corresponding function declaration line.
75+
// It assumes the function is declared as "export function <funcName>(..."
76+
// and that the JSDoc block is immediately before the function declaration.
77+
const jsdocRegex = new RegExp(`(/\\*\\*[\\s\\S]*?\\*/)(\\s*export\\s+function\\s+(\\w+)\\s*\\()`, 'g');
78+
79+
return tsCode.replace(jsdocRegex, (match, jsdocBlock, funcDecl, funcDef) => {
80+
if (funcDef !== funcName) return match; // Only update if the function name matches
81+
// Check if an @example tag already exists
82+
const exampleTagRegex = /@example\s+([\s\S]*?)(\n\s*\*\s*@|\n\s*\*\/)/;
83+
let updatedJsdoc: string;
84+
if (exampleTagRegex.test(jsdocBlock)) {
85+
// Replace existing @example content with the new example (preserving formatting)
86+
updatedJsdoc = jsdocBlock.replace(exampleTagRegex, (_, __, ending) => {
87+
return `@example\n * \`\`\`javascript\n * ${example.replace(/\n/g, '\n * ')}\n * \`\`\`${ending}`;
88+
});
89+
} else {
90+
// Insert the @example tag before the closing */
91+
updatedJsdoc = jsdocBlock.replace(/\n\s*\*\/$/, `\n * @example\n * \`\`\`javascript\n * ${example.replace(/\n/g, '\n * ')}\n * \`\`\`\n */`);
92+
}
93+
return updatedJsdoc + funcDecl;
94+
});
95+
}
96+
97+
/**
98+
* Main function that takes a wiki folder and a target TypeScript file,
99+
* and propagates the examples from the wiki files into the corresponding JSDoc blocks.
100+
*/
101+
function propagateExamplesToTs(wikiFolder: string, tsFilePath: string): void {
102+
const wikiExamples = getWikiExamples(wikiFolder);
103+
let tsCode = fs.readFileSync(tsFilePath, 'utf8');
104+
105+
// For every function example from the wiki files, update the corresponding jsdoc comment.
106+
wikiExamples.forEach((example, funcName) => {
107+
const newTsCode = updateFunctionJsDoc(tsCode, funcName, example);
108+
if (newTsCode === tsCode) {
109+
console.warn(`No JSDoc for function "${funcName}" was updated. Ensure there is an exported function named "${funcName}" with a preceding JSDoc block.`);
110+
} else {
111+
console.log(`Updated JSDoc for function "${funcName}".`);
112+
// console.log(`Example:\n${example}`);
113+
}
114+
tsCode = newTsCode;
115+
});
116+
117+
// Write updated source code back to file (or you could write to a new file if desired)
118+
fs.writeFileSync(tsFilePath, tsCode, 'utf8');
119+
console.log(`File updated: ${tsFilePath}`);
120+
}
121+
122+
// ---
123+
// Example usage:
124+
//
125+
// node populate-examples.js <path-to-wiki-folder> <path-to-ts-file>
126+
//
127+
// For example:
128+
//
129+
// node populate-examples.js ./wiki ./src/extra-number.ts
130+
// ---
131+
132+
// Process command-line arguments
133+
const args = process.argv.slice(2);
134+
if (args.length < 2) {
135+
console.error('Usage: node populate-examples.js <wikiFolderPath> <tsFilePath>');
136+
process.exit(1);
137+
}
138+
139+
const [wikiFolderPath, tsFilePath] = args;
140+
141+
if (!fs.existsSync(wikiFolderPath)) {
142+
console.error(`Wiki folder does not exist: ${wikiFolderPath}`);
143+
process.exit(1);
144+
}
145+
146+
if (!fs.existsSync(tsFilePath)) {
147+
console.error(`TypeScript file does not exist: ${tsFilePath}`);
148+
process.exit(1);
149+
}
150+
151+
propagateExamplesToTs(wikiFolderPath, tsFilePath);

‎deno.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "@nodef/extra-string",
3+
"version": "0.1.1",
4+
"license": "MIT",
5+
"exports": "./index.ts",
6+
"exclude": [".github/"]
7+
}

‎deno.lock

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎index.test.ts

Lines changed: 1255 additions & 0 deletions
Large diffs are not rendered by default.

‎index.ts

Lines changed: 1835 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.