├── .npmrc ├── src ├── snippets │ ├── pug.json │ ├── variables.json │ ├── xsl.json │ └── html.json ├── extract-abbreviation │ ├── brackets.ts │ ├── quotes.ts │ ├── reader.ts │ ├── is-html.ts │ └── index.ts ├── markup │ ├── format │ │ ├── slim.ts │ │ ├── pug.ts │ │ ├── haml.ts │ │ ├── walk.ts │ │ ├── utils.ts │ │ ├── comment.ts │ │ └── template.ts │ ├── addon │ │ ├── xsl.ts │ │ ├── label.ts │ │ └── bem.ts │ ├── implicit-tag.ts │ ├── utils.ts │ ├── lorem │ │ ├── russian.json │ │ ├── latin.json │ │ ├── spanish.json │ │ └── index.ts │ ├── attributes.ts │ ├── index.ts │ └── snippets.ts ├── stylesheet │ ├── color.ts │ ├── score.ts │ ├── snippets.ts │ └── format.ts ├── index.ts └── output-stream.ts ├── packages ├── scanner │ ├── .gitignore │ ├── tsconfig.json │ ├── .npmignore │ ├── rollup.config.js │ ├── package.json │ ├── LICENSE │ ├── test │ │ ├── stream-reader.ts │ │ └── utils.ts │ └── src │ │ ├── scanner.ts │ │ └── utils.ts ├── abbreviation │ ├── .npmignore │ ├── tsconfig.json │ ├── rollup.config.js │ ├── src │ │ ├── index.ts │ │ ├── parser │ │ │ └── TokenScanner.ts │ │ ├── tokenizer │ │ │ ├── utils.ts │ │ │ └── tokens.ts │ │ ├── types.ts │ │ └── stringify.ts │ ├── package.json │ ├── LICENSE │ ├── test │ │ ├── assets │ │ │ ├── stringify-node.ts │ │ │ └── stringify.ts │ │ ├── tokenizer.ts │ │ ├── convert.ts │ │ └── parser.ts │ └── README.md └── css-abbreviation │ ├── .npmignore │ ├── tsconfig.json │ ├── rollup.config.js │ ├── src │ ├── index.ts │ ├── tokenizer │ │ ├── utils.ts │ │ └── tokens.ts │ └── parser │ │ ├── TokenScanner.ts │ │ └── index.ts │ ├── package.json │ ├── LICENSE │ ├── test │ ├── assets │ │ └── stringify.ts │ └── parser.ts │ └── README.md ├── lerna.json ├── .npmignore ├── .editorconfig ├── tsconfig.json ├── .github ├── FUNDING.yml └── workflows │ └── node.js.yml ├── rollup.config.js ├── test ├── snippets.ts ├── assets │ └── stringify.ts ├── lorem.ts ├── output.ts ├── markup.ts └── extract-abbreviation.ts ├── LICENSE ├── .gitignore ├── package.json └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true 2 | -------------------------------------------------------------------------------- /src/snippets/pug.json: -------------------------------------------------------------------------------- 1 | { 2 | "!!!": "{doctype html}" 3 | } 4 | -------------------------------------------------------------------------------- /packages/scanner/.gitignore: -------------------------------------------------------------------------------- 1 | /scanner.js 2 | /scanner.es.js 3 | /scanner.cjs 4 | /*.d.ts 5 | /*.map 6 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 3 | "version": "independent" 4 | } 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | node_modules 3 | jspm_packages 4 | .npm 5 | /.* 6 | /*.* 7 | /test 8 | /src 9 | /packages 10 | -------------------------------------------------------------------------------- /packages/abbreviation/.npmignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | node_modules 3 | jspm_packages 4 | .npm 5 | /.* 6 | /*.* 7 | /test 8 | /src 9 | -------------------------------------------------------------------------------- /packages/css-abbreviation/.npmignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | node_modules 3 | jspm_packages 4 | .npm 5 | /.* 6 | /*.* 7 | /test 8 | /src 9 | -------------------------------------------------------------------------------- /src/snippets/variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "en", 3 | "locale": "en-US", 4 | "charset": "utf-8", 5 | "indentation": "\t", 6 | "newline": "\n" 7 | } 8 | -------------------------------------------------------------------------------- /packages/scanner/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": ["src"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/abbreviation/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": ["src/**/*.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/css-abbreviation/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig", 3 | "compilerOptions": { 4 | "outDir": "./dist" 5 | }, 6 | "include": ["src"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/scanner/.npmignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | node_modules 3 | jspm_packages 4 | .npm 5 | /.* 6 | /*.* 7 | !/scanner.js 8 | !/scanner.cjs 9 | !/*.d.ts 10 | !/*.map 11 | /test 12 | /src 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.{json,yml}] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [snippets/*.json] 16 | indent_style = tab 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /src/extract-abbreviation/brackets.ts: -------------------------------------------------------------------------------- 1 | export const enum Brackets { 2 | SquareL = 91, 3 | SquareR = 93, 4 | RoundL = 40, 5 | RoundR = 41, 6 | CurlyL = 123, 7 | CurlyR = 125, 8 | } 9 | 10 | export const bracePairs = { 11 | [Brackets.SquareL]: Brackets.SquareR, 12 | [Brackets.RoundL]: Brackets.RoundR, 13 | [Brackets.CurlyL]: Brackets.CurlyR, 14 | }; 15 | -------------------------------------------------------------------------------- /packages/scanner/rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | 3 | export default { 4 | input: './src/scanner.ts', 5 | plugins: [typescript()], 6 | output: [{ 7 | format: 'cjs', 8 | exports: 'named', 9 | sourcemap: true, 10 | file: './dist/scanner.cjs' 11 | }, { 12 | format: 'es', 13 | sourcemap: true, 14 | file: './dist/scanner.js' 15 | }] 16 | }; 17 | -------------------------------------------------------------------------------- /src/markup/format/slim.ts: -------------------------------------------------------------------------------- 1 | import type { Abbreviation } from '@emmetio/abbreviation'; 2 | import indentFormat from './indent-format'; 3 | import type { Config } from '../../config'; 4 | 5 | export default function slim(abbr: Abbreviation, config: Config): string { 6 | return indentFormat(abbr, config, { 7 | beforeAttribute: ' ', 8 | glueAttribute: ' ', 9 | beforeTextLine: '| ', 10 | selfClose: '/' 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /packages/abbreviation/rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | 3 | export default { 4 | input: './src/index.ts', 5 | external: ['@emmetio/scanner'], 6 | plugins: [typescript()], 7 | output: [{ 8 | format: 'cjs', 9 | sourcemap: true, 10 | exports: 'named', 11 | file: './dist/index.cjs' 12 | }, { 13 | format: 'es', 14 | sourcemap: true, 15 | file: './dist/index.js' 16 | }] 17 | }; 18 | -------------------------------------------------------------------------------- /packages/css-abbreviation/rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | 3 | /** @type {import('rollup').RollupOptions} */ 4 | export default { 5 | input: './src/index.ts', 6 | external: ['@emmetio/scanner'], 7 | plugins: [typescript()], 8 | output: [{ 9 | format: 'cjs', 10 | file: 'dist/index.cjs', 11 | sourcemap: true, 12 | exports: 'named', 13 | }, { 14 | format: 'es', 15 | file: 'dist/index.js', 16 | sourcemap: true, 17 | }] 18 | }; 19 | -------------------------------------------------------------------------------- /src/markup/format/pug.ts: -------------------------------------------------------------------------------- 1 | import type { Abbreviation } from '@emmetio/abbreviation'; 2 | import indentFormat from './indent-format'; 3 | import type { Config } from '../../config'; 4 | 5 | export default function pug(abbr: Abbreviation, config: Config): string { 6 | return indentFormat(abbr, config, { 7 | beforeAttribute: '(', 8 | afterAttribute: ')', 9 | glueAttribute: ', ', 10 | beforeTextLine: '| ', 11 | selfClose: config.options['output.selfClosingStyle'] === 'xml' ? '/' : '' 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /src/markup/format/haml.ts: -------------------------------------------------------------------------------- 1 | import type { Abbreviation } from '@emmetio/abbreviation'; 2 | import indentFormat from './indent-format'; 3 | import type { Config } from '../../config'; 4 | 5 | export default function haml(abbr: Abbreviation, config: Config): string { 6 | return indentFormat(abbr, config, { 7 | beforeName: '%', 8 | beforeAttribute: '(', 9 | afterAttribute: ')', 10 | glueAttribute: ' ', 11 | afterTextLine: ' |', 12 | booleanValue: 'true', 13 | selfClose: '/' 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "sourceMap": true, 5 | "noUnusedLocals": true, 6 | "alwaysStrict": true, 7 | "noImplicitThis": true, 8 | "strictNullChecks": true, 9 | "isolatedModules": true, 10 | "declaration": true, 11 | "resolveJsonModule": true, 12 | "esModuleInterop": true, 13 | "verbatimModuleSyntax": true, 14 | "module": "ESNext", 15 | "moduleResolution": "bundler", 16 | "newLine": "LF", 17 | "outDir": "./dist" 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: emmetio 4 | patreon: # Replace with a single Patreon username 5 | open_collective: emmet 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /src/markup/addon/xsl.ts: -------------------------------------------------------------------------------- 1 | import type { AbbreviationNode, AbbreviationAttribute } from '@emmetio/abbreviation'; 2 | 3 | /** 4 | * XSL transformer: removes `select` attributes from certain nodes that contain 5 | * children 6 | */ 7 | export default function xsl(node: AbbreviationNode) { 8 | if (matchesName(node.name) && node.attributes && (node.children.length || node.value)) { 9 | node.attributes = node.attributes.filter(isAllowed); 10 | } 11 | } 12 | 13 | function isAllowed(attr: AbbreviationAttribute): boolean { 14 | return attr.name !== 'select'; 15 | } 16 | 17 | function matchesName(name?: string): boolean { 18 | return name === 'xsl:variable' || name === 'xsl:with-param'; 19 | } 20 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { extname } from 'path'; 2 | import typescript from '@rollup/plugin-typescript'; 3 | import nodeResolve from '@rollup/plugin-node-resolve'; 4 | 5 | export default { 6 | input: './src/index.ts', 7 | plugins: [nodeResolve(), json(), typescript()], 8 | output: [{ 9 | file: './dist/emmet.js', 10 | format: 'es', 11 | sourcemap: true 12 | }, { 13 | file: './dist/emmet.cjs', 14 | format: 'cjs', 15 | exports: 'named', 16 | sourcemap: true 17 | }] 18 | }; 19 | 20 | function json() { 21 | return { 22 | transform(code, id) { 23 | if (extname(id) === '.json') { 24 | return { code: `export default ${code}`, map: null }; 25 | } 26 | } 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/extract-abbreviation/quotes.ts: -------------------------------------------------------------------------------- 1 | import { type BackwardScanner, previous, sol, peek } from './reader.js'; 2 | 3 | const enum Chars { 4 | SingleQuote = 39, 5 | DoubleQuote = 34, 6 | Escape = 92 7 | } 8 | 9 | /** 10 | * Check if given character code is a quote 11 | */ 12 | export function isQuote(c?: number) { 13 | return c === Chars.SingleQuote || c === Chars.DoubleQuote; 14 | } 15 | 16 | /** 17 | * Consumes quoted value, if possible 18 | * @return Returns `true` is value was consumed 19 | */ 20 | export function consumeQuoted(scanner: BackwardScanner): boolean { 21 | const start = scanner.pos; 22 | const quote = previous(scanner); 23 | 24 | if (isQuote(quote)) { 25 | while (!sol(scanner)) { 26 | if (previous(scanner) === quote && peek(scanner) !== Chars.Escape) { 27 | return true; 28 | } 29 | } 30 | } 31 | 32 | scanner.pos = start; 33 | return false; 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ "master", "ci" ] 9 | pull_request: 10 | branches: [ "master" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [20.x, 22.x, 24.x] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | - run: npm ci 29 | - run: npm run build:full 30 | - run: npm run test:all 31 | -------------------------------------------------------------------------------- /packages/abbreviation/src/index.ts: -------------------------------------------------------------------------------- 1 | import { ScannerError } from '@emmetio/scanner'; 2 | import parse, { type TokenGroup } from './parser'; 3 | import tokenize, { getToken, type AllTokens } from './tokenizer'; 4 | import convert from './convert'; 5 | import type { ParserOptions } from './types'; 6 | 7 | export { parse, tokenize, getToken, convert }; 8 | export * from './tokenizer/tokens'; 9 | export * from './types'; 10 | export type MarkupAbbreviation = TokenGroup; 11 | 12 | /** 13 | * Parses given abbreviation into node tree 14 | */ 15 | export default function parseAbbreviation(abbr: string | AllTokens[], options?: ParserOptions) { 16 | try { 17 | const tokens = typeof abbr === 'string' ? tokenize(abbr) : abbr; 18 | return convert(parse(tokens, options), options); 19 | } catch (err) { 20 | if (err instanceof ScannerError && typeof abbr === 'string') { 21 | err.message += `\n${abbr}\n${'-'.repeat(err.pos)}^`; 22 | } 23 | 24 | throw err; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/css-abbreviation/src/index.ts: -------------------------------------------------------------------------------- 1 | import { ScannerError } from '@emmetio/scanner'; 2 | import tokenize, { getToken, type AllTokens } from './tokenizer'; 3 | import parser, { type CSSProperty, type ParseOptions } from './parser'; 4 | 5 | export { tokenize, getToken, parser }; 6 | export * from './tokenizer'; 7 | export type { CSSProperty, CSSValue, ParseOptions, FunctionCall, Value } from './parser'; 8 | export type CSSAbbreviation = CSSProperty[]; 9 | 10 | /** 11 | * Parses given abbreviation into property set 12 | */ 13 | export default function parse(abbr: string | AllTokens[], options?: ParseOptions): CSSAbbreviation { 14 | try { 15 | const tokens = typeof abbr === 'string' ? tokenize(abbr, options && options.value) : abbr; 16 | return parser(tokens, options); 17 | } catch (err) { 18 | if (err instanceof ScannerError && typeof abbr === 'string') { 19 | err.message += `\n${abbr}\n${'-'.repeat(err.pos)}^`; 20 | } 21 | 22 | throw err; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/snippets.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'node:test'; 2 | import { ok, strictEqual as equal } from 'node:assert'; 3 | import markup from '@emmetio/abbreviation'; 4 | import expand from '../src'; 5 | import html from '../src/snippets/html.json' assert { type: 'json' }; 6 | import xsl from '../src/snippets/xsl.json' assert { type: 'json' }; 7 | 8 | describe('Snippets', () => { 9 | it('HTML', () => { 10 | Object.keys(html).forEach(k => ok(markup(html[k]), k)); 11 | equal(expand('fset>input:c'), '
'); 12 | }); 13 | 14 | it('XSL', () => { 15 | Object.keys(xsl).forEach(k => ok(markup(xsl[k]), k)); 16 | }); 17 | 18 | it('Invalid snippets', () => { 19 | const snippets = { 20 | invalid: 'invalid snippet', 21 | valid: 'button' 22 | } 23 | 24 | const result = expand('invalid+valid', { snippets }) 25 | equal(result, '\n') 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/scanner/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@emmetio/scanner", 3 | "version": "1.0.4", 4 | "description": "Scans given text character-by-character", 5 | "main": "./dist/scanner.cjs", 6 | "module": "./dist/scanner.js", 7 | "types": "./dist/scanner.d.ts", 8 | "type": "module", 9 | "exports": { 10 | "import": "./dist/scanner.js", 11 | "require": "./dist/scanner.cjs" 12 | }, 13 | "scripts": { 14 | "test": "tsx --test ./test/*.ts", 15 | "build": "rollup -c", 16 | "watch": "rollup -wc", 17 | "clean": "rm ./scanner.* ./*.d.ts", 18 | "prepublishOnly": "npm test && npm run clean && npm run build" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/emmetio/stream-reader.git" 23 | }, 24 | "keywords": [ 25 | "emmet", 26 | "stream", 27 | "scanner" 28 | ], 29 | "author": "Sergey Chikuyonok ", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/emmetio/emmet/issues" 33 | }, 34 | "homepage": "https://github.com/emmetio/emmet#readme" 35 | } 36 | -------------------------------------------------------------------------------- /packages/css-abbreviation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@emmetio/css-abbreviation", 3 | "version": "2.1.8", 4 | "description": "Parses Emmet CSS abbreviation into AST tree", 5 | "main": "./dist/index.cjs", 6 | "module": "./dist/index.js", 7 | "types": "./dist/index.d.ts", 8 | "type": "module", 9 | "exports": { 10 | "import": "./dist/index.js", 11 | "require": "./dist/index.cjs" 12 | }, 13 | "scripts": { 14 | "test": "tsx --test ./test/*.ts", 15 | "build": "rollup -c", 16 | "watch": "rollup -wc", 17 | "clean": "rm -rf ./dist", 18 | "prepublishOnly": "npm test &&npm run clean && npm run build" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/emmetio/emmet.git" 23 | }, 24 | "keywords": [], 25 | "author": "Sergey Chikuyonok ", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/emmetio/emmet/issues" 29 | }, 30 | "homepage": "https://github.com/emmetio/emmet#readme", 31 | "dependencies": { 32 | "@emmetio/scanner": "^1.0.4" 33 | }, 34 | "directories": { 35 | "test": "test" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sergey Chikuyonok 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. 22 | -------------------------------------------------------------------------------- /packages/abbreviation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@emmetio/abbreviation", 3 | "version": "2.3.3", 4 | "description": "Emmet standalone abbreviation parser", 5 | "main": "./dist/index.cjs", 6 | "module": "./dist/index.js", 7 | "types": "./dist/index.d.ts", 8 | "type": "module", 9 | "exports": { 10 | "import": "./dist/index.js", 11 | "require": "./dist/index.cjs" 12 | }, 13 | "scripts": { 14 | "test": "tsx --test ./test/*.ts", 15 | "build": "rollup -c", 16 | "watch": "rollup -wc", 17 | "clean": "rm -rf ./dist", 18 | "prepublishOnly": "npm test && npm run clean && npm run build" 19 | }, 20 | "keywords": [ 21 | "emmet", 22 | "abbreviation" 23 | ], 24 | "author": "Sergey Chikuyonok ", 25 | "license": "MIT", 26 | "dependencies": { 27 | "@emmetio/scanner": "^1.0.4" 28 | }, 29 | "directories": { 30 | "test": "test" 31 | }, 32 | "repository": { 33 | "type": "git", 34 | "url": "git+https://github.com/emmetio/emmet.git" 35 | }, 36 | "bugs": { 37 | "url": "https://github.com/emmetio/emmet/issues" 38 | }, 39 | "homepage": "https://github.com/emmetio/emmet#readme" 40 | } 41 | -------------------------------------------------------------------------------- /packages/scanner/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sergey Chikuyonok 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. 22 | -------------------------------------------------------------------------------- /packages/abbreviation/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sergey Chikuyonok 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. 22 | -------------------------------------------------------------------------------- /packages/css-abbreviation/src/tokenizer/utils.ts: -------------------------------------------------------------------------------- 1 | export const enum Chars { 2 | /** `#` character */ 3 | Hash = 35, 4 | 5 | /** `$` character */ 6 | Dollar = 36, 7 | 8 | /** `-` character */ 9 | Dash = 45, 10 | 11 | /** `.` character */ 12 | Dot = 46, 13 | 14 | /** `:` character */ 15 | Colon = 58, 16 | 17 | /** `,` character */ 18 | Comma = 44, 19 | 20 | /** `!` character */ 21 | Excl = 33, 22 | 23 | /** `@` character */ 24 | At = 64, 25 | 26 | /** `%` character */ 27 | Percent = 37, 28 | 29 | /** `_` character */ 30 | Underscore = 95, 31 | 32 | /** `(` character */ 33 | RoundBracketOpen = 40, 34 | 35 | /** `)` character */ 36 | RoundBracketClose = 41, 37 | 38 | /** `{` character */ 39 | CurlyBracketOpen = 123, 40 | 41 | /** `}` character */ 42 | CurlyBracketClose = 125, 43 | 44 | /** `+` character */ 45 | Sibling = 43, 46 | 47 | /** `'` character */ 48 | SingleQuote = 39, 49 | 50 | /** `"` character */ 51 | DoubleQuote = 34, 52 | 53 | /** `t` character */ 54 | Transparent = 116, 55 | 56 | /** `/` character */ 57 | Slash = 47, 58 | } 59 | -------------------------------------------------------------------------------- /packages/css-abbreviation/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sergey Chikuyonok 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. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | .rpt2_cache 51 | dist/ 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # next.js build output 63 | .next 64 | .DS_Store 65 | /.vscode 66 | -------------------------------------------------------------------------------- /packages/abbreviation/test/assets/stringify-node.ts: -------------------------------------------------------------------------------- 1 | import type { Abbreviation, AbbreviationNode, Value, AbbreviationAttribute } from '../../src'; 2 | 3 | export default function stringify(abbr: Abbreviation): string { 4 | return abbr.children.map(elem).join(''); 5 | } 6 | 7 | function elem(node: AbbreviationNode): string { 8 | const name = node.name || '?'; 9 | const attributes = node.attributes 10 | ? node.attributes.map(attr => ' ' + attribute(attr)) 11 | : ''; 12 | const value = node.value ? stringifyValue(node.value) : ''; 13 | const repeat = node.repeat ? `*${node.repeat.count}@${node.repeat.value}` : ''; 14 | 15 | return node.selfClosing && !node.value && !node.children.length 16 | ? `<${name}${repeat}${attributes} />` 17 | : `<${name}${repeat}${attributes}>${value}${node.children.map(elem).join('')}`; 18 | 19 | } 20 | 21 | function attribute(attr: AbbreviationAttribute): string { 22 | const name = attr.name || '?'; 23 | const value = attr.value ? `"${stringifyValue(attr.value)}"` : null; 24 | return value != null ? `${name}=${value}` : name; 25 | } 26 | 27 | function stringifyValue(items: Value[]): string { 28 | return items.map(item => 29 | typeof item === 'string' 30 | ? item 31 | : (item.name ? `\${${item.index!}:${item.name}}` : `\${${item.index!}}`)).join(''); 32 | } 33 | -------------------------------------------------------------------------------- /src/markup/addon/label.ts: -------------------------------------------------------------------------------- 1 | import type { AbbreviationAttribute, AbbreviationNode } from '@emmetio/abbreviation'; 2 | import { find } from '../utils'; 3 | 4 | /** 5 | * Preprocessor of `