This commit is contained in:
hakutaku 2025-03-22 01:43:05 +03:00
commit 3bc4598142
17 changed files with 5382 additions and 0 deletions

5
.envrc Normal file
View File

@ -0,0 +1,5 @@
use nix
# hack
# https://github.com/direnv/direnv/issues/1345
mkdir -p $TMPDIR

132
.gitignore vendored Normal file
View File

@ -0,0 +1,132 @@
# ---> Node
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

5
.vscode-test.mjs Normal file
View File

@ -0,0 +1,5 @@
import { defineConfig } from '@vscode/test-cli';
export default defineConfig({
files: 'out/test/**/*.test.js',
});

5
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher", "ms-vscode.extension-test-runner"]
}

21
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,21 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}"
}
]
}

13
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,13 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false, // set this to true to hide the "out" folder with the compiled JS files
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
},
"search.exclude": {
"out": true, // set this to false to include "out" folder in search results
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off"
}

40
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,40 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": "$ts-webpack-watch",
"isBackground": true,
"presentation": {
"reveal": "never",
"group": "watchers"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "watch-tests",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never",
"group": "watchers"
},
"group": "build"
},
{
"label": "tasks: watch-tests",
"dependsOn": [
"npm: watch",
"npm: watch-tests"
],
"problemMatcher": []
}
]
}

14
.vscodeignore Normal file
View File

@ -0,0 +1,14 @@
.vscode/**
.vscode-test/**
out/**
node_modules/**
src/**
.gitignore
.yarnrc
webpack.config.js
vsc-extension-quickstart.md
**/tsconfig.json
**/eslint.config.mjs
**/*.map
**/*.ts
**/.vscode-test.*

71
README.md Normal file
View File

@ -0,0 +1,71 @@
# test README
This is the README for your extension "test". After writing up a brief description, we recommend including the following sections.
## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
## Extension Settings
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
For example:
This extension contributes the following settings:
* `myExtension.enable`: Enable/disable this extension.
* `myExtension.thing`: Set to `blah` to do something.
## Known Issues
Calling out known issues can help limit users opening duplicate issues against your extension.
## Release Notes
Users appreciate release notes as you update your extension.
### 1.0.0
Initial release of ...
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
---
## Following extension guidelines
Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension.
* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)
## Working with Markdown
You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux).
* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux).
* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets.
## For more information
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
**Enjoy!**

28
eslint.config.mjs Normal file
View File

@ -0,0 +1,28 @@
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
export default [{
files: ["**/*.ts"],
}, {
plugins: {
"@typescript-eslint": typescriptEslint,
},
languageOptions: {
parser: tsParser,
ecmaVersion: 2022,
sourceType: "module",
},
rules: {
"@typescript-eslint/naming-convention": ["warn", {
selector: "import",
format: ["camelCase", "PascalCase"],
}],
curly: "warn",
eqeqeq: "warn",
"no-throw-literal": "warn",
semi: "warn",
},
}];

4736
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

73
package.json Normal file
View File

@ -0,0 +1,73 @@
{
"name": "test",
"displayName": "test",
"description": "test",
"version": "0.0.1",
"engines": {
"vscode": "^1.97.0"
},
"categories": [
"Other"
],
"activationEvents": [],
"main": "./dist/extension.js",
"contributes": {
"commands": [
{
"command": "hakutaku.initSymfonyFlexRepo",
"title": "New Objective-C class..."
},
{
"command": "hakutaku.initSymfonyFlexRepo",
"title": "New Objective-C class..."
}
],
"submenus": [
{
"id": "sparkup.submenu",
"label": "Objective-C"
}
],
"menus": {
"explorer/context": [
{
"submenu": "sparkup.submenu",
"group": "navigation"
}
],
"sparkup.submenu": [
{
"command": "hakutaku.initSymfonyFlexRepo"
},
{
"command": "hakutaku.initSymfonyFlexRepo"
}
]
}
},
"scripts": {
"vscode:prepublish": "npm run package",
"compile": "webpack",
"watch": "webpack --watch",
"package": "webpack --mode production --devtool hidden-source-map",
"compile-tests": "tsc -p . --outDir out",
"watch-tests": "tsc -p . -w --outDir out",
"pretest": "npm run compile-tests && npm run compile && npm run lint",
"lint": "eslint src",
"test": "vscode-test"
},
"devDependencies": {
"@types/vscode": "^1.97.0",
"@types/mocha": "^10.0.10",
"@types/node": "20.x",
"@typescript-eslint/eslint-plugin": "^8.22.0",
"@typescript-eslint/parser": "^8.22.0",
"eslint": "^9.19.0",
"typescript": "^5.7.3",
"ts-loader": "^9.5.2",
"webpack": "^5.97.1",
"webpack-cli": "^6.0.1",
"@vscode/test-cli": "^0.0.10",
"@vscode/test-electron": "^2.4.1"
}
}

7
shell.nix Normal file
View File

@ -0,0 +1,7 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = with pkgs.buildPackages; [
gnumake
nodejs_22
];
}

153
src/extension.ts Normal file
View File

@ -0,0 +1,153 @@
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
// Функция для преобразования в PascalCase
const toPascalCase = (input: string): string => {
return input
.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))
.replace(/^(.)/, (match) => match.toUpperCase());
};
const toCamelCase = (input: string): string => {
return input
.trim()
.replace(/[^a-zA-Z0-9]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))
.replace(/^(.)/, (match) => match.toLowerCase());
};
function validateUserInput(userInput: string): true {
const isValidFormat = (input: string): boolean => {
const regex = /^[a-z0-9-_]+\/[a-z0-9-_]+$/;
return regex.test(input);
};
if (!isValidFormat(userInput)) {
throw new Error('Incorrect package name');
}
return true;
}
function getBundlePaths(uri: vscode.Uri, userInput: string): [vendorPath: string, bundlePath: string] {
const [vendor, bundle] = userInput.split('/');
const pascalCasedVendor: string = toPascalCase(vendor);
const pascalCasedBundle: string = toPascalCase(bundle);
const vendorPath: string = path.join(uri.path, pascalCasedVendor);
const bundlePath: string = path.join(vendorPath, pascalCasedBundle);
return [vendorPath, bundlePath];
}
function prepareBundlePaths(vendorPath: string, bundlePath: string): true {
if (!directoryExists(vendorPath)) {
fs.mkdirSync(vendorPath);
}
if (directoryExists(bundlePath)) {
throw new Error('Already exists');
}
fs.mkdirSync(bundlePath);
return true;
}
/**
*
* @param dirPath
* @returns
*/
function directoryExists(dirPath: string): boolean {
try {
return fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory();
} catch (err: unknown) {
return false;
}
}
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
const initSymfonyFlexRepo: vscode.Disposable = vscode.commands.registerCommand('hakutaku.initSymfonyFlexRepo', async (uri: vscode.Uri): Promise<void> => {
// Проверка на наличие директории "recipes" и flex.lock файла
try {
const workspaceFolders = vscode.workspace.workspaceFolders;
const workspaceFsPaths = workspaceFolders?.map((folder: vscode.WorkspaceFolder) => folder.uri.fsPath);
if (!workspaceFsPaths?.includes(uri.fsPath)) {
throw new Error('Можно добавить только в корневую директорию');
}
const stats: fs.Stats = fs.statSync(uri.path);
if (stats.isDirectory()) {
const packagesDir = path.join(uri.path, 'packages');
if (!fs.existsSync(packagesDir)) {
fs.mkdirSync(packagesDir);
}
} else {
throw new Error('Пакет можно добавить только в директорию');
}
// Диалог добавления нового рецепта
const userInput: string | undefined = await vscode.window.showInputBox({
prompt: 'Enter your package name',
placeHolder: 'acme/foo-bundle'
});
// Валидация строки на соответствие формату acme/foo-bundle
if ((userInput) && (validateUserInput(userInput))) {
const [vendorPath, bundlePath] = getBundlePaths(uri, userInput);
if (prepareBundlePaths(vendorPath, bundlePath)) {
}
vscode.window.showInformationMessage(`Hello, ${userInput}!`);
} else {
throw new Error('No input provided');
}
} catch (error: unknown) {
if (error instanceof Error) {
vscode.window.showErrorMessage(error.message);
} else {
vscode.window.showErrorMessage('Unhandled error');
}
}
});
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
const disposable: vscode.Disposable = vscode.commands.registerCommand('test.helloWorld', () => {
const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
if (editor) {
const language: string = editor.document.languageId;
vscode.window.showInformationMessage(`The current document's language is ${language}`);
const position = editor.selection.active;
const line = position.line;
vscode.window.showInformationMessage(`Current caret line: ${line}`);
editor.edit(editBuilder => {
editBuilder.insert(new vscode.Position(line, 0), '#[Annotation]\n');
});
}
});
context.subscriptions.push(initSymfonyFlexRepo);
context.subscriptions.push(disposable);
}
// This method is called when your extension is deactivated
export function deactivate() { }

View File

@ -0,0 +1,15 @@
import * as assert from 'assert';
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../../extension';
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});

16
tsconfig.json Normal file
View File

@ -0,0 +1,16 @@
{
"compilerOptions": {
"module": "Node16",
"target": "ES2022",
"lib": [
"ES2022"
],
"sourceMap": true,
"rootDir": "src",
"strict": true, /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
}
}

48
webpack.config.js Normal file
View File

@ -0,0 +1,48 @@
//@ts-check
'use strict';
const path = require('path');
//@ts-check
/** @typedef {import('webpack').Configuration} WebpackConfig **/
/** @type WebpackConfig */
const extensionConfig = {
target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
output: {
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
path: path.resolve(__dirname, 'dist'),
filename: 'extension.js',
libraryTarget: 'commonjs2'
},
externals: {
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
// modules added here also need to be added in the .vscodeignore file
},
resolve: {
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader'
}
]
}
]
},
devtool: 'nosources-source-map',
infrastructureLogging: {
level: "log", // enables logging required for problem matchers
},
};
module.exports = [ extensionConfig ];